Spring AOP 代理事务及 事务隔离级别

本文介绍了Spring AOP的基本概念及实现方式,对比了Spring AOP与AspectJ的不同之处,并详细解析了AOP中的核心术语。同时,文章还探讨了如何在Spring中使用注解配置事务管理,并解释了不同事务传播行为的效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

SpringAOP面向切面编程

aopalliance:联合的开源协作组织,在多个项目间进行协作以期提供一套标准的AOP Java接口

Spring AOP:就是基于AOP Alliance标准API实现的

aspectJ:采用了源代码生成技术来实现AOP。它提供了一套独有的基于Java平台的AOP语法,以及专有的AspectJ编译器。,能够识别诸如aspect,pointcut等特殊关键字,然后利用静态织入的方式.

Spring AOP与AspectJ区别

Spring 允许使用 AspectJ Annotation 用于定义方面(Aspect)、切入点(Pointcut)和增强处理(Advice),Spring 框架则可识别并根据这些 Annotation 来生成 AOP 代理。Spring 只是使用了和 AspectJ 5 一样的注解,但并没有使用 AspectJ 的编译器或者织入器(Weaver),底层依然使用的是 Spring AOP,依然是在运行时动态生成 AOP 代理,并不依赖于 AspectJ 的编译器或者织入器。

AOP 术语:

① Aspect(切面):将关注点提取模块化,最终放到一个类里面如上列SecurityHandler 

② Advice(通知):具体横切关注点实现 如:checkSecurity(),包括Before Advice,after Advice,拦截器MethodInterceptor(实现Advice

③ Pointcut(切入点):应用到 哪些目标对象的,哪些方法上。如:Pointcut(add*)应用到add*方法

④ Weave(织入):将advice应用到目标对象的方法这个过程,术语名称为织入。

⑤ JointPoint(连接点):就是要拦截的方法 如:adduser() 方法

⑥ TargetObject:目标对象UserManagerImpl 

Advisor=advice(具体通知,拦截需要做什么)+pointcut(需要拦截哪些方法)定义应该在哪里应用哪个通知

拦截:主要通过反射和正则表达式完成

1)JDK动态代理(有接口):实现InvocationHandlerinvoke方法

public class SecurityHandler implements InvocationHandler {

    private Object targetObject;// 目标对象

    // 传入目标对象

    public Object newProxy(Object targetObject) {

       this.targetObject = targetObject;

       // 对目标对象封装,并且返回代理对象(属于目标对象接口)(目标对象类加载器,目标对象接口,自身引用)

       return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),

       targetObject.getClass().getInterfaces(), this);

    }

    // 代理对象拦截到要执行的方法

    public Object invoke(Object proxy, Method method, Object[] args)

    throws Throwable {

       checkSecurity();

       // 目标对象真正执行,有的函数有返回值需要定义ret

       Object ret = method.invoke(targetObject, args);

       return ret;

    }

    public void checkSecurity() {

       System.out.println("--------安全性检查checkSecurity()-------");

    }

}

2)CGLIB代理(无接口,内存临时生成):实现MethodInterceptor (强制使用cglib:<aop:aspectj-autoproxy proxy-target-class="true"/> )

org.aopalliance.intercept.MethodInterceptor:

public class SpringMethodInterceptor implements MethodInterceptor {

    @Override

    public Object invoke(MethodInvocation invocation) throws Throwable {

        System.out.println("before call " + invocation.getMethod().getName());

        Object retVal = invocation.proceed();

        System.out.println("after call:");

        return retVal;

    }

}

import org.springframework.cglib.proxy.MethodInterceptor;

public class SpringAopMethodInterceptor implements MethodInterceptor {

    @Override

    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {

        System.out.println("Before invoke " + method); 

        Object result = proxy.invokeSuper(obj, args); 

        System.out.println("After invoke" + method); 

        return result; 

    }

}

AfterReturningAdvice,MethodBeforeAdvice

public class MyAdvice implements AfterReturningAdvice,MethodBeforeAdvice,MethodInterceptor  {

    @Override

    public Object invoke(MethodInvocation invocation) throws Throwable {

       System.out.println("before");

         Object obj = invocation.proceed();

         System.out.println("after");

         return obj;

    }

    @Override

    public void before(Method method, Object[] args, Object target) throws Throwable {

       System.out.println("我在程序运行之前出现");

    }

 

    @Override

    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {

       System.out.println("我在程序运行之后出现");

    }

}

CGLIB原理:通过底层字节码增强技术动态创建代理类

(CtNewMethod,CtMethod,CtClass,ClassPool)

JdkRegexpMethodPointcut:正则匹配动态代理  

<bean id="userManager" class="com.whl.beans.UserManagerImpl"></bean>

    <bean id="userCheck" class="com.whl.beans.UserCheck"></bean>

    <bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">

      <property name="target">

         <ref bean="userManager"/>

      </property>

      <property name="interceptorNames"><!-- 拦截器就是通知者(包含advice+pointcut) -->

        <list>

          <value>advisor1</value>

        </list>

      </property>

    </bean>

    <bean id="advisor1" class="org.springframework.aop.support.DefaultPointcutAdvisor">

      <property name="pointcut" ref="jdkRegexPointcut"/><!-- 切入点正则匹配方法 -->

      <property name="advice" ref="userCheck"/>

       <!-- advice通知器(必须实现MethodBeforeAdvice或者AfterReturningAdvice或者MethodInterceptor) -->

    </bean>

    <bean id="jdkRegexPointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut">

      <property name="patterns">

      <list>

        <value>.*add.*</value><!-- .代表占位符 -->

        <value>.*del.*</value>

      </list>

      </property>

    </bean>

Advisor 包括 pointcut切入点 advice通知

扫描注解事务拦截@Transactional

    <tx:annotation-driven transaction-manager="transactionManager"/>

    <context:component-scan base-package="com.xxx.service,com.yyy.service" />

事务Transaction:
默认情况下运行异常才会回滚,包括继承RunTimeException类,普通异常不会回滚
 前缀强制回滚前缀指定提交(这允许即使抛出unchecked异常时也可以提交事务)
事务属性中的readOnly标志表示对应的事务应该被最优化为只读事务。这是一个最优化提示。在一些情况下,一些事务策略能够起到显著的最优化效果,例如在使用Object/Relational映射工具(如:HibernateTopLink)时避免dirty checking(试图刷新

常用使用ProxyFactoryBean 和TransactionInterceptor

<!-- 配置事务管理(必须传入sessionFactory,管理事务) -->

   <bean id="transactionManagerclass="org.springframework.orm.hibernate3.HibernateTransactionManager">

    <property name="sessionFactory">

      <ref bean="sessionFactory"/>

    </property>

   </bean>

  <!--定义拦截器 -->

  <bean id="transactionInterceptorclass="org.springframework.transaction.interceptor.TransactionInterceptor">

    <property name="transactionManager">

      <ref bean="transactionManager"/>

    </property>

    <property name="transactionAttributes">

     <props>

      <prop key="add*">PROPAGATION_REQUIRED</prop>

      <prop key="del*">PROPAGATION_REQUIRED</prop>

     </props>

    </property>

  </bean>

   <!-- 定义目标对象的事务代理对象-->

   <bean id="baseServiceProxyclass="org.springframework.aop.framework.ProxyFactoryBean">

     <property name="interceptorNames">

      <list>

       <idref bean="transactionInterceptor"/>

      </list>

     </property>

   </bean>

   <bean id="userManager" parent="baseServiceProxy">

     <!-- 代理接口 -->

     <property name="proxyInterfaces">

      <value>com.whl.user.manager.UserManager</value>

     </property>

     <!-- 代理目标对象 -->

     <property name="target">

      <ref bean=" userManagerBean"/>

     </property>

  </bean>

<!-- 定义目标对象 -->

   <bean id="userManagerBeanclass="com.whl.user.manager.UserManagerImpl" autowire="byName"></bean>

 事务传播类型:

Required:有则加入,没有开启新事务

Supports:有则加入,没有非事务

Mandatory:有则加入,没有抛异常

Requires_new:总是开启一个新事务,如果已经存在则挂起

Not_supported:总是非事务执行,挂起任务存在事务

Never:总是非事务执行,存在事务抛异常

Nested:如果存在,则嵌套事务,如果没有则

举例:

PROPAGATION_REQUIRED(默认)

ServiceA.methodA或者在ServiceB.methodB内的任何地方出现异常,事务都会被回滚,因为在一个事务中的。即使ServiceB.methodB的事务已经被 提交,但是ServiceA.methodA在接下来fail要回滚,ServiceB.methodB也要回滚。

PROPAGATION_REQUIRES_NEW(存在于同一事务,任何地方错误都一清回滚):

因为是两个事务:如果ServiceB.methodB已经提交,那么ServiceA.methodA失败回滚,ServiceB.methodB是不会回滚的。如果ServiceB.methodB失败回滚, 如果他抛出的异常被ServiceA.methodA捕获(系统就不会捕获ServiceA异常,因为异常在ServiceA中已经被拦截),ServiceA.methodA事务仍然可能提交。而如果ServiceA也不捕获,继续上抛。系统会认为ServiceA也抛出异常,所以都要回滚。

PROPAGATION_NESTED(子事务依赖于父事务,但父事务不依赖于子事务,父回滚子必回滚,子回滚父不必回滚)
PROPAGATION_REQUIRES_NEW的区别是,PROPAGATION_REQUIRES_NEW另起一个事务,将会与他的父事务相互独立,而Nested的事务和他的父事务是相依的,他的提交是要等和他的父事务一块提交的。也就是说,如果父事务最后回滚,他也要回滚的。而如果子事务回滚可以返回到父SavePoint点,选择另外分支执行。

/** 
事务属性配置为 PROPAGATION_REQUIRED 
*/ 
void methodA({ 
try { 
//savepoint 
ServiceB.methodB(); //PROPAGATION_NESTED 级别 
} catch (SomeException) { 
// 执行其他业务, 如 ServiceC.methodC(); 
} 
} 
} 

也就是说ServiceB.methodB失败回滚,那么ServiceA.methodA也会回滚到savepoint点上,ServiceA.methodA可以选择另外一个分支,比如ServiceC.methodC,继续执行,来尝试完成自己的事务。

 事务隔离级别ISOLATION:

ISOLATION_DEFAULT:默认数据库隔离级别

ISOLATION_READ_UNCOMMITTED:事务最低级别,允许其它事务看到未提交事务数据,产生脏读,不可重读,幻读

ISOLATION_READ_COMMITTED:保证事务只能看到其它事务提交后数据,避免脏读

ISOLATION_REPEATABLE_READ:对相同字段的多次读取的结果是一致的,除非数据被当前事务本身改变。可防止脏读和不可重复读,但幻读仍可发生

ISOLATION_SERIALIZABLE: 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行

可以重复读:对当前字段,同一事务多次读取结果相同除非本身事务修改

幻读:     是对增加或减少记录,如当前事务正在读,其它事务插入一条,当前到就增加一条记录称为幻读



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值