Spring学习入门:IoC、DI、bean配置和实例化、依赖注入、容器、注解开发、AOP、整合MyBatis、事务...【建议收藏】

壹、核心概念和注解:

1.1. IOC和DI

IOC(Inversion of Control)控制反转:对象的创建控制权由程序转移到外部,这种思想称为控制反转。/使用对象时,由主动new产生对象转换为由外部提供对象,此过程种对象创建控制权由程序转移到外部,此思想称为控制反转。/Spring提供了一个容器,称为IoC容器,用来充当Ioc思想中的“外部”。/IoC容器负责对象的创建、初始化等一系列工作,被创建或被管理的对象在IoC容器中统称为Bean。

DI(Dependency Injection)依赖注入:在容器中建立bean与bean之间的依赖关系的整个过程,,称为依赖注入。

Spring实现充分解耦:使用IoC容器管理bean+在IoC容器内将有依赖关系的bean进行关系绑定。

实现效果:使用对象时不仅可以直接从IoC容器中获取,并且获取到的bean已经绑定了所有的依赖关系。

1.2 Bean

Bean是由Spring容器管理的对象实例。

1.3 AOP

AOP(Aspect Oriented Programming)面向切面编程,是一种编程范式,指导开发者如何组织程序结构。

作用:在不惊动原始设计的基础上为其进行功能增强。

核心本质:代理(Proxy)模式。

连接点(JoinPoint):程序执行过程中的任意位置,粒度为执行方法、抛出异常、设置变量等。

在SpringAOP中,理解为任意方法的执行。

切入点(Pointcut):匹配连接点的式子,具有共性功能的方法描述。在SpringAOP中,一个切入点可以只描述一个具体方法,也可以匹配多个方法。

一个具体方法:com.itheima.dao包下的BookDao接口中的无形参无返回值的sava方法。

匹配多个方法:所有的sava方法,所有的get开头的方法,所有以Dao结尾的接口中的任意方法,所有带有一个参数的方法。

通知(Advice):若干个方法的共性功能在切入点处执行的操作,最终体现为一个方法。

在SpringAOP中,功能最终以方法的形式呈现。

通知类:定义通知的类。

切面(Aspect):描述通知与切入点的对应关系。

Spring学习入门:IoC、DI、bean配置和实例化、依赖注入、容器、注解开发、AOP、整合MyBatis、事务...【建议收藏】_第1张图片

目标对象(Target):原始功能去掉共性功能对应的类产生的对象,这种对象是无法直接完成最终工作的。

代理(Proxy):目标对象无法直接完成工作,需要对其进行功能回填,通过原始对象的代理对象实现。

1.4 事务

事务作用:在数据层保障一系列的数据库操作同成功同失败。

Spring事务作用:在数据层或业务层保障一系列的数据库操作同成功同失败。

1.5 核心注解

1. @Configuration:用于设定当前类为配置类,用于代替配置文件。

2. @Controller:用于表现层(用于处理用户界面和用户输入)bean定义。

3. @Service:用于业务层(用于实现业务逻辑的处理和业务规则的执行)bean定义。

4. @Repository:用于数据层(负责与底层的数据存储系统进行交互)bean定义。

5. @Bean:将方法的返回值作为一个Bean注册到容器中,并将其纳入到Spring的管理和依赖注入体系中

6. @PropertySource:用于指定外部属性文件的位置。可以将外部的.properties或.yml文件加载到Spring的环境中。

7. @Import:用于将其他配置类或组件引入到当前配置类中(Config结尾的是配置类)。

贰、重要知识点

一、Bean的基础

1.1 标签

标签表示配置当前bean的属性,name属性表示配置哪一个具体的属性,ref属性表示参照哪一个bean。

1.2 给bean起别名

标签的name属性中指定名称,多个别名之间可以用逗号、分号或者空格分隔。
在<>

1.3 bean的作用范围

通俗地说:看造的对象是单例的还是非单例的。

标签的scope属性中进行修改,singleton是单例,prototype是非单例,默认是单例的。

使用FactoryBean实例化bean,想调整单例非单例:

public boolean isSingleton(){
    return true; //表示单例
}

Spring帮我们管理的是可以复用的对象,提高我们的效率。

适合交给容器进行管理的bean(可以反复用):表现层对象,业务层对象service,数据层对象dao,工具对象。不适合交给容器进行管理的bean(有状态的,会记录成员变量的属性值):封装实体的域对象。

1.4 bean的实例化

私有的东西能访问是通过反射。

方法1:通过构造方法来实例化对象

方法2:使用静态工厂创建对象

class配的是工厂类名,还需要添加工厂中真正用来造对象的方法名:

方法3:实例工厂初始化bean

先把工厂对象造出来:

factory-bean写工厂的实例在哪,factory-method写工厂中的方法名:

方法4:使用FactoryBean实例化bean

public class UserDaoFactoryBean implements FactoryBean{
    //代替原始实例工厂中创建对象的方法
    @Override
    public UserDao getObject() throws Exception {
        return new UserDaoImpl();
    }

    @Override
    public Class getObjectType() {
        return UserDao.class;
    }
}

1.5 bean的生命周期

bean生命周期:bean从创建到消亡的完整过程

初始化容器:1. 创建对象(内存分配)2.执行构造方法 3.执行属性诸如(set操作)4.执行bean初始化方法 / 使用bean:执行业务操作 / 关闭/销毁容器:执行bean销毁方法

标签里,init-method属性填写初始化的方法,destroy-method填写销毁的方法。

想要调用销毁方法还要调用容器close方法(更加暴力),也可以调用registerShutdownHook方法。

在ServiceImpl类中可以,继承InitializingBean和DisposableBean

 1.6配置Spring文件

1.6.1 初始

管理什么?(Service与Dao)

如何将被管理的对象告知IoC容器?(配置)

被管理的对象交给IoC容器,如何获取到IoC容器?(接口)

IoC容器得到后,如何从容器中获取bean?(接口方法)

使用Spring导入哪些坐标?(pom.xml)

第1步:导入Spring坐标,记得刷新Maven如下:


      org.springframework
      spring-context
      5.2.10.RELEASE

第2步:定义Spring管理的类(接口)

BookService如下:

public interface BookService {
    public void save();
}

BookServiceImpl如下:

public class BookServiceImpl implements BookService{
    private BookDao bookDao = new BookDaoImpl();
    public void save(){
        bookDao.save();
    }
}

第3步:创建Spring配置文件,配置对应类作为Spring管理的bean

点击resources然后New-XML Configuration File-Spring Config

 新建的.xml文件名为:applicationContext.xml

写入:


    
    

标签里的class属性表示给bean定义类型,id属性表示给bean起名字。

第4步:初始化IoC容器(Spring核心容器/Spring容器),通过容器获取bean

 右键java-New-Java Class,创建一个名为App的文件

public class App {
    public static void main(String[] args) {
        //获取IoC容器
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        //获取bean
        BookDao bookDao = (BookDao)ctx.getBean("bookDao");
        bookDao.save();
        BookService bookService = (BookService) ctx.getBean("bookService");
        bookService.save();
    }
}

1.6.2 完善

第1步:删除使用new的形式创建对象的代码+第2步:提供依赖对象对应的setter方法

public class BookServiceImpl implements BookService{
    //5.删除业务层中使用new的方式创建的dao对象
    private BookDao bookDao;
    public void save(){
        bookDao.save();
    }
    //6.提供对应的set方法
    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }
}

第3步:配置service与dao之间的关系

二、Bean的依赖注入和容器

2.1 Bean的依赖注入

依赖注入描述了在容器中建立bean与bean之间依赖关系的过程。

向一个类中传递数据的方式有几种?答:普通方法(set方法)和构造方法。

如果bean运行需要的是数字或字符串呢?答:引用类型;简单类型(基本数据类型域String).

依赖注入方式:

Spring学习入门:IoC、DI、bean配置和实例化、依赖注入、容器、注解开发、AOP、整合MyBatis、事务...【建议收藏】_第2张图片Spring学习入门:IoC、DI、bean配置和实例化、依赖注入、容器、注解开发、AOP、整合MyBatis、事务...【建议收藏】_第3张图片

强制依赖用构造器注入,因为使用setter注入有概率不进行注入导致null对象出现。

可选依赖使用setter注入进行,灵活性强

Spring框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化,相对严谨。

如果有必要刻意两者同时使用,实际开发过程中要根据实际情况分析,自己开发的模块推荐使用setter注入。

2.1.1 setter注入

在bean中定义引用类型属性并提供可访问的set方法:

Spring学习入门:IoC、DI、bean配置和实例化、依赖注入、容器、注解开发、AOP、整合MyBatis、事务...【建议收藏】_第4张图片

配置中使用property标签value属性注入简单类型数据:

 Spring学习入门:IoC、DI、bean配置和实例化、依赖注入、容器、注解开发、AOP、整合MyBatis、事务...【建议收藏】_第5张图片

2.1.2 构造器注入

传统的经典写法:

Spring学习入门:IoC、DI、bean配置和实例化、依赖注入、容器、注解开发、AOP、整合MyBatis、事务...【建议收藏】_第6张图片

Spring学习入门:IoC、DI、bean配置和实例化、依赖注入、容器、注解开发、AOP、整合MyBatis、事务...【建议收藏】_第7张图片

Spring学习入门:IoC、DI、bean配置和实例化、依赖注入、容器、注解开发、AOP、整合MyBatis、事务...【建议收藏】_第8张图片

但上面的写法会存在一个问题:就是当BookServiceImpl类中的构造方法的命名改变之后,配置文件就不能用了,也就是与形参名的耦合度太高。

以下是解决方法1:通过指定type类型来对应变量。

Spring学习入门:IoC、DI、bean配置和实例化、依赖注入、容器、注解开发、AOP、整合MyBatis、事务...【建议收藏】_第9张图片

但假如有2个字符串类型的数据,便无法对应,该方式失效。

解决方法2:通过指定位置来对应变量。

Spring学习入门:IoC、DI、bean配置和实例化、依赖注入、容器、注解开发、AOP、整合MyBatis、事务...【建议收藏】_第10张图片

2.1.3 依赖自动装配

IoC容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程称为自动装配。

自动装配方式:按类型(常用)、按名称、按构造方法、不启用自动装配。

Spring学习入门:IoC、DI、bean配置和实例化、依赖注入、容器、注解开发、AOP、整合MyBatis、事务...【建议收藏】_第11张图片

借助set方法来自动装配:

 Spring学习入门:IoC、DI、bean配置和实例化、依赖注入、容器、注解开发、AOP、整合MyBatis、事务...【建议收藏】_第12张图片

 按名称装配是Impl中的变量名。

自动装配用于引用类型依赖注入,不能对简单类型进行操作。

按类型装配时(byType)必须保证容器中相同类型的bean唯一,推荐使用。

按名称装配时(byName)必须保障容器中具有指定名称的bean,因变量名与配置耦合,不推荐使用。

自动装配优先级低于setter注入与构造器注入,同时出现时自动装配配置失效。

2.1.4 集合注入


        
            
                100
                200
                300
            
        
        
            
                itheima
                itcast
                boxuelu
            
        
        
            
                itheima
                itcast
                boxuelu
                boxuelu
            
        
        
            
                
                
                
            
        
        
            
                china
                henan
                kaifeng
            
        
    

数组array,列表list,集合set(注意会自动去重)的注入方式如下(都是):

Spring学习入门:IoC、DI、bean配置和实例化、依赖注入、容器、注解开发、AOP、整合MyBatis、事务...【建议收藏】_第13张图片Spring学习入门:IoC、DI、bean配置和实例化、依赖注入、容器、注解开发、AOP、整合MyBatis、事务...【建议收藏】_第14张图片Spring学习入门:IoC、DI、bean配置和实例化、依赖注入、容器、注解开发、AOP、整合MyBatis、事务...【建议收藏】_第15张图片

map的注入方式如下:

 Spring学习入门:IoC、DI、bean配置和实例化、依赖注入、容器、注解开发、AOP、整合MyBatis、事务...【建议收藏】_第16张图片

properties的注入方式如下:

Spring学习入门:IoC、DI、bean配置和实例化、依赖注入、容器、注解开发、AOP、整合MyBatis、事务...【建议收藏】_第17张图片

2.1.5 加载properties文件

第1步:开启一个新的namespace命名空间,名为context

Spring学习入门:IoC、DI、bean配置和实例化、依赖注入、容器、注解开发、AOP、整合MyBatis、事务...【建议收藏】_第18张图片


第2步:使用context空间加载properties文件

property-placeholder属性占位符,用location指定要加载的文件

第3步:使用属性占位符${}读取properties文件中的属性

大括号里面写的是properties文件中的变量名


     
     
     
     

注意在properties文件中,变量命名最好不要与系统命名冲突,否则系统命名的优先级会更高,修改会无效。如果想忽略系统命名,可以加入下面这段代码:

system-properties-mode="NEVER"

 加载多个properties文件可以用逗号分隔,也可以用classpath:*.来指明:

    

如果在classpath后再加一个*,写成:classpath*:*表示不仅可以从当前工程中读还可以从依赖的jar包中读:

2.2 容器

BeanFactory是IoC容器的顶层接口,初始化BeanFactory对象时,加载的bean延迟加载。

ApplicationContext接口是Spring容器的核心接口,初始化时bean立即加载。

ApplicationContext接口提供基础的bean操作相关方法,通过其他接口拓展其功能。

ApplicationContext接口常用初始化类:

ClassPathXmlApplicationContext

FileSystemXmlApplicationContext

2.2.1创建容器

方法1:类路径加载配置文件

ApplicationContexxt ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

方法2:文件路径加载配置文件

ApplicationContext ctx = new FileSystemXmlApplicationContext("D:\\applicationContext.xml");

 方法3:加载多个配置文件

ApplicationContext ctx = new ClassPathXmlApplicationContext("bean1.xml","bean2.xml");

2.2.2 获取bean

方法1:使用bean名称获取

BookDao bookDao = (BookDao) ctx.getBean("bookDao");

方法2:使用bean名称获取并指定类型

BookDao bookDao = ctx.getBean("bookDao",BookDao.class);

 方法3:使用bean类型获取

BookDao bookDao = ctx.getBean(BookDao.class);

BeanFactory创建完毕后,所有的bean均为延迟加载。

Spring学习入门:IoC、DI、bean配置和实例化、依赖注入、容器、注解开发、AOP、整合MyBatis、事务...【建议收藏】_第19张图片

Spring学习入门:IoC、DI、bean配置和实例化、依赖注入、容器、注解开发、AOP、整合MyBatis、事务...【建议收藏】_第20张图片

三、Bean的注解开发

3.1 注解开发 

3.1.1 注解开发定义bean

@Component相当于是定义了一个bean语句,bookDao相当于Id,定义了名称。

Spring学习入门:IoC、DI、bean配置和实例化、依赖注入、容器、注解开发、AOP、整合MyBatis、事务...【建议收藏】_第21张图片

Spring学习入门:IoC、DI、bean配置和实例化、依赖注入、容器、注解开发、AOP、整合MyBatis、事务...【建议收藏】_第22张图片

 接下来有一个问题,Spring如何知道定义了一个注解?只需要在配置文件中写入如下的代码:

Spring提供@Component注解的三个衍生注解:

@Controller:用于表现层bean定义

@Service:用于业务层bean定义

@Repository:用于数据层bean定义

注意:下面是表现层的注解可以不写名称:

@Service
public class BookServiceImpl implements BookService {
    public void save() {
        System.out.println("book service save ...");
    }
}

数据层的注解一定要写名称:

@Repository("bookDao")
public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("book dao save ...");
    }
}

3.1.2 纯注解开发模式

如果想要用Java类来代替配置文件,需要先创建一个类:

Spring学习入门:IoC、DI、bean配置和实例化、依赖注入、容器、注解开发、AOP、整合MyBatis、事务...【建议收藏】_第23张图片Spring学习入门:IoC、DI、bean配置和实例化、依赖注入、容器、注解开发、AOP、整合MyBatis、事务...【建议收藏】_第24张图片

然后标注上注解@Configuration用于设定当前类为配置类,用于代替配置文件:

然后用注解@ComponentScan("com.itheima")来代替即可,记得要把包名加上,代码如下:

@Configuration
@ComponentScan("com.itheima")
public class SpringConfig {
}

如果想要写多个包名,用数组的格式即可:

@Configuration
@CompinentScan({"com.itheima.service","com.itheima.dao"})
public class SpringConfig{
}

唯一的改动就是:将AnnotationConfigApplicationContext里改为SpringConfig.class。

ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);

Spring框架将会基于SpringConfig类中的注解配置来初始化和加载应用程序上下文,使得定义的Bean可以被Spring容器管理和使用。

public class AppForAnnotation {
    public static void main(String[] args) {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
        System.out.println(bookDao);
        BookService bookService = ctx.getBean(BookService.class);
        System.out.println(bookService);
    }

3.1.3 bean作用范围和生命周期

bean的作用范围通过@Scope标签设置。

 prototype是多例,singleton是单例。

设定生命周期的初始方法init()和终止方法destroy(),要添加如下依赖:


    
      javax.annotation
      javax.annotation-api
      1.3.2
    

初始方法加注解@PostConstruct(彻底构造后),终止方法加注解@PreDestroy(彻底销毁前)。

如果要执行销毁操作,要添加ctx.close();

3.2 依赖注入

加上Autowired注解,完成自动装配:

Spring学习入门:IoC、DI、bean配置和实例化、依赖注入、容器、注解开发、AOP、整合MyBatis、事务...【建议收藏】_第25张图片

如果bookDaoImpl没有名,说明是按类型装配的。

此时不需要再写set方法,只需要写成下面这样:

@Service
public class BookServiceImpl implements BookService {
    @Autowired
    private BookDao bookDao;
    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
    }
}

自动装配基于反射设计创建对象并暴力反射对应属性为私有属性初始化数据,因此无需提供setter方法。 

自动装配建议使用无参构造方法创建对象(默认),如果不提供对应构造方法,请提供唯一的构造方法。

如果有多个数据层的实现,只能按名称装配,采用注解@Qualifier("填写名称"):

通过Value注解来注入简单类型:

Spring学习入门:IoC、DI、bean配置和实例化、依赖注入、容器、注解开发、AOP、整合MyBatis、事务...【建议收藏】_第26张图片

如果@Value注解中引用的值在PropertySource中,则通过@PropertySource注解加载properties配置文件。

 name是property中的变量名:

 Spring学习入门:IoC、DI、bean配置和实例化、依赖注入、容器、注解开发、AOP、整合MyBatis、事务...【建议收藏】_第27张图片

如果要写多个就这么写:

@PropertySource({"jdbc.properties1","jdbc.propertie2","jdbc.propertie3"})

3.3 第三方bean管理和依赖注入

第1步:在SpringConfig类中先定义一个方法

第2步:添加@Bean表示当前方法的返回值是一个bean

@Configuration
public class SpringConfig {
    @Bean("dataSource")
    public DataSource dataSource(){
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName("com.mysql.jdbc.Driver");
        ds.setUrl("jdbc:mysql://localhost:3306/spriing_db");
        ds.setUsername("root");
        ds.setPassword("root");
        return ds;
    }
}

 然后调用打印即可:

public class App {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
        DataSource dataSource = ctx.getBean(DataSource.class);
        System.out.println(dataSource);
    }
}

对于Jdbc的配置类我们可以专门写在JdbcConfig类中,类似于下面这样:

public class JdbcConfig {
    @Bean("dataSource")
    public DataSource dataSource(){
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName("com.mysql.jdbc.Driver");
        ds.setUrl("jdbc:mysql://localhost:3306/spriing_db");
        ds.setUsername("root");
        ds.setPassword("root");
        return ds;
    }
}

 通过标签@Import来导入其它依赖,用数组形式如下:

@Configuration
@Import({JdbcConfig.class})
public class SpringConfig {
}

加入简单类型就通过@Value标签来给变量赋值:

public class JdbcConfig {
    @Value("com.mysql.jdbc.Driver")
    private String driver;
    @Value("jdbc:mysql://localhost:3306/spriing_db")
    private String url;
    @Value("root")
    private String userName;
    @Value("root")
    private String password;
    @Bean("dataSource")
    public DataSource dataSource(){

        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName(driver);
        ds.setUrl(url);
        ds.setUsername(userName);
        ds.setPassword(password);
        return ds;
    }

 加入引用类型,直接给出形参即可,会自动装配,按类型进行检测而:

public DataSource dataSource(BookDao bookDao){
        System.out.println(bookDao);
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName(driver);
        ds.setUrl(url);
        ds.setUsername(userName);
        ds.setPassword(password);
        return ds;
    }

 ​​Spring学习入门:IoC、DI、bean配置和实例化、依赖注入、容器、注解开发、AOP、整合MyBatis、事务...【建议收藏】_第28张图片

四、AOP

4.1 AOP入门案例

先创建一个通知类,比如MyAdvic

1. 注解@Component是告诉Spring来加载我。

2. @Aspect是告诉Spring这个东西是用来做AOP的。

3. @Pointcut注解是定义切入点:给它一个参数,execution()。void是返回值,com包下,itheima包下,dao包下,BookDao接口,.update()方法。

4. method()方法是通知,执行的方法。

5. 通过@Before注解来绑定。意思是method()方法的执行在pt()方法的前面。

@Component //变成Spring控制的Bean,通知类必须配置成Spring管理的bean
//设置当前类为切面类类
@Aspect //知道是面向切面
public class MyAdvice {
    @Pointcut("execution(void com.itheima.dao.BookDao.update())") //定义切入点
    private void pt(){} //先写私有方法

    @Before("pt()")//想上面的方法在什么位置执行,如前面
    public void method(){ //执行的方法
        System.out.println(System.currentTimeMillis()); //共性功能
    }
}

 @EnableAspectJAutoProxy是为了告诉程序用注解开发AOP:

@Configuration
@ComponentScan("com.itheima")
@EnableAspectJAutoProxy //开启注解开发AOP功能
public class SpringConfig {
}

4.2 AOP工作流程

1. Spring容器启动。

2.读取所有切面配置中的切入点。@Pointcut注解定义的。

3.初始化bean,判定bean对应的类中的方法是否匹配到任意切入点。

匹配失败,创建对象

匹配成功,创建原始对象(目标对象)的代理(可以增强)对象

4. 获取bean执行方法

获取bean,调用方法并执行,完成操作。

获取的bean是代理对象时,根据代理对象的运行模式运行原始方法和增强内容。

4.3 AOP切入点表达式

切入点:要进行增强的方法。切入点表达式:要进行增强的方法的描述方式。】

方式1:执行com.itheima.dao包下的BookDao接口中的无参数update方法:execution(void com.itheima.dao.BookDao.update())

方式2:执行com.itheima.dao.impl包下的BookDaoImpl类中的无参数update方法:execution(void com.itheima.dao.impl.BookDaoImpl.update())

切入点表达式标准格式:动作关键字(访问修饰符 返回值 包名.类/接口名.方法名(参数)异常名)。其中访问修饰符是public、private等,可以省略。

一个程序中如果开发了很多功能,挨个写会极为困难。

通配符:

*:单个独立的任意符号(可以是一个范围,但必须要有一个值),可以独立出现;也可以作为前缀或者后缀(范围匹配)的匹配符出现。

匹配com.itheima包下的任意包中的UserService类或接口中所有find开头的带有一个参数的方法:execution(public * com.itheima.*.UserService.find*(*))

..:多个连续的任意符号(也可以不出现),可以独立出现,常用于简化包名与参数的书写。

匹配com包下的任意包中的UserService类或接口中所有名称为findById的方法:execution(public User com..UserService.findById(..))

+:专用于匹配子类类型

execution(* *..*Service+..*(..))

1.描述切入点通常描述接口,而不描述实现类(否则紧耦合)。

2.返回值类型对于增删改类使用精确类型加速匹配,对于查询类使用*通配快速描述。

3.包名书写尽量不使用..匹配,效率过低,通常*做单个包描述匹配,或精确匹配。

4.接口名/类名书写名称与模块相关的采用*匹配,例如UserService书写成*Service,绑定业务层接口。

5.方法名书写以动词进行精确匹配,名词采用*匹配,例如getById书写成getBy*,selectAll书写成selectAll。

6.通常不使用异常作为匹配规则。

4.4 AOP通知类型

AOP通知分为5种类型:

1. 前置通知@Before("填写")

2. 后置通知@After("填写")

3. 环绕通知@Around("填写")。要在前后语句中间加一个.proceed()方法。要强制抛出一个异常。

@Around("pt()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("around before advice ...");
        Object ret = pjp.proceed();//表示对原始操作的调用
        System.out.println("around after advice ...");
        return ret;
    }

环绕通知必须依赖形参ProceedingJoinPoint才能实现对原始方法的调用(否则会对原始操作作出隔离,将跳过原始方法的执行),进而实现原始方法调用前后同时添加通知。

对原始方法调用可以不接收返回值,通知方法设置成Void即可,如果接收返回值,必须要加上返回值Object,返回一个对象。

环绕通知可以模拟出其它所有通知,只在调用原始操作前做事情是前置通知,用try-catch在finally里写的东西是后置通知,在try-catch的try大括号结束之前,原始调用方法结束后模拟返回后通知。catch模拟抛出异常后通知。

4. 返回后通知(了解)@AfterReturning("填写")。只有当方法在正常运行没有抛异常的前提下才会执行语句。

5. 抛出异常后通知(了解)@AfterThrowing("填写")。

4.5 AOP案例

Spring学习入门:IoC、DI、bean配置和实例化、依赖注入、容器、注解开发、AOP、整合MyBatis、事务...【建议收藏】_第29张图片

@Component
@Aspect
public class ProjectAdvice {
    @Pointcut("execution(* com.itheima.service.*Service.*(..))")//匹配业务层的所有方法
    private void servicePt(){};
    @Around("ProjectAdvice.servicePt()")
    public void runSpeed(ProceedingJoinPoint pjp) throws Throwable {
        Signature signature = pjp.getSignature();//一次执行的签名信息
        String className = signature.getDeclaringTypeName(); //获取类型名
        String methodName = signature.getName(); //获取执行方法名
        long start = System.currentTimeMillis(); //开始时间
        for(int i=0;i<10000;i++){
            Object ret = pjp.proceed(); //执行操作
        }
        long end = System.currentTimeMillis(); //结束时间
        System.out.println("万次执行"+className+"."+methodName+"————"+(end-start)+"ms"); //打印
    }
}

 下面是执行类:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class AccountServiceTestCase {
    @Autowired
    private AccountService accountService;
    @Test
    public void testFindById(){
        Account ac = accountService.findById(2);
    }
    @Test
    public void testFindAll(){
        List all = accountService.findAll();
    }
}

 下面是百度网盘密码数据兼容处理:

@Component
@Aspect
public class DataAdvice {
    @Pointcut("execution(boolean com.itheima.service.ResourcesService.*(*,*))") //增强功能的对象文件
    private void servicePt(){}

    @Around("DataAdvice.servicePt()")
    public Object trimStr(ProceedingJoinPoint pjp) throws Throwable {
        Object[] args = pjp.getArgs(); //取出参数内容
        for(int i=0;i< args.length;i++){
            if(args[i].getClass().equals(String.class)) //比对是否是字符串
                args[i] = args[i].toString().trim(); //trim方法用于去掉字符串两段多余空格
            //修改参数内容
        }
        Object ret = pjp.proceed(args); //重新回填参数
        return ret; //返回
    }
}

4.6 AOP通知获取数据

1. 获取切入点方法的参数

JoinPoint:适用于前置、后置、返回后、抛出异常后通知。

//   @Before("pt()")
    public void before(JoinPoint jp) {
//JoinPoint:用于描述切入点的对象,必须配置成通知方法中的第一个参数,可用于获取原始方法调用的参数
        Object[] args = jp.getArgs();
        System.out.println(Arrays.toString(args));
        System.out.println("before advice ..." );
    }

ProceedJointPoint:适用于环绕通知。

@Around("pt()")
    public Object around(ProceedingJoinPoint pjp) {
//ProceedingJoinPoint:专用于环绕通知,是JoinPoint子类,可以实现对原始方法的调用
        Object[] args = pjp.getArgs();
        System.out.println(Arrays.toString(args));
        args[0] = 666; //传过来的参数如果有问题可以先处理一下
        //如果要字符串,如果传的不是字符串,可以先更改再赋予初始值
        Object ret = null;
        try {
            ret = pjp.proceed(args);
        } catch (Throwable t) {
            t.printStackTrace();
        }
        return ret;
    }

2. 获取切入点方法返回值(必须保证方法内部正常执行才会有返回值)

返回后通知和环绕通知可以拿到返回值。

//设置返回后通知获取原始方法的返回值,要求returning属性值必须与方法形参名相同
//@AfterReturning(value = "pt()",returning = "ret")
//定义一个参数变量用于接收返回值,returning="ret"
    public void afterReturning(JoinPoint jp,String ret) {
        System.out.println("afterReturning advice ..."+ret);
    }

3. 获取切入点方法运行异常信息

抛出异常后通知和环绕通知。

//设置抛出异常后通知获取原始方法运行时抛出的异常对象,要求throwing属性值必须与方法形参名相同
   @AfterThrowing(value = "pt()",throwing = "t")
    public void afterThrowing(Throwable t) {
        System.out.println("afterThrowing advice ..."+t);
    }
}

五、Spring事务 

5.1事务入门

Spring学习入门:IoC、DI、bean配置和实例化、依赖注入、容器、注解开发、AOP、整合MyBatis、事务...【建议收藏】_第30张图片

步骤1:在业务层接口上添加Spring事务管理

public interface AccountService{
    @Transactional
    public void transfer(String out,String in,Double money);
}

注意1:通常添加在业务层的接口中而不会添加到业务层的实现类中,降低耦合。

注意2:注解可以添加到业务方法上表示当前方法开启事务,也可以添加到接口上表示当前接口所有方法开启事务。

步骤2:设置事务管理器

@Bean
public PlatformTransactionManager transationManager(DataSource dataSource){
    DataSourceTransactionManager ptm = new DataSourceTransactionManager();
    ptm.setDataSource(dataSource);
    return ptm;
}

 注意1:事务管理器要根据实现技术进行选择。Mybatis框架使用的是JDBC事务。

步骤3:开启注解式事务驱动

@EnablTransactionManagement
public class SpringConfig{
}

5.2 事务角色

Spring学习入门:IoC、DI、bean配置和实例化、依赖注入、容器、注解开发、AOP、整合MyBatis、事务...【建议收藏】_第31张图片

 事务管理员:发起事务方,在Spring中通常指代业务层

 事务协调员:加入事务方,在Spring中通常指代数据层方法,也可以是业务层方法。

5.3 事务属性

Spring学习入门:IoC、DI、bean配置和实例化、依赖注入、容器、注解开发、AOP、整合MyBatis、事务...【建议收藏】_第32张图片

rollbackFor遇到某类异常回滚事务 

会回滚的异常包括:Error系的,运行时异常。有些异常不会回滚,如:IOException。

try-finally结构:将一定要运行的代码放在finally里,将有可能出问题的代码放在try里。

popagation = Propagation.REQUIRES_NEW 表示开启一个新的日志。

Spring学习入门:IoC、DI、bean配置和实例化、依赖注入、容器、注解开发、AOP、整合MyBatis、事务...【建议收藏】_第33张图片

 MANDATORY表示要想调用我必须携带事务。

NEVER表示千万不能携带事务。

六、Spring整合系列

4.1 Spring整合Mybatis

 4.1.1 整合的思路

 下面是原始开发:

public class App {
    public static void main(String[] args) throws IOException {
        // 1. 创建SqlSessionFactoryBuilder对象
        SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
        // 2. 加载SqlMapConfig.xml配置文件
        InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        // 3. 创建SqlSessionFactory对象
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
        // 4. 获取SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        // 5. 执行SqlSession对象执行查询,获取结果User
        AccountDao accountDao = sqlSession.getMapper(AccountDao.class);
        Account ac = accountDao.findById(1);
        System.out.println(ac);
        // 6. 释放资源
        sqlSession.close();
    }
}

 其中最核心的是SelSessionFactory对象:

Spring学习入门:IoC、DI、bean配置和实例化、依赖注入、容器、注解开发、AOP、整合MyBatis、事务...【建议收藏】_第34张图片

 Spring学习入门:IoC、DI、bean配置和实例化、依赖注入、容器、注解开发、AOP、整合MyBatis、事务...【建议收藏】_第35张图片

 4.1.2 整合的具体操作

Spring中操作数据库的包:


      org.springframework
      spring-jdbc
      5.2.10.RELEASE

Spring整合Mybatis的包:


      org.mybatis
      mybatis-spring
      1.3.0

 SqlSessionFactoryBean可以快速创建SqlSessionFactory对象。

框架的好处在于大量的东西采用默认值,不需要设置。

在MybatisConfig配置类中要设置原先sqlMapConfig.xml文件中的信息:

public class MybatisConfig {
    @Bean
    public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){
        SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean();
        ssfb.setTypeAliasesPackage("com.itheima.domin"); //需要修改的地方
        ssfb.setDataSource(dataSource);
        return ssfb;
    }

    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer(){
        MapperScannerConfigurer msc= new MapperScannerConfigurer();
        msc.setBasePackage("com.itheima.dao"); //需要修改的地方
        return msc;
    }
}

下面是Configuration注解: 

@Configuration
@ComponentScan("com.itheima")
@PropertySource("classpath:jdbc.properties")
@Import({JdbcConfig.class,MybatisConfig.class})
public class SpringConfig {
}

Spring学习入门:IoC、DI、bean配置和实例化、依赖注入、容器、注解开发、AOP、整合MyBatis、事务...【建议收藏】_第36张图片

 Spring学习入门:IoC、DI、bean配置和实例化、依赖注入、容器、注解开发、AOP、整合MyBatis、事务...【建议收藏】_第37张图片

4.2 Spring整合JUnit

先导入如下的依赖:


      junit
      junit
      4.12
      test

    

      org.springframework
      spring-test
      5.2.10.RELEASE

 在src - test - java - com.itheima.service 下创建AccountServiceTest类:

@RunWith(SpringJUnit4ClassRunner.class)//设置类运行器
@ContextConfiguration(classes = SpringConfig.class)//设置Spring环境对应的配置类
public class AccountServiceTest {
    @Autowired //支持自动装配注入bean
    private AccountService accountService;
    @Test
    public void testFindById(){
        System.out.println(accountService.findById(1));
    }
    @Test
    public void testFindAll(){
        System.out.println(accountService.findAll());
    }
}

你可能感兴趣的:(spring,学习,笔记,mybatis,java,前端,数据库)