文章目录
前言
从前面几章我们不难看出 Aspect(切面) = PointCut(切入点)+ Advice(增强)。所谓的增强也就是在被增强的方法的前后执行特定的逻辑。对应的类被代理了。如下图所示:
仔细看一下上图,会发现增强的对象里面包含有advisors
和advisorArray
这样的信息。那这些都是什么信息呢?恰巧在Spring AOP中,存在这样的一个接口org.springframework.aop.Advisor
。这个接口就包含有两个方法:
public interface Advisor {
Advice getAdvice();
boolean isPerInstance();
}
从第一个方法不难看出,这个一个提供Advice
增强的的接口。然后再看看这个接口的两个子接口
尤其是org.springframework.aop.PointcutAdvisor
,是不是有点想法了?PointcutAdvisor = Pointcut + Advice,这是不是就和Aspect一模一样了?本文就通过使用Advisor
的方式来达到之前Aspect
所达到的效果。
An advisor is like a small self-contained aspect that has a single piece of advice. The advice itself is represented by a bean, and must implement one of the advice interfaces。
Base interface holding AOP advice (action to take at a joinpoint) and a filter determining the applicability of the advice (such as a pointcut). This interface is not for use by Spring users, but to allow for commonality in support for different types of advice.
Spring AOP is based around around advice delivered via method interception, compliant with the AOP Alliance interception API. The Advisor interface allows support for different types of advice, such as before and after advice, which need not be implemented using interception.
自定义Advisor
package com.example.aop.anno.aspects;
import org.aopalliance.aop.Advice;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.Pointcut;
import org.springframework.aop.PointcutAdvisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.Arrays;
@Component
public class BeforePointcutAdvisor implements PointcutAdvisor {
@Override
public Pointcut getPointcut() {
AspectJExpressionPointcut aspectJExpressionPointcut = new AspectJExpressionPointcut();
aspectJExpressionPointcut.setExpression("execution(public * *(..)) && within(com.example.aop.anno.service..*)");
return aspectJExpressionPointcut;
}
@Override
public Advice getAdvice() {
return new MethodBeforeAdvice() {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("------------方法 " + method.getName() + " 增强逻辑-----------");
System.out.println("target = " + target);
System.out.println("args = " + Arrays.toString(args));
}
};
}
@Override
public boolean isPerInstance() {
return false;
}
}
运行结果如下
"C:\Program Files\Java\jdk1.8.0_92\bin\java.exe" "-javaagent:D:\Program Files\JetBrains\IntelliJ IDEA 2019.3.1\lib\idea_rt.jar=12142:D:\Program Files\JetBrains\IntelliJ IDEA 2019.3.1\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_92\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_92\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_92\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_92\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_92\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_92\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_92\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_92\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_92\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_92\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_92\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_92\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_92\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_92\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_92\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_92\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_92\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_92\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_92\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_92\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_92\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_92\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_92\jre\lib\rt.jar;D:\springboot\gs-managing-transactions-master\complete\target\classes;D:\maven\repo\org\springframework\spring-core\4.3.27.RELEASE\spring-core-4.3.27.RELEASE.jar;D:\maven\repo\commons-logging\commons-logging\1.2\commons-logging-1.2.jar;D:\maven\repo\org\springframework\spring-tx\4.3.27.RELEASE\spring-tx-4.3.27.RELEASE.jar;D:\maven\repo\org\springframework\spring-beans\4.3.27.RELEASE\spring-beans-4.3.27.RELEASE.jar;D:\maven\repo\org\springframework\spring-context-support\4.3.27.RELEASE\spring-context-support-4.3.27.RELEASE.jar;D:\maven\repo\org\springframework\spring-context\4.3.27.RELEASE\spring-context-4.3.27.RELEASE.jar;D:\maven\repo\org\springframework\spring-expression\4.3.27.RELEASE\spring-expression-4.3.27.RELEASE.jar;D:\maven\repo\org\springframework\spring-aop\4.3.27.RELEASE\spring-aop-4.3.27.RELEASE.jar;D:\maven\repo\org\springframework\spring-aspects\4.3.27.RELEASE\spring-aspects-4.3.27.RELEASE.jar;D:\maven\repo\org\aspectj\aspectjweaver\1.8.9\aspectjweaver-1.8.9.jar" com.example.aop.anno.SpringStartMain
九月 15, 2020 11:39:22 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@20ad9418: startup date [Tue Sep 15 23:39:22 CST 2020]; root of context hierarchy
------------方法 add 增强逻辑-----------
target = com.example.aop.anno.service.impl.DealServiceImpl@36902638
args = [Order{orderId=1600184364312, name='HuaWei', price=5998.00}, User{name='Lisa', age=18}]
九月 15, 2020 11:39:24 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext doClose
信息: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@20ad9418: startup date [Tue Sep 15 23:39:22 CST 2020]; root of context hierarchy
Process finished with exit code 0
不难看出,与前面通过Aspect定义的结果没什么差别。
还可以采用以下的方式
package com.example.aop.anno.aspects;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.Pointcut;
import org.springframework.aop.PointcutAdvisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.StaticMethodMatcherPointcut;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.Arrays;
@Component
public class BeforePointcutAdvisor implements PointcutAdvisor {
@Override
public Pointcut getPointcut() {
return new StaticMethodMatcherPointcut() {
@Override
public boolean matches(Method method, Class<?> targetClass) {
Class<?>[] interfaces = targetClass.getInterfaces();
for (Class<?> anInterface : interfaces) {
if (anInterface.getName().startsWith("com.example.aop.anno.service")) {
return true;
}
}
return false;
}
};
}
@Override
public Advice getAdvice() {
return new MethodInterceptor() {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("------------方法 " + invocation.getMethod().getName() + " 增强逻辑-----------");
System.out.println("this = " + invocation.getThis());
System.out.println("args = " + Arrays.toString(invocation.getArguments()));
return invocation.proceed();
}
};
}
@Override
public boolean isPerInstance() {
return false;
}
}
结果如下
"C:\Program Files\Java\jdk1.8.0_92\bin\java.exe" "-javaagent:D:\Program Files\JetBrains\IntelliJ IDEA 2019.3.1\lib\idea_rt.jar=12282:D:\Program Files\JetBrains\IntelliJ IDEA 2019.3.1\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_92\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_92\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_92\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_92\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_92\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_92\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_92\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_92\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_92\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_92\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_92\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_92\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_92\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_92\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_92\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_92\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_92\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_92\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_92\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_92\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_92\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_92\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_92\jre\lib\rt.jar;D:\springboot\gs-managing-transactions-master\complete\target\classes;D:\maven\repo\org\springframework\spring-core\4.3.27.RELEASE\spring-core-4.3.27.RELEASE.jar;D:\maven\repo\commons-logging\commons-logging\1.2\commons-logging-1.2.jar;D:\maven\repo\org\springframework\spring-tx\4.3.27.RELEASE\spring-tx-4.3.27.RELEASE.jar;D:\maven\repo\org\springframework\spring-beans\4.3.27.RELEASE\spring-beans-4.3.27.RELEASE.jar;D:\maven\repo\org\springframework\spring-context-support\4.3.27.RELEASE\spring-context-support-4.3.27.RELEASE.jar;D:\maven\repo\org\springframework\spring-context\4.3.27.RELEASE\spring-context-4.3.27.RELEASE.jar;D:\maven\repo\org\springframework\spring-expression\4.3.27.RELEASE\spring-expression-4.3.27.RELEASE.jar;D:\maven\repo\org\springframework\spring-aop\4.3.27.RELEASE\spring-aop-4.3.27.RELEASE.jar;D:\maven\repo\org\springframework\spring-aspects\4.3.27.RELEASE\spring-aspects-4.3.27.RELEASE.jar;D:\maven\repo\org\aspectj\aspectjweaver\1.8.9\aspectjweaver-1.8.9.jar" com.example.aop.anno.SpringStartMain
九月 15, 2020 11:51:55 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@20ad9418: startup date [Tue Sep 15 23:51:55 CST 2020]; root of context hierarchy
------------方法 add 增强逻辑-----------
this = com.example.aop.anno.service.impl.DealServiceImpl@3b2cf7ab
args = [Order{orderId=1600185117718, name='HuaWei', price=5998.00}, User{name='Lisa', age=18}]
九月 15, 2020 11:51:57 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext doClose
信息: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@20ad9418: startup date [Tue Sep 15 23:51:55 CST 2020]; root of context hierarchy
Process finished with exit code 0
总结
Advisor属于Spring AOP的范畴,是对AspectJ的补充。也同样可以充分利用AspectJ的切点表达式。有一点需要注意下,就是Aspect类中可以定义多个Advice,而Advisor真能包含一个。