前面章节讲解过Spring AOP的基本使用和实践,本章以实现AOP事务作为示例,看看如何快速实现一个非常简单的支持事务的Advice实现。
自定义事务注解
只需要将该自定义事务注解注释到需要事务的方法上即可。
package examples;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CustomTransaction {
}
定义Aspect
package examples;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class SystemArchitecture {
@Pointcut("execution(public * *(..))")
public void anyPublicOperation() {}
@Pointcut("@annotation(examples.CustomTransaction) && anyPublicOperation()")
public void anyMethodUsingTransaction() {}
@Around("anyMethodUsingTransaction()")
public void commit(ProceedingJoinPoint pjp) throws Throwable {
try {
pjp.proceed();
doCommit();
} catch (Throwable throwable) {
doRollBack();
throw throwable;
}
}
private void doCommit() {
System.out.println("commit executed.");
}
private void doRollBack() {
System.out.println("rollback executed.");
}
}
使用了@Around类型的Advice,它支持在切点周围任意的点插入操作,示例代码commit方法描述了事务控制过程。anyMethodUsingTransaction()代表切入点,切入点是所有的公共方法且该公共方法上是使用examples.CustomTransaction注解的。
定义需要使用事务的服务
使用@CustomTransaction注解到需要事务的方法上。下面给出两个示例:MyCommitService 代表方法执行成功,事务正常提交;MyRollbackService 代表方法执行失败,事务回滚。
package examples;
import org.springframework.stereotype.Component;
@Component
public class MyCommitService {
@CustomTransaction
public void writeToDatabase() {
System.out.println("write data to database...");
}
}
package examples;
import org.springframework.stereotype.Component;
@Component
public class MyRollbackService {
@CustomTransaction
public void writeToDatabase() {
System.out.println("write data to database...");
throw new RuntimeException("unknown exception happened!");
}
}
AppConfig定义
package examples;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@ComponentScan(basePackages = "examples")
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class AppConfig {
}
入口点函数
package examples;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Application {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
MyCommitService myCommitService = context.getBean("myCommitService", MyCommitService.class);
myCommitService.writeToDatabase();
MyRollbackService myRollbackService = context.getBean("myRollbackService", MyRollbackService.class);
myRollbackService.writeToDatabase();
}
}
执行结果,myCommitService成功提交了事务,myRollbackService由于方法执行抛出异常,导致事务执行回滚操作。
write data to database...
commit executed.
write data to database...
rollback executed.
Exception in thread "main" java.lang.RuntimeException: unknown exception happened!
at examples.MyRollbackService.writeToDatabase(MyRollbackService.java:10)
at examples.MyRollbackService$$FastClassBySpringCGLIB$$a9e09160.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:749)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:56)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:88)
at examples.SystemArchitecture.commit(SystemArchitecture.java:22)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:644)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:633)
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:175)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
at examples.MyRollbackService$$EnhancerBySpringCGLIB$$c1a15ae7.writeToDatabase(<generated>)
at examples.Application.main(Application.java:21)
Spring AOP背后实现方式是jdk代理和cglib代理,网上资料很多,有兴趣可以自行查找。