spring


spring


spring框架介绍

传统项目的架构

  • 在传统的项目中,一般遵循MVC开发模型。

    1. view层与用户进行交互,显示数据或者将数据传输给view层。
    2. 在controller层创建service层对象,调用service层中业务方法。
    3. 在service层创建dao层对象,调用dao层中操作数据的方法。
    4. dao层进行具体的数据库操作
  • 架构图

    架构图

spring的核心组件

组件

核心容器

  • 核心容器由 spring-core,spring-beans,spring-context,spring-context-support和spring-expression(SpEL,Spring 表达式语言,Spring Expression Language)等模块组成,它们的细节如下:

    1. spring-core 模块提供了框架的基本组成部分,包括 IoC 和依赖注入功能。
    2. spring-beans 模块提供 BeanFactory,工厂模式的微妙实现,它移除了编码式单例的需要,并且可以把配置和依赖从实际编码逻辑中解耦。
    3. context 模块建立在由 core和 beans 模块的基础上建立起来的,它以一种类似于 JNDI 注册的方式访问对象。Context 模块继承自 Bean 模块,并且添加了国际化(比如,使用资源束)、事件传播、资源加载和透明地创建上下文(比如,通过 Servelet 容器)等功能。Context 模块也支持 Java EE 的功能,比如 EJB、JMX 和远程调用等。ApplicationContext 接口是 Context 模块的焦点。spring-context-support 提供了对第三方库集成到 Spring 上下文的支持,比如缓存(EhCache, Guava, JCache)、邮件(JavaMail)、调度(CommonJ, Quartz)、模板引擎(FreeMarker, JasperReports, Velocity)等。
    4. spring-expression 模块提供了强大的表达式语言,用于在运行时查询和操作对象图。它是 JSP2.1 规范中定义的统一表达式语言的扩展,支持 set 和 get 属性值、属性赋值、方法调用、访问数组集合及索引的内容、逻辑算术运算、命名变量、通过名字从 Spring IoC 容器检索对象,还支持列表的投影、选择以及聚合等。
  • 依赖关系图

    依赖关系

数据访问/集成

  • 数据访问/集成层包括 JDBC,ORM,OXM,JMS 和事务处理模块,它们的细节如下:

    :JDBC=Java Data Base Connectivity,ORM=Object Relational Mapping,OXM=Object XML Mapping,JMS=Java Message Service)

    1. JDBC 模块提供了 JDBC 抽象层,它消除了冗长的 JDBC 编码和对数据库供应商特定错误代码的解析。
    2. ORM 模块提供了对流行的对象关系映射 API 的集成,包括 JPA、JDO 和 Hibernate 等。通过此模块可以让这些 ORM 框架和 spring的其它功能整合,比如前面提及的事务管理。
    3. OXM 模块提供了对 OXM 实现的支持,比如 JAXB、Castor、XML Beans、JiBX、XStream 等。
    4. JMS 模块包含生产(produce)和消费(consume)消息的功能。从 Spring 4.1 开始,集成了 spring-messaging 模块。
    5. 事务模块为实现特殊接口类及所有的 POJO 支持编程式和声明式事务管理。(注:编程式事务需要自己写 beginTransaction()、commit()、rollback() 等事务管理方法,声明式事务是通过注解或配置由 spring 自动处理,编程式事务粒度更细)

web层

  • Web 层由 Web,Web-MVC,Web-Socket 和 Web-Portlet 组成,它们的细节如下:
    1. Web 模块提供面向 web 的基本功能和面向 web 的应用上下文,比如多部分(multipart)文件上传功能、使用 Servlet 监听器初始化 IoC 容器等。它还包括 HTTP 客户端以及 Spring 远程调用中与 web 相关的部分。
    2. Web-MVC 模块为 web 应用提供了模型视图控制(MVC)和 REST Web服务的实现。Spring 的 MVC 框架可以使领域模型代码和 web 表单完全地分离,且可以与 Spring 框架的其它所有功能进行集成。
    3. Web-Socket 模块为 WebSocket-based 提供了支持,而且在 web 应用程序中提供了客户端和服务器端之间通信的两种方式。
    4. Web-Portlet 模块提供了用于 Portlet 环境的 MVC 实现,并反映了 spring-webmvc 模块的功能。

其他

  • 还有其他一些重要的模块,像 AOP,Aspects,Instrumentation,Web 和测试模块,它们的细节如下:
    1. AOP 模块提供了面向方面(切面)的编程实现,允许你定义方法拦截器和切入点对代码进行干净地解耦,从而使实现功能的代码彻底的解耦出来。使用源码级的元数据,可以用类似于.Net属性的方式合并行为信息到代码中。
    2. Aspects 模块提供了与 AspectJ 的集成,这是一个功能强大且成熟的面向切面编程(AOP)框架。
    3. Instrumentation 模块在一定的应用服务器中提供了类 instrumentation 的支持和类加载器的实现。
    4. Messaging 模块为 STOMP 提供了支持作为在应用程序中 WebSocket 子协议的使用。它也支持一个注解编程模型,它是为了选路和处理来自 WebSocket 客户端的 STOMP 信息。
    5. 测试模块支持对具有 JUnit 或 TestNG 框架的 Spring 组件的测试。

Bean标签的属性介绍

id

  • 是 bean的唯一标识 一个bean,其id 值只能有一个 。整个IOC 容器id 值不允许重复,使用名称作为key

name

  • 一个bean的名称,可以存在多个,多个之间使用逗号分隔。不论bean有没有定义name属性,默认id都会当做name。

class

  • bean的具体的类型,包名和类名组成。

scope

  • bean的作用域
    1. prototype :非单例,每次获取都会创建一个新的bean对象。
    2. singleton : 单例,多次获取永远同一个bean, 默认值。
    3. request : 一次请求,基于web项目的bean的作用域。
    4. session : 一次会话,基于web项目的bean的作用域。

lazy-init

  • 延迟初始化,默认只要加载了配置文件。bean对象就会被初始化,lazy-init则是获取时才会初始化。只针对单例模式有效,非单例每次获取都会创建,没有延迟初始化的意义

depends-on

  • 初始化时依赖的对象,当前对象初始化前需先初始化depends-on指定的对象

init-method

  • 对象初始化后,调用的方法

destroy-method

  • 对象销毁时,调用的方法

autowire

  • 属性自动装配

    1. byName 根据属性名称装配

    2. byType 根据类型装配

autowire-candidate

  • 是否允许作为自动装配的候选项

    1. true 作为自动装配的候选项

    2. false 不作为自动装配的候选项

primary

  • 优先使用该bean,因为Spring需要支持使用类型查找对象,在一个大类型下,可能存在多个小类型。如果根据大类型装配属性时,不知道使用哪个具体的对象,则可以根据primary设置优先级。

Bean对象创建的方法

构造方法创建

<bean id="user" class="com.abc.domian.User" />

静态工厂创建

<!--
    id : bean 的唯一标识
    class : 工厂类
    factory-method : 工厂方法
 -->
<bean id="user2" class="com.abc.factory.UserStaticFactory" factory-method="getObj" />

非静态工厂创建

<!--
    非静态工厂创建对象
        在非静态工厂中,创建对象的方法是非静态方法。非静态方法的执行,首先需要该类对象
        注意: 使用非静态工厂创建对象,首先需要创建工厂类对象
-->
<!-- 工厂类对象 -->
<bean id="userFactory" class="com.abc.factory.UserFactory" />
<!-- 使用非静态工厂创建对象 -->
<!--
    factory-bean : 非静态工厂对象
    factory-method : 创建对象的非静态方法
-->
<bean id="user3" factory-bean="userFactory" factory-method="getObj" />

注解创建

  • 组件注解

    • @Component

      表示该类为一个被Spring管理的组件。但是,由于在开发中为了让代码的可读性更高。

      Spring基于分层思想,将需要创建的组件分为以下几类:

      1. @Controller

        @Controller注解,标识该类是controller层的类。并且,注意在使用SpringMVC时,所有的Constroller,必须使用@Controller注解。

      2. @Service

      @Service注解,标识该类是业务层的类。

      1. @Respository

        @Respository注解,标识该类是操作数据层的类。

  • 注解使用步骤

    • 在spring的核心配置文件中,开启注解扫描,让Spring将被注解修饰的类,创建对相关。

      <!--
          开启组件扫描
       -->
      <context:component-scan base-package="com.abc.*" />
      
    • 将需要交给spring管理的类上面标上对应的注解

      import org.springframework.stereotype.Component;
      @Component
      public class Person {
      
          public Person(){
              System.out.println("Person的构造方法.........");
          }
      }
      

ioc属性注入

构造方法属性注入

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
        <!-- 无参构造方法 -->
        <bean class="com.abc.domain.User" />
        <!--
           有参数的构造方法
                此时是2个参数的构造方法
                index : 参数下标  从 0开始
                value : 属性的值
         -->
        <bean id="user2" class="com.abc.domain.User" >
            <constructor-arg index="0" value="1001" />
            <constructor-arg index="1" value="韩梅梅" />
        </bean>
        <!-- 有参数的构造方法
                使用index下标查找 属性 存在问题 都只有一个参数 则默认使用后面的构造方法
                可以使用 type 指定参数的类型
                更推荐 使用name属性 : name表示构造器中参数的名称
         -->
        <bean id="user3" class="com.abc.domain.User">
            <constructor-arg index="0" value="1001" type="java.lang.Integer"  />
        </bean>
        <bean id="user4" class="com.abc.domain.User">
                <constructor-arg name="name" value="韩梅梅" />
        </bean>
</beans>

set方法属性注入

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
         <!--
           使用set方法进行属性注入
            property 表示属性
                name : 表示属性对应的set方法名,去掉set前缀,首字母小写。并不是真正的属性名
         -->
        <bean id="student1" class="com.abc.domain.Student">
           <property name="studentId" value="1001" />
        </bean>
</beans>

注解属性注入

  • 在spring中,为了简化属性的注入,Spring提供注解:**@Autowired**,Spring会自动从IOC容器中,为这个属性查找相应类型的值,进行注入。

    public class Student {
    
        public Integer id;
    
        public String name;
    
        @Autowired  //使用注解自动注入
        //User 对象
        public User user;
        public void setStudentId(Integer id) {
            System.out.println("set方法被调用了............");
            this.id = id;
        }
     /*   public void setUser(User user) {
            this.user = user;
        }*/
    }
    

    注意:在使用自动注入时,可以在bean标签上,配置autowire,但是此时必须有该属性的set方法,**@Autowired**注解,是不需要set方法的。

    如果是在xml中注入对象,值使用ref属性。value属性,只支持boolean,数字,字符串等。

AOP代理

aop简介

  • 代理:静态代理
    • 静态代理,每个被代理类都需要创建对应的代理类。随着程序的扩展,代理类也会增多,臃肿,维护量变多,为了解决这个问题,Java中,提供了动态代理技术,开发者不需要自己定义代理类,代理类由JDK动态的创建,开发只需要指定被代理的类即可。

动态代理

  • JDK动态代理

    • proxy

    • 该类提供了方法创建代理类和代理类的对象的方法

      创建一个代理类并返回代理类对象

      static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)  
      loader :// 类加载器,指定类加载器,是为了精确的定位类
      interfaces : // 接口Class类,使用JDK的反射,必须要有接口
      h :InvocationHandler ,//代理的处理器,每个代理类都有一个关联的处理器
      
    • InvocationHandler

    • 是每个代理类对应的处理器

      Object invoke(Object proxy,Method method,Object[] args)
      Object  //方法调用的返回值,可以作为被代理的方法调用的返回值
      proxy : //代理类对象
      method : //目标类中被代理的方法
      args : //目标类中被代理的方法的运行参数
      
    • 例子如下

      //目标接口类
      public interface Agent {
          void rent();
          void rent2(int i);
      }
      //目标类
      public class FangDong implements Agent{
          @Override
          public void rent() {
              System.out.println("租房1000元");
          }
      
          @Override
          public void rent2(int i) {
              System.out.println("第二套房");
          }
      }
      //代理增强类
      public class MyRent implements MethodBeforeAdvice {
      
          @Override
          public void before(Method method, Object[] objects, Object o) throws Throwable {
              System.out.println("增加500元");
          }
      }
      
  • cglib动态代理

    • MethodInterceptor

      • cglib中,提供的对方法执行拦截的接口。其中intercept是对具体方法进行拦截处理的方法。

        public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,
                                       MethodProxy proxy) 
        Object  :// 方法执行返回的结果
        obj ://增强类的对象
        method ://目标方法
        proxy ://用于回调的方法的对象
        
      • 例子如下

        //代理增强类
        public class MyMethodInterceptor implements MethodInterceptor {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("多收5000元租金");
                return methodProxy.invokeSuper(o,objects);
            }
        }
        //目标类
        public class Fangdong {
            public void sent() {
                System.out.println("房子出租1000元");
            }
        }
        //测试类
        public class App {
            public static void main(String[] args) {
                Enhancer enhancer = new Enhancer();
                enhancer.setSuperclass(Fangdong.class);
                enhancer.setCallback(new MyMethodInterceptor());
                Fangdong fangdong = (Fangdong) enhancer.create();
                fangdong.sent();
            }
        }
        

spring的AOP配置

  • AOP的相关概念

    • **连接点(JoinPoint)**:所谓连接点是指那些被拦截的点,而spring中这些点就是指方法,因为spring只支持方法类型的连接点。
    • **切入点(PointCut)**:所谓切入点就是指我们要对那些JoinPoint进行拦截的定义,指的是具体的拦截的位置
    • 增强/通知(Advice) : 增强就是对具体的连接点进行扩展的功能。由于一般对方法进行增强,分为在方法前执行或者方法后,或者发生异常执行等等,所以增强被分为:前置增强(前置通知)、后置增强(后置通知)、环绕通知(环绕增强)、异常增强(异常通知)
    • **引介(Introduction)**:引介是一种特殊的Advice,在不修改代码的前提下,引介可以在运行期为类动态的添加一些方法或Field.
    • 目标(Target) :被代理的类(需要增强类)
    • 织入(Weaving) :把Advice应用到Target的过程
    • 代理(Proxy):使用AOP配置后产生的代理类
    • 切面(Aspect):切点和增强整合形成了切面
  • AOP增强图

    aop增强

  • 前置增强-MethodBeforeAdvice

  • 后置增强-AfterReturningAdvice

  • 环绕增强-MethodInterceptor

  • 异常增强-ThrowsAdvice

  • aop配置

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
    
        <!-- 定义目标类对象 -->
        <bean id="targetClass" class="com.abc.impl.TargetClassImpl" />
        <!-- 定义增强类对象 前置增强类 -->
        <bean id="myBeforeAdvice" class="com.abc.advice.MyBeforeAdvice" />
        <!-- 定义增强类对象  后置增强 -->
        <bean id="myAfterAdvice" class="com.abc.advice.MyAfterAdvice" />
        <!-- 定义增强类 环绕增强 -->
        <bean id="myAroundAdvice" class="com.abc.advice.MyAroundAdvice" />
        <!-- 定义增强类  异常增强类 -->
        <bean id="myExceptionAdvice" class="com.abc.advice.MyExceptionAdvice" />
        <!-- 进行织入 -->
        <aop:config>
            <!--
                id : 连接点的唯一标识
                expression : 连接点的表达式
                    execution(* 包名.类名.方法名(..))
                    * 指任意字符
                    .. 表示参数可以是任意个
            -->
            <aop:pointcut id="beforePoint" expression="execution(* com.abc.impl.TargetClassImpl.targetMethod(..))"/>
            <!-- 后置增强的切点 -->
            <aop:pointcut id="afterPoint" expression="execution(* com.abc.impl.TargetClassImpl.afterTargetMethod(..))"/>
            <!-- 环绕增强的切点 -->
            <aop:pointcut id="aroundPoint" expression="execution(* com.abc.impl.TargetClassImpl.aroundTargetMethod(..))"/>
            <!-- 异常增强的切点 -->
            <aop:pointcut id="exceptionPoint" expression="execution(* com.abc.impl.TargetClassImpl.runException(..))"/>
            <!--
                织入
                将增强和连接点 结合
            -->
            <aop:advisor advice-ref="myBeforeAdvice" pointcut-ref="beforePoint" />
    
            <!-- 织入
                后置增强的织入
             -->
            <aop:advisor advice-ref="myAfterAdvice" pointcut-ref="afterPoint" />
    
            <!--
                织入
                环绕增强的织入
            -->
            <aop:advisor advice-ref="myAroundAdvice"  pointcut-ref="aroundPoint" />
    
            <!--
              织入
              异常增强的织入
          -->
            <aop:advisor advice-ref="myExceptionAdvice"  pointcut-ref="exceptionPoint" />
        </aop:config>
    
    </beans>
    
  • AspectJ框架AOP配置

    • 编写增强类

      public class MyAdvice {
      
          public void beforAdvice(){
              System.out.println("前置增强的方法");
          }
      
          public void afterAdvice(String name,String rs){
              System.out.println("后置增强的方法");
          }
      
          public void aroundAdvice(ProceedingJoinPoint joinPoint){
              System.out.println("前置增强");
              try {
                  joinPoint.proceed();
              } catch (Throwable throwable) {
                  throwable.printStackTrace();
              }
              System.out.println("后置增强");
          }
      
          /**
           * 异常增强
           * @param exception
           */
          public  void exceptionAdvice(Exception exception){
              System.out.println("异常增强!");
          }
      }
      
    • 编写目标类

      public interface ITargetClass {
      
          /**
           * 前置增强的方法
           */
          void  beforeMethod();
      
          /**
           * 后置增强的方法
           */
          String afterMethod(String name1);
      
          /**
           * 环绕增强的方法
           */
          void aroundMethod();
      
          /**
           * 异常增的方法
           */
          void runExceptionMethod();
      
    • 实现类

      public class TargetClassImpl  implements ITargetClass {
      
          @Override
          public void beforeMethod() {
              System.out.println("待前置增强--------beforeMethod");
          }
      
          @Override
          public String afterMethod(String name) {
              System.out.println("待后置增强--------afterMethod");
              return  "韩梅梅";
          }
      
          @Override
          public void aroundMethod() {
              System.out.println("待环绕增强--------aroundMethod");
          }
      
          @Override
          public void runExceptionMethod() {
              System.out.println("待异常增强--------runExceptionMethod");
              int m = 0;
              int n = 100/m;
          }
      }
      
    • 配置AspectJ的增强配置

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
      
          <!-- 定义增强的目标类对象 -->
          <bean id="targetClass" class="com.abc.impl.TargetClassImpl" />
          <!-- 定义增强类的对象 -->
          <bean id="myAdvice" class="com.abc.advice.MyAdvice" />
      
          <!-- 进行AOP配置 -->
          <aop:config>
              <!-- 前置切点 -->
              <!--
                    aop:before : aspectJ中 前置增强的配置
                     method : 当前增强类中前置增强的方法  方法名
                     pointcut-ref : 增强连接点
                 -->
              <aop:pointcut id="beforPoint" expression="execution(* com.abc.impl.TargetClassImpl.beforeMethod(..)) " />
              <!-- 后置切点 -->
              <!-- args 配置被增强的方法的参数名称 -->
              <aop:pointcut id="afterPoint" expression="execution(* com.abc.impl.TargetClassImpl.afterMethod(..)) and args(name)"   />
              <!-- 环绕切点 -->
              <aop:pointcut id="aroundPoint" expression="execution(* com.abc.impl.TargetClassImpl.aroundMethod(..))"  />
              <!-- 异常切点 -->
              <aop:pointcut id="exceptionPoint" expression="execution(* com.abc.impl.TargetClassImpl.runExceptionMethod(..))" />
      
              <aop:aspect ref="myAdvice">
                <!--  <aop:before method="beforAdvice" pointcut-ref="beforPoint" />-->
                  <!--
                      arg-names :后置增强中增强的方法的参数名称
                          注意: name 也是被增强的方法的参数名称 参数名称要一致
                      returning :返回结果的参数名称
                  -->
                 <aop:after-returning method="afterAdvice" pointcut-ref="afterPoint" arg-names="name,rs"   returning="rs" />
                  
                  <!--<aop:around method="aroundAdvice" pointcut-ref="aroundPoint"  />-->
                   <!--
                       throwing : 接收异常参数的名称
                   -->
                 <aop:after-throwing method="exceptionAdvice" pointcut-ref="exceptionPoint" throwing="exception"  />
              </aop:aspect>
          </aop:config>
      </beans>
      

声明式事务

xml版本事务

  • xml事务配置

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context
           https://www.springframework.org/schema/context/spring-context.xsd
           http://www.springframework.org/schema/tx
           http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
    
    
        <!--关联数据库的配置信息-->
        <context:property-placeholder location="classpath:db.properties"/>
    
          <!--注入service-->
        <bean id="accountService" class="com.abc.service.impl.AccountServiceImpl" >
        </bean>
    
        <!--注入数据源-->
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
              init-method="init" destroy-method="close">
            <property name="driverClassName" value="${db.driver}"/>
            <property name="username" value="${db.username}"/>
            <property name="password" value="${db.password}"/>
            <property name="url" value="${db.url}"/>
        </bean>
    
        <bean id="configuration" class="org.apache.ibatis.session.Configuration">
    
            <!-- 指定日志工具 -->
            <property name="logImpl"  value="org.apache.ibatis.logging.log4j.Log4jImpl" />
            <!-- 配置缓存 -->
            <property name="cacheEnabled" value="true" />
    
            <!--懒加载-->
            <property name="aggressiveLazyLoading"  value="false"/>
            <property name="lazyLoadingEnabled" value="true"/>
            <property name="lazyLoadTriggerMethods" value="clone"/>
        </bean>
        <!--注入sqlSessionFactory工厂对象-->
        <bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    
            <!--配置属性 MyBatis 的主配置文件-->
            <property name="configuration" ref="configuration"/>
            <!--配置数据源-->
            <property name="dataSource" ref="dataSource"/>
            <!--配置类的别名-->
            <property name="typeAliasesPackage" value="com.abc.domain"/>
            <!--配置关联mapper的xml
             要想省掉 它,必须要求,mapper的接口和xml文件编译之后在一个文件夹中-->
         <!--   <property name="mapperLocations" value="classpath*:**/*Mapper.xml"/>-->
            <!--配置分页插件-->
            <property name="plugins">
                <array>
                    <bean class="com.github.pagehelper.PageInterceptor">
                        <property name="properties">
                            <value>
                                helperDialect=mysql
                                reasonable=true
                                autoRuntimeDialect=true
                            </value>
                        </property>
                    </bean>
                </array>
            </property>
        </bean>
        <!--配置Mapper接口的扫描器
          这个扫描器 是专门 扫描 mapper 接口所在的包,给这些mapper接口 创建代理对象
          里面的参数设置 包的设置必须是mapper的包
         -->
        <bean  class="org.mybatis.spring.mapper.MapperScannerConfigurer">
            <property name="basePackage" value="com.bjpowernode.mapper"/>
        </bean>
    
    
         <!-- aop 机制 通过面向切面编程的思想,给程序添加事务处理-->
         <!--配置事务处理器 相当于 我们以前写的 增强类-->
        <bean id="transactionManager"  class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <!--配置数据源-->
             <property name="dataSource" ref="dataSource"/>
        </bean>
    
        <!--对什么方法 做什么增强-->
        <tx:advice id="advice" transaction-manager="transactionManager">
             <tx:attributes>
                 <!--
                   name : 进行数据库操作方法的名称  add* 表示 add开头的方法  * 指代任意字符
                   propagation : 事务传播性  面试重点
                   read-only : 只读事务  默认 false
                   rollback-for : 指定回滚的异常  默认是 RunTimeException 下的异常会自动回滚
                   no-rollback-for : 不回滚的异常
                   timeout : 事务的超时时间
                   isolation : 事务隔离级别  面试重点
                       | 1. 读未提交
                       | 2. 读已提交
                       | 3. 可重复读
                       | 4. 串行化
               -->
                 <tx:method name="find*" read-only="true"/>
                 <tx:method name="get*" read-only="true"/>
                 <tx:method name="select*" read-only="true"/>
                 <tx:method name="query*" read-only="true"/>
                 <tx:method name="list*" read-only="true"/>
                 <!--isolation="DEFAULT" 隔离级别 默认隔离级别 不用写 propagation 传播行为 默认的-->
                 <tx:method name="*" propagation="REQUIRED" isolation="DEFAULT"/>
             </tx:attributes>
        </tx:advice>
    
        <!--aop 的配置-->
        <aop:config>
    
            <!--切入点-->
             <aop:pointcut id="pointcut" expression="execution(* com.abc.service.impl.*Impl.*(..))"/>
    
            <!--织入-->
            <aop:advisor advice-ref="advice" pointcut-ref="pointcut"/>
    
        </aop:config> 
    </beans>
    
  • 注解版声明事务,配置

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context
           https://www.springframework.org/schema/context/spring-context.xsd
           http://www.springframework.org/schema/tx
           http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
    
    
        <!--关联数据库的配置信息-->
        <context:property-placeholder location="classpath:db.properties"/>
    
          <!--注入service-->
        <bean id="accountService" class="com.abc.service.impl.AccountServiceImpl" >
        </bean>
    
        <!--注入数据源-->
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
              init-method="init" destroy-method="close">
            <property name="driverClassName" value="${db.driver}"/>
            <property name="username" value="${db.username}"/>
            <property name="password" value="${db.password}"/>
            <property name="url" value="${db.url}"/>
        </bean>
    
        <bean id="configuration" class="org.apache.ibatis.session.Configuration">
    
            <!-- 指定日志工具 -->
            <property name="logImpl"  value="org.apache.ibatis.logging.log4j.Log4jImpl" />
            <!-- 配置缓存 -->
            <property name="cacheEnabled" value="true" />
    
            <!--懒加载-->
            <property name="aggressiveLazyLoading"  value="false"/>
            <property name="lazyLoadingEnabled" value="true"/>
            <property name="lazyLoadTriggerMethods" value="clone"/>
        </bean>
        <!--注入sqlSessionFactory工厂对象-->
        <bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    
            <!--配置属性 MyBatis 的主配置文件-->
            <property name="configuration" ref="configuration"/>
            <!--配置数据源-->
            <property name="dataSource" ref="dataSource"/>
            <!--配置类的别名-->
            <property name="typeAliasesPackage" value="com.abc.domain"/>
            <!--配置关联mapper的xml
             要想省掉 它,必须要求,mapper的接口和xml文件编译之后在一个文件夹中-->
         <!--   <property name="mapperLocations" value="classpath*:**/*Mapper.xml"/>-->
            <!--配置分页插件-->
            <property name="plugins">
                <array>
                    <bean class="com.github.pagehelper.PageInterceptor">
                        <property name="properties">
                            <value>
                                helperDialect=mysql
                                reasonable=true
                                autoRuntimeDialect=true
                            </value>
                        </property>
                    </bean>
                </array>
            </property>
        </bean>
        <!--配置Mapper接口的扫描器
          这个扫描器 是专门 扫描 mapper 接口所在的包,给这些mapper接口 创建代理对象
          里面的参数设置 包的设置必须是mapper的包
         -->
        <bean  class="org.mybatis.spring.mapper.MapperScannerConfigurer">
            <property name="basePackage" value="com.abc.mapper"/>
        </bean>
    
    
         <!-- aop 机制 通过面向切面编程的思想,给程序添加事务处理-->
         <!--配置事务处理器 相当于 我们以前写的 增强类-->
        <bean id="transactionManager"  class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <!--配置数据源-->
             <property name="dataSource" ref="dataSource"/>
        </bean>
        <!--事务注解驱动-->
         <tx:annotation-driven transaction-manager="transactionManager"/>
    </beans>
    
  • service代码

    @Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT)
    public class AccountServiceImpl implements IAccountService {
    
        @Autowired
        private AccountMapper accountMapper;
    
        @Transactional // 方法上添加事务 或者类上添加事务注解 都可以
        // 添加在类上,表示类中的所有方法都有事务
        // 添加在方法上,表示该方法有事务
        public void transMoney(String sourceName, String targetName, BigDecimal money) {
              // 开启事务
            accountMapper.subMoney(sourceName,money);
            int i = 1/0;
            accountMapper.addMoney(targetName,money);
            // 提交事务
            // 回滚事务
        }
    }
    

事务的传播性

传播级别 说明 描述
REQUIRED 必须的 默认值,表示当前若存在事务则使用当前事务,若不存在则创建一个新的事务
SUPPORTS 支持的 表示当前若存在事务则在当前事务中执行,若不存在则在非事务中执行
MANDATORY 强制性的 表示必须在事务中执行,若当前没有事务则抛出异常
NEVER 绝不 表示一定不在事务中的执行,若当前存在事务则报错
NESTED 嵌套的 若当前存在事务,则创建一个子事务,嵌套在当前事务中,注意,外层事务出现异常会回滚子事务,子事务出现异常,不影响外层事务
REQUIRES_NEW 必须新建 表示无论当前是否存在事务,都会创建一个新的事务,在新的事务中执行
只支持JtaTransactionManager
NOT_SUPPORTED 不支持事务 表示不论当前是否存在事务,都不会在事务中执行。只支持JtaTransactionManager

文章作者: 勾魂大猩猩
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 勾魂大猩猩 !
  目录