先聊下Spring AOP的背景。如果说有一件事情在一个100人的团队中每个人都需要完成,将这一百人中的每个人都看做一个对象,是不是需要重复100遍。映射到Java应用来说代码冗余性何其之高,届时代码的重用性与复用性显得尤为重要。更有甚者,这一百个人的团队中,不是所有人都需要完成这件事情,比如只有其中的男生需要完成,如何处理?又或者这件事情跟自己平时的日常工作范畴并无联系,团队中的男生能不能只需要专注自己平时的工作内容?为此,Spring AOP应运而生。
先介绍几个概念。一件事情,无非分为几个要素,这件事情是什么,这件事情i什么时候做,这件事情哪些地方要做。AOP当中,通知Advice就是扮演这件事情是什么以及什么时候做这个角色。切点就是扮演这件事情哪些地方要做这个角色。切面就是包含通知与切点。其中,通知又包含前置通知,后置通知,环绕通知。顾名思义,就是在事情完成的前后分别完成不同的事件。那么,刚才讲到切点就是定义这件事情在哪些地方要做,这个哪些地方能不能通过一个Expresion表达式定义好,相当于是一个规则,只要是符合我这个规则的表达式就去完成这件事情,文初的男生是不是恰好就是一个规则?很多同事不理解动态代理里面的代理对象到底是什么,AOP当中这件事情的完成对象就是代理对象来完成,其实只要是符合切点表达式的对象就是代理对象。
关于Spring AOP 的具体应用,基于Aspect注解方式会简便直观很多。下文将附上基于@Aspect注解方式的应用场景。
@Aspect
@Configuration
public class TestAdviceConfig {
private static final String AOP_POINTCUT_EXPRESSION = "execution(* *..service..*Service.*(..))";
@Autowired
private PlatformTransactionManager transactionManager;
@Bean
public MethodTraceAdvice traceAdvice() {
return new MethodTraceAdvice();
}
@Bean
public DaoSQLTraceAdvice sqltraceAdvice() {
return new DaoSQLTraceAdvice();
}
@Bean
public Advisor traceAdviceAdvisor() {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(AOP_POINTCUT_EXPRESSION);
return new DefaultPointcutAdvisor(pointcut, traceAdvice());
}
@Bean
public TransactionInterceptor txAdvice() {
DefaultTransactionAttribute txAttr_REQUIRED = new DefaultTransactionAttribute();
txAttr_REQUIRED.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
DefaultTransactionAttribute txAttr_REQUIRED_READONLY = new DefaultTransactionAttribute();
txAttr_REQUIRED_READONLY.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
txAttr_REQUIRED_READONLY.setReadOnly(true);
NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
source.addTransactionalMethod("get*", txAttr_REQUIRED_READONLY);
source.addTransactionalMethod("query*", txAttr_REQUIRED_READONLY);
source.addTransactionalMethod("find*", txAttr_REQUIRED_READONLY);
source.addTransactionalMethod("list*", txAttr_REQUIRED_READONLY);
source.addTransactionalMethod("count*", txAttr_REQUIRED_READONLY);
source.addTransactionalMethod("is*", txAttr_REQUIRED_READONLY);
source.addTransactionalMethod("*", txAttr_REQUIRED);
return new TransactionInterceptor(transactionManager, source);
}
@Bean
public Advisor txAdviceAdvisor() {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(AOP_POINTCUT_EXPRESSION);
return new DefaultPointcutAdvisor(pointcut, txAdvice());
}
}