Spring基础

90 阅读21分钟

1.1概述及IOC概念

  1. spring

    1. 开源的免费的框架
    2. 轻量级的、非侵入式的框架
    3. 提供了控制反转、面向切面编程的功能
    4. 支持事务处理、支持大多数框架的整合
    5. 配置十分繁琐
  2. spring七大模块

    1. 图例

    2. 详解

      1. 核心容器(Spring Core):核心容器提供Spring框架的基本功能即依赖注入
      2. 应用上下文(Spring Context):一个配置文件,用于向Spring框架提供上下文信息,包括国际化、邮件处理等企业级功能
      3. 面向切面编程(Spring AOP):提供面向切面编程的功能
      4. JDBC和DAO模块(Spring DAO):提供了模块化编写DAO层代码的功能
      5. 对象实体映射(Spring ORM):提供了整合ORM框架实现对象实体相互映射的功能
      6. Web模块(Spring Web):提供了基于应用上下文的web上下文
      7. MVC模块(Spring Web MVC):提供了基于Spring实现的MVC框架
  3. IOC相关概念

    1. 控制反转(IOC),主动创建依赖对象的控制权被反转了,依赖对象不再主动创建,从而降低程序耦合度,增强代码复用性

    2. 依赖注入(DI),控制反转的一种实现方式,控制权被交于IOC容器,依赖的对象将会被IOC容器以注入的方式添加到需要的地方,一般spring可以通过属性、构造方法或工厂方法的参数来确定依赖

      1. set注入:通过set方法的参数来确定依赖,基于set方法,优点是按需注入,可以解决循环依赖问题,但对应属性不能以final修饰,例子如下

        @Component
        public class FirstBean {
            private SecondBean sb;
            public SecondBean getSb() {
                return sb;
            }
            @Autowired
            public void setSb(SecondBean sb) {
                this.sb = sb;
            }
        }
        
      2. 构造器注入:通过构造方法的参数确定依赖,基于构造方法,优点是减少了对spring的依赖,确保了注入的对象不为空且完成了初始化,同时对于属性会被加上final修饰,并且出现循环依赖时还会抛异常,但构造器的参数可能过长,例子如下

        @Component
        public class FirstBean {
            private SecondBean sb;
            @Autowired
            public FirstBean(SecondBean sb) {
                this.sb = sb;
            }
        
            public SecondBean getSb() {
                return sb;
            }
            public void setSb(SecondBean sb) {
                this.sb = sb;
            }
        }
        
      3. field注入(不推荐):通过属性来确定依赖,基于反射,优点是简洁明了,缺点是对spring依赖过高,无法解决循环依赖也不会抛异常,并且对应属性也不能用final修饰,例子如下

        @Component
        public class FirstBean {
            @Autowired
            private SecondBean sb;
        
            public SecondBean getSb() {
                return sb;
            }
            
            public void setSb(SecondBean sb) {
                this.sb = sb;
            }
        }
        
    3. IOC容器,用于管理bean并提供依赖注入的功能,容器会通过读取configuration元数据获取有关objects实例化、配置和汇编的指令,spring中主要提供了具备完整依赖注入功能的BeanFactory与BeanFactory的超集ApplicationContext这两种容器,相较而言,ApplicationContext还会提供一些类似于国际化等的企业级功能,并且其单例bean默认非懒加载

      1. Configuration元数据:是对objects创建、管理的一些描述,如该object是否为bean、是singleton还prototype、其属性是否需要注入,应该注入何种对象等,元数据可以为XML、Java注解、Java代码

        1. XML,不安全、查找类不方便、可读性差、配置不简洁、修改配置不用重编译、非侵入、自由度低、可注入非自己创建的类
        2. Java注解,安全、方便、可读性很好、配置十分简洁、修改配置要重编译、侵入、自由度高、不可注入非自己创建的类
        3. Java配置,安全、不方便、可读性一般、配置比较简洁、修改配置要重编译、非侵入、自由度非常高、可以注入非自己创建的类
      2. 使用实例

        //bean类
        @Component
        @Data
        public class FirstBean {
            private String name;
        }
        
        //Configuration类
        @Configuration
        @ComponentScan("org.example.bean")
        public class SpringConfiguration {
        }
        
        //启动类
        public class MyTest {
            public static void main(String[] args) {
                ApplicationContext ac=new AnnotationConfigApplicationContext(SpringConfiguration.class);
                FirstBean fb=ac.getBean(FirstBean.class);
                System.out.println(fb.toString());
            }
        }
        
    4. bean,是对象,IOC容器基于我们提供给它的configuration来实例化、组装和管理这些对象,常见的元数据及对应信息如下

      1. beanDefinition:一个用于存储bean相关信息的对象,如bean的类名、scope、属性、构造函数的,Spring容器启动时会通过beanDefinitionReader去获取各个bean相关属性和配置信息并将它们存放在对应的beanDefinition中,然后将这些beanDefinition存放在map中,之后根据beanDefinition中的类名、构造函数、构造函数参数,使用反射就可以创建对应的bean了,非懒加载的bean会在此时直接创建并存放在另一个map便于之后直接获取使用

      2. FactoryBean:工程bean,也由Spring容器管理,可以生产和修饰一些bean,若对AOP中对应类加以修饰形成所需的bean

      3. bean生命周期图

    5. Spring循环依赖解决方式

      1. 前提:
        1. Spring实例化bean会分三步,分别为调用构造方法实例化,通过set方法填充属性,通过init方法对bean初始化
        2. bean存放于三级缓存中,一级缓存,用于存放完全初始化好的bean,二级缓存尚未填充属性的bean,三级存放正在实例化的bean,Spring会从一级到三级去尝试获取到对应bean
      2. 循环依赖解决过程如下
        1. A创建过程中需要 B,于是A将自己放到三级缓里面,去实例化B
        2. B实例化的时候发现需要A,于是B先查一级缓存,没有,再查二级缓存,还是没有,再查三级缓存,找到了,则将其作为自己的注入属性
          1. 然后把三级缓存里面的这个 A 放到二级缓存里面,并删除三级缓存里面的 A
          2. B 顺利初始化完毕,将自己放到一级缓存里面,此时B里面的A依然是创建中状态
        3. 然后回来接着创建A,此时B已经创建结束,直接从一级缓存里面拿到 B ,然后完成创建,并将自己放到一级缓存里面
    6. 自动装配常见值及解释

      1. no,默认值,即不进行自动装配,需要通过注解如@Autowire来主动指明该属性、方法需要主动装配
      2. byName,按照beanName进行自动装配,使用setter注入
      3. byType,按照beanClass进行自动装配,使用setter注入
      4. constructor,类似于byType,不过通过构造器注入

1.2IOC中常用注解

  1. 声明bean的相关注解

    1. 作用于类上的注解

      1. @Component,通用注解,当不知道这个类属于哪一层的时候可以通过该注解来标明为bean,这些bean的默认名称为第一个字母小写的类名,类型就是注解作用类的类型
      2. @Controller,组合了@Component的注解,用于声明控制层的类为bean
      3. @RestController,组合了@Controller和@ResponseBody的注解,同样用于声明控制层的类为bean,并指明该类返回的是数据而非视图,数据默认是json格式
      4. @Service,组合了@Component的注解,用于声明服务层的类为bean
      5. @Repository,组合里@Component的注解,用于声明数据访问层的类为bean
    2. 作用域方法上的注解

      1. @Bean,用于指明对应方法的返回值为一个bean,需要配合@Configuration使用,该bean的名称默认为方法的名称,类型为方法的返回类型,其详尽信息如下

        @Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
        @Retention(RetentionPolicy.RUNTIME)
        @Documented
        public @interface Bean {
            @AliasFor("name")
            String[] value() default {};	//用于指明别名
        
            @AliasFor("value")
            String[] name() default {};
        
            /** @deprecated */
            @Deprecated
            Autowire autowire() default Autowire.NO;		//默认不启用自动装配
        
            boolean autowireCandidate() default true;		//默认开启自动条件匹配
        
            String initMethod() default "";					//用于指明初始化方法
        
            String destroyMethod() default "(inferred)";	//用于指明消除方法
        }
        
  2. 修饰bean的相关注解

    1. @Scope,用于指明bean的作用域,常见作用域如下

      1. singleton,默认值,单例,全局有且仅有一个实例
      2. prototype,原型,每次获取Bean的时候都会创建一个新的实例
      3. request,针对每一次http请求都会产生一个新的bean,同时该bean只在此次http请求内有效
      4. session,针对每一次无bean的http请求都会产生一个新的bean,同时该bean只在此个session中有效

      事实上90%以上的业务使用singleton即可,这也就是为什么Spring用singleton作为默认值,不过由于singleton保证了全局只有一个实例,使得如果实例中有非静态变量时,会因共享资源的竞争而导致线程安全问题,当然因为是单例所以不用频繁GC,同时也会节省内存,使得总体性能会有所提升,@Scope实现如下

      @Target({ElementType.TYPE, ElementType.METHOD})
      @Retention(RetentionPolicy.RUNTIME)
      @Documented
      public @interface Scope {
          @AliasFor("scopeName")
          String value() default "";
      
          @AliasFor("value")
          String scopeName() default "";
      
          ScopedProxyMode proxyMode() default ScopedProxyMode.DEFAULT;
      }
      
    2. @Primary,指明该bean为首选bean,当有多个符合要求的bean时会首先选择该个bean

    3. @Qualify,可在注解中写入名称来详细指明注入的bean,如@Qualify("firstBean")就是指明注入一个名称为firstBean的bean

    4. @Profile,组合了@Condition的注解,指明bean的方法或bean在什么情况下起作用,如@Profile("test")需要在spring.profiles.active = test时才有效,对于Springboot可以直接在application.profiles中设置,也可以通过容器的getEnvironment().setActiveProfiles("test")方法设置

  3. 配置类的相关注解

    1. @Configuration,指明该类为bean并将其设置为配置类,配置类中可以有多个返回bean的方法,这些方法需要用@Bean注释
    2. @Import,用于导入其他多个配置类到一个配置类中,如@Import({Config.clsss,BasicConfig.clss})就是将Config和BasicConfig两个配置类导入到当前配置类中
    3. @PropertyResource,用于导入相应的资源文件,可以配合@Value来获取对应的资源信息,其属性为文件的路径,需要加上classpath:来指明是类路径,如@PropertyResource("classpath:test.properties"),在maven项目中就是导入resources目录下的test.properties文件
    4. @ComponentScan,用于指明扫描的范围,地址是以类路径起始的,如@ComponentScan("basic")就是在maven项目中扫描Java包下的basic包中的所有文件,默认扫描该类所在包及其子包中的所有类
  4. 注入bean和属性的相关注解

    1. @Autowired,用于装配bean,默认按类型装配,详情如下

      @Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
      @Retention(RetentionPolicy.RUNTIME)
      @Documented
      public @interface Autowired {
          boolean required() default true;		//是否必要,即是否允许为null,默认不允许
      }
      
    2. @Resource,JDK1.6支持的注解,默认按照名称进行装配,名称可以通过name属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取字段名为名称来按照名称查找,如果注解写在setter方法上默认取属性名作为名称来查找装配,当找不到与名称匹配的bean时才按照类型进行装配,不过只要指定了name属性则只会按照名称进行装配

    3. @Value,用于注入资源信息,如MySQL相关配置等,在使用前需要通过@Properties先导入对应的资源文件,使用格式为@Value("${properties文件中对应key值}"),通过它注入属性不需要set方法

1.3AOP概念

  1. 代理模式视图如下

  2. 静态代理:在编译期完成,完成后代理类会是一个具体的类,静态代理只能为一个目标对象服务,不过效率高,示例如下

    //接口
    public interface Fly(){
        void fly();
    }
    
    //具体类、被代理类
    public class Bird implements Fly(){
        public void fly(){
            System.out.println("the bird is flying");
        }
    }
    
    //代理类
    public class BirdProxy implements Fly(){
        private Bird bird;			//需要构造注入一个具体类
        public void fly(){
            System.out.println("start--------");
            bird.fly();
            System.out.println("end----------");
        }
    }
    
    //测试
    public class Test(){
        public static void main(String[] args){
            Fly fly=new BirdProxy(new Bird());
            fly.fly();
        }
    }
    
    //结果
    start--------
    the bird is flying    
    end----------
    
  3. 动态代理:在运行时通过反射动态生成对应的代理类,编译时并不存在实际的代理类,动态代理可以为多个目标对象服务,比较灵活,但基于反射实现的动态代理效率较低

    1. JDK:基于反射实现,代理对象必须实现了一个或多个接口
    2. cglib:基于字节码处理框架ASM实现,代理对象不必实现一个或多个接口,它可以在运行期间扩展Java类或实现Java接口,且代理类无侵入
  4. AOP:Spring AOP是综合了JDK和cglib两种技术实现的动态代理,性能很高且适用范围也很广,Spring AOP的作用为抽离与业务无关的系统代码并整合在一起统一管理,大大降低了整个软件的耦合度、繁杂度及代码量,使得程序员能更高效的实现业务并为代码迭代升级

    1. 相关概念
      1. 横切关注点:跨越应用程序多个模块的、与业务无关的方法或模块,如日志、安全、缓存、事务等
      2. 切面:整合后的、模块化的横切关注点对象,为一个类
      3. 通知:切面中进行的额外操作,如记录日志、权限检查等
      4. 目标:被通知或者说是被代理的对象
      5. 代理:向目标对象注入通知后得到的代理对象
      6. 切入点与连接点:前者为切面中的对应方法,后者为目标中的对应方法
    2. 代理过程:
      1. 注册自动代理器,Spring加载自动代理器AnnotationAwareAspectJAutoProxyCreator作为一个系统组件
      2. 构建代理工厂,当一个bean加载到Spring中时,就会触发自动代理器中的bean后置处理,bean后置处理时会先扫描bean中所有的Advisor,然后用这些Adviosr和其他参数构建ProxyFactory
      3. 创建代理对象,当某个bean对象与切面规则匹配时,ProxyFactory便会创建出对应的代理bean并将其放入context中,之后调用其代理的方法或将这个代理bean注入到对应的属性中
    3. 实现细节
      1. 默认情况下Spring是不会加载自动代理器的,需要在配置类上添加@EnableAspectJAutoProxy来让Spring去加载自动代理器
      2. 当Spring AOP基于注解配置时,会使用到AspectJ包的标准注解,因此需要在maven中添加对AspectJ的依赖来引入AspectJ的标准注解
      3. Advisor中包含了通知方法(Advice)和切面规则(PointCut)
      4. Spring AOP会根据目标是否实现了接口来选择使用JDK还是cglib来实现动态代理
    4. 注意事项
      1. 由于使用动态代理,所以final、static、private、构造器等方法是无法使用AOP的,并且如果类是final的还会触发异常而无法启动Spring
      2. 自调用不会被拦截,源于自调用会直接转换成this.对应方法名调用,所以会直接调用自己的方法,不会调用代理的方法,因此表现为没有被拦截的现象,推荐不要出现自调用
      3. 通过FactoryBean得到的bean也是可以被aop代理的
      4. 正常情况下切面相关方法执行顺序为Around、Before、Around、After、AfterReturning
      5. 有异常抛出时切面相关方法执行顺序为Around、Before、Around、After、AfterThrowing
      6. 有多个切面拦截同一个方法时,多个切面执行的先后顺序是随机的,可以添加@Order(int)注解,其值越小则优先级越高
      7. 切面类及被代理类都必须是bean才能使用spring AOP

1.4AOP相关注解

  1. 注明切面的相关注解

    1. @Aspect,此为AspectJ的注解,并非spring原生的,所以也就没有组合@Component注解,因此标明切面类时还需要为切面类添加额外的@Component注解指明该切面类为bean,@Before、@After、@PointCut等注解只能在切面类的方法上使用才能起作用
  2. 注明切点的相关注解

    1. @PointCut,同样为Aspect的注解,用于标明切点,方便之后复用,具体情况如下

      @Retention(RetentionPolicy.RUNTIME)
      @Target({ElementType.METHOD})
      public @interface Pointcut {
          String value() default "";					//用于指明切点位置、参数等
      
          String argNames() default "";				//用于指明切点方法参数
      }
      

      其详尽使用实例如下

      //execution指明了切断位置,args指明了参数,注意args的参数名必须与方法中的参数名相同
      @Pointcut("execution(public * org.example.bean.SecondBean.printTest(..))&&args(i)")
      public void basic(int i){
      
      }
      
      //指明了切点,参数名可与原切点不同,但注解中的参数名必须与方法中的参数名相同
      @Before("basic(j)")
      public void beforeExecution(JoinPoint i,int j){
          System.out.println("before");
      }
      
      1. execution详解

        1. 简介:用于指明切点,格式为execution(访问修饰符 返回值 包名.类名.方法名(参数)),访问修饰符可省

        2. 特殊符号

          1. *,可以表示任意方法、任意访问修饰符等
          2. ..,表示此包及其所有子包或任意参数
        3. 示例

          //拦截org.example包下类名为bean的、公共的、返回值为空的,拥有一个int参数的test方法
          execution(public void org.example.bean.test(int))
              
          //拦截org.example包下以Imp结尾的类的公共方法,不包含子包    
          execution(public * org.example.*Imp.*(..))    
              
          //拦截org.example包及其子包下的任意类的任意方法
          execution(* org.example..*.*(..))    
              
          //拦截所有公共方法
          execution(* *(..))    
          
      2. args详解

        1. 简介:用于指明参数,不用写类型,但其方法上要写,格式为args(参数名1,参数名2,....),当配合execution()使用是两者之间要加&&来连接
        2. 注意点
          1. 注解中的参数名和方法中的参数名必须相同
          2. 每一个通知方法都会默认被传入一个JoinPoint或ProceedingJoinPoint对象,这些参数不用显示指明,但必须位于方法参数的第一位
      3. @target详解

        1. 简介:用于增加匹配规则,只有对应类有指定注解时才会被拦截
        2. 注意点
          1. 同样需要用&&来连接
          2. 其值应是一个全注解名
      4. @annotation,类似于@target,只有对应方法有指定注解时才会被拦截

      5. JoinPoint详解

        1. 简介:一个包含了拦截方法相关信息的对象,而ProceedingsJoinPoint会比该类多一个proceed()方法用于放行,会在环绕通知时替代JoinPoint作为默认参数传入对应方法

        2. 常见方法

          1. getSignature(),用于获取封装了署名信息的对象,在该对象中可以获取到目标方法名,所属类的Class等信息

          2. getArgs(),用于获取包含了目标方法参数的Object数组

          3. getTarget(),用于获取被代理对象,为Object类型

          4. getThis(),用于获取代理对象,也是Object类型

          5. proceed(),执行被拦截的方法,如果有参数应记得传入其中

          6. 示例如下

            @Before("execution(public * org.example.bean.SecondBean.printTest(..))&&args(i)")
            public void beforeExecution(JoinPoint j, int i){
                System.out.println(j.getSignature().getName());
                System.out.println(j.getArgs()[0]);
                System.out.println(((SecondBean) j.getTarget()).getFb().getI());
            }
            
  3. 注明通知的相关注解

    1. @Before、@After

      1. 简介:用于定义前置通知和后置通知,必定会被执行

      2. 属性:其value可以是一个切点配置("execution()..."),也可也是一个切点方法,后一个argsName用于指明参数,详细如下

        @Retention(RetentionPolicy.RUNTIME)
        @Target({ElementType.METHOD})
        public @interface Before {
            String value();
        
            String argNames() default "";		//不常用,一般使用args()来指明参数
        }
        
    2. @Around

      1. 简介:用于定义环绕通知即被拦截方法执行前后需要再执行哪些操作,实例如下

        @Around("execution(public * org.example.bean.SecondBean.printTest(..))&&args(i)")
        public void beforeExecution(ProceedingJoinPoint j, int i){
            System.out.println("around before");
            try {
                j.proceed();					//用于放行或者说执行被拦截方法
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }
            System.out.println("around after");
        }
        
    3. @AfterReturning

      1. 简介:用于定义返回通知,方法正确返回后才会执行,多了一个返回值属性,其他类似于@After

      2. 属性:returning用于指明返回值名,不用指明类型,不过注解的返回值名必须与方法的返回值名相同,其他类型与@After,示例如下

        @AfterReturning(value = "execution(public * org.example.bean.SecondBean.printTest(..))&&args(i)",returning = "k")
        public void beforeExecution(JoinPoint j, int i,int k){
            System.out.println(k);				//输出返回值
        }
        
    4. @AfterThrowing

      1. 简介:用于定义抛出异常时的通知,方法在抛出异常后才会执行,多了一个抛出异常属性,其他类似于@After
      2. 属性:throwing用于指明抛出异常名,不用指明类型,不过注解的抛出异常名必须与方法的抛出异常名相同

1.5事务

  1. spring事务管理的三个接口

    1. PlatformTransactionManager,事务管理器,提供了提交事务、回滚事务、获取事务三个方法,该接口针对不同的平台如Hibernate与mybatis会有不同的修改,最终的实现还是交给的各个平台,可以看出Spring在事务管理中只起一个辅助作用,真正进行事务管理还是各个平台

    2. TransactionDefinition,事务定义,事务管理器会基于事务定义来获取事务,事务定义包括隔离级别、传播行为、回滚规则、是否只读、事务超时这五个方面的信息,详细如下

      1. 隔离级别
        1. TransactionDefinition.ISOLATION_DEFAULT,采用后端数据库的默认隔离级别
        2. TransactionDefinition.ISOLATION_READ_UNCOMMITTED,不提交读
        3. TransactionDefinition.ISOLATION_READ_COMMITTED,提交读
        4. TransactionDefinition.ISOLATION_REPEATABLE_READ,可重复读
        5. TransactionDefinition.ISOLATION_SERIALIZABLE,序列化
      2. 传播行为,当一个事务方法被另一个事务方法调用时,事务该如何传播
        1. 支持当前事务
          1. TransactionDefinition.PROPAGATION_REQUIRED,如果当前存在事务,则加入该事务,如果当前没有事务,则创建一个新的事务
          2. TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务,如果当前没有事务,则以非事务的方式继续运行
          3. TransactionDefinition.PROPAGATION_MANDATORY: 如果当前存在事务,则加入该事务,如果当前没有事务,则抛出异常
          4. TransactionDefinition.PROPAGATION_NESTED: 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行,如果当前没有事务,则创建一个事务,内嵌事务实际上就是一个savepoint,外部事务才是真正的事务,所有内嵌事务不能单独提交,只有外部事务提交时才能提交
        2. 不支持当前事务
          1. TransactionDefinition.PROPAGATION_REQUIRES_NEW: 创建一个新的事务,如果当前存在事务,则把当前事务挂起
          2. TransactionDefinition.PROPAGATION_NOT_SUPPORTED: 以非事务方式运行,如果当前存在事务,则把当前事务挂起
          3. TransactionDefinition.PROPAGATION_NEVER: 以非事务方式运行,如果当前存在事务,则抛出异常
      3. 回滚规则:这些规则定义了哪些异常会导致事务回滚而哪些不会,默认情况下,事务只有遇到运行期异常时才会回滚,而在遇到检查型异常时不会回滚
      4. 是否只读:指明事务是否会修改资源,如果不会则表明为只读事务从而提高事务性能
      5. 事务超时:指明一个事务必须在多长时间内完成,否则自动回滚,单位是秒
    3. TransactionStatus,事务状态,包括事务是否完成、是否为新事务、是否为回滚、是否有恢复点等,用于事务回滚和事务提交,详细如下

      public interface TransactionStatus{
          boolean isNewTransaction(); 	// 是否是新的事物
          boolean hasSavepoint(); 		// 是否有恢复点
          void setRollbackOnly(); 	 	// 设置为只回滚
          boolean isRollbackOnly(); 		// 是否为只回滚
          boolean isCompleted; 			// 是否已完成
      } 
      
      
  2. 声明式事务:spring支持编程式事务和声明式事务,后者更为便捷,基于spring aop实现,以下是基于注解的声明式事务使用方式

    1. 在maven中引入spring-jdbc依赖,实例如下

      <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-jdbc</artifactId>
          <version>5.1.10.RELEASE</version>
      </dependency>
      
    2. 在配置类上加@EnableTransactonManagement来开启注解事务

    3. 创建返回对应事务管理器的被@Bean修饰的方法

      //注意这个dataSource是必须的,在此处希望作为bean注入
      @Bean
      public DataSourceTransactionManager transactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);	
      }
      
    4. 在要使用事务管理的方法上加上@Transactional标签

  3. @Transactional

    1. 详情

      @Target({ElementType.TYPE, ElementType.METHOD})
      @Retention(RetentionPolicy.RUNTIME)
      @Inherited
      @Documented
      public @interface Transactional {
          //指明事务管理器,不指明则spring会自动使用一个transactionManager
          @AliasFor("transactionManager")
          String value() default "";													
      
          @AliasFor("value")
          String transactionManager() default "";
      
          //事务传播行为,默认是有则加入,没有则创建
          Propagation propagation() default Propagation.REQUIRED;
      
          //隔离级别,默认是使用数据库的隔离级别
          Isolation isolation() default Isolation.DEFAULT;
      
          //超时,默认是无超时限制
          int timeout() default -1;
      
          //是否只读,默认否
          boolean readOnly() default false;
      
          //回滚异常
          Class<? extends Throwable>[] rollbackFor() default {};
      
          String[] rollbackForClassName() default {};
      
          //不回滚异常
          Class<? extends Throwable>[] noRollbackFor() default {};
      
          String[] noRollbackForClassName() default {};
      }
      
    2. 注意点

      1. 由于是基于AOP实现的,所有@Transactional一般只在public方法上才起作用,且对自调用无效
      2. 尽量不要从@Transactional注释的方法内捕获异常,因为spring事务会将异常从方法外抛出
      3. 默认情况下Spring只会对非受查异常回滚,如空指针异常,受查异常如IO异常时不回滚的
      4. 当@Transactional注释到类上时,其所有public方法都会被纳入spring事务管理,并使用相同的管理方式