20210931 Spring AOP 学习
ProxyFactory
测试程序代码
public interface EchoService {
String echo(String message) throws NullPointerException;
default String echoTwice(String message) {
return "echoTwice :: " + message;
}
}
public class DefaultEchoService implements EchoService {
@Override
public String echo(String message) {
return "[ECHO] " + message;
}
}
public class EchoServiceMethodInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Method method = invocation.getMethod();
System.out.println("拦截 EchoService 的方法:" + method);
return invocation.proceed();
}
}
public class SecondEchoServiceMethodInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Method method = invocation.getMethod();
System.out.println("Second 拦截 EchoService 的方法:" + method);
return invocation.proceed();
}
}
public class ProxyFactoryDemo {
public static void main(String[] args) {
DefaultEchoService defaultEchoService = new DefaultEchoService();
// 注入目标对象(被代理)
ProxyFactory proxyFactory = new ProxyFactory(defaultEchoService);
// ProxyFactory proxyFactory = new ProxyFactory();
// proxyFactory.setTarget(defaultEchoService);
// 添加 Advice 实现 MethodInterceptor < Interceptor < Advice
proxyFactory.addAdvice(new EchoServiceMethodInterceptor());
proxyFactory.addAdvice(new SecondEchoServiceMethodInterceptor());
// 获取代理对象
EchoService echoService = (EchoService) proxyFactory.getProxy();
String echo = echoService.echo("Hello,World");
System.out.println(echo);
}
}
代码解析
设置代理目标源
ProxyFactory proxyFactory = new ProxyFactory(defaultEchoService);
ProxyFactory
继承了 AdvisedSupport
继承了 ProxyConfig
,内部包含了代理相关的一些配置,例如 target
。
使用 ProxyFactory
的构造器初始化时:
public ProxyFactory(Object target) {
setTarget(target);
setInterfaces(ClassUtils.getAllInterfaces(target));
}
会设置 AdvisedSupport
里的属性 targetSource
和 interfaces
,因为设置了 interfaces
,所以会选择 JDK 动态代理
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(defaultEchoService);
如果以这种方式初始化,因为没有设置 interfaces
,选择代理时,会选择 CGLIB 动态代理
设置通知信息
proxyFactory.addAdvice(new EchoServiceMethodInterceptor());
作用:设置 AdvisedSupport
里的属性 advisors
和 advisorArray
关键代码:org.springframework.aop.framework.AdvisedSupport#addAdvice(int, org.aopalliance.aop.Advice)
- 判断
Advice
的具体类型,此处判断了IntroductionInfo
和DynamicIntroductionAdvice
- 添加
Advice
对应的Advisor
Advice
类型为IntroductionInfo
,IntroductionAdvisor
,添加DefaultIntroductionAdvisor
IntroductionInfo
不是Advice
的子接口,这里应该是判断是否为IntroductionAdvisor
- 类型为
DynamicIntroductionAdvice
,抛出异常 - 否则,添加
DefaultPointcutAdvisor
- 设置
pointcut
为Pointcut.TRUE
- 设置传入的
advice
- 设置
获取代理对象
EchoService echoService = (EchoService) proxyFactory.getProxy();
org.springframework.aop.framework.ProxyFactory#getProxy()
public Object getProxy() {
return createAopProxy().getProxy();
}
org.springframework.aop.framework.ProxyCreatorSupport#createAopProxy
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}
org.springframework.aop.framework.DefaultAopProxyFactory#createAopProxy
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
执行代理对象调用
String echo = echoService.echo("Hello,World");
org.springframework.aop.framework.JdkDynamicAopProxy#invoke
构建拦截器链
target = targetSource.getTarget();
通过 targetSource
获取 target
,这里可以选择不同 TargetSource
对象
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
获取调用链
org.springframework.aop.framework.AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice
org.springframework.aop.framework.DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice
(重要)
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
public DefaultAdvisorAdapterRegistry() {
registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
registerAdvisorAdapter(new AfterReturningAdviceAdapter());
registerAdvisorAdapter(new ThrowsAdviceAdapter());
}
org.springframework.aop.framework.adapter.DefaultAdvisorAdapterRegistry#getInterceptors
@Override
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
List<MethodInterceptor> interceptors = new ArrayList<>(3);
Advice advice = advisor.getAdvice();
if (advice instanceof MethodInterceptor) {
interceptors.add((MethodInterceptor) advice);
}
for (AdvisorAdapter adapter : this.adapters) {
if (adapter.supportsAdvice(advice)) {
interceptors.add(adapter.getInterceptor(advisor));
}
}
if (interceptors.isEmpty()) {
throw new UnknownAdviceTypeException(advisor.getAdvice());
}
return interceptors.toArray(new MethodInterceptor[0]);
}
这里的 AdvisorAdapterRegistry
会根据 Advisor
获取对应的 Interceptor
- 如果
Advisor
里的advice
类型为MethodInterceptor
,添加 ``MethodInterceptor - 如果是以下三种,返回对应的
Interceptor
MethodBeforeAdvice
-MethodBeforeAdviceInterceptor
AfterReturningAdvice
-AfterReturningAdviceInterceptor
ThrowsAdvice
-ThrowsAdviceInterceptor
for (Advisor advisor : advisors) {
...
}
遍历 AdvisedSupport
里的属性 advisors
,根据 advisors
获取 interceptorList
,interceptorList
里的对象类型可能是 Interceptor
或 InterceptorAndDynamicMethodMatcher
advisor
类型为PointcutAdvisor
- 使用
PointcutAdvisor
里的Pointcut
内部的ClassFilter
和MethodMatcher
判断- 校验 Class 和 Method
- 判断
MethodMatcher#isRuntime
,如果为true
,添加InterceptorAndDynamicMethodMatcher
InterceptorAndDynamicMethodMatcher
中包含MethodInterceptor
和MethodMatcher
- 使用
advisor
类型为IntroductionAdvisor
- 其他
- 添加
Interceptor
- 添加
执行调用
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
retVal = invocation.proceed();
内部是递归调用
org.springframework.aop.framework.ReflectiveMethodInvocation#proceed
- 这里区分
InterceptorAndDynamicMethodMatcher
和 其他 - 如果是
InterceptorAndDynamicMethodMatcher
,会再进行一次校验,校验方法参数,如果校验为true
,再执行调用
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
MethodInterceptor
实现内部需要调用 invocation.proceed();
,例如:
public Object invoke(MethodInvocation invocation) throws Throwable {
Method method = invocation.getMethod();
System.out.println("拦截 EchoService 的方法:" + method);
return invocation.proceed();
}
方法 proceed
里将 MethodInvocation
对象作为入参传入了 MethodInterceptor
,MethodInterceptor
的 invoke
方法再调用 proceed
方法,实际就是递归调用,终止递归的判断在 proceed
方法内:
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
这里是通过反射调用连接点方法
动态验证方法参数
public class MyDynamicMethodMatcherPointcut extends DynamicMethodMatcherPointcut {
@Override
public boolean matches(Method method, Class<?> targetClass, Object... args) {
if (Objects.equals("hwj", args[0])) {
return true;
}
return false;
}
}
public class DynamicProxyFactoryDemo {
public static void main(String[] args) {
DefaultEchoService defaultEchoService = new DefaultEchoService();
// 注入目标对象(被代理)
ProxyFactory proxyFactory = new ProxyFactory(defaultEchoService);
// 添加 Advisor
proxyFactory.addAdvisor(new DefaultPointcutAdvisor(new MyDynamicMethodMatcherPointcut(), new EchoServiceMethodInterceptor()));
// 获取代理对象
EchoService echoService = (EchoService) proxyFactory.getProxy();
String echo = echoService.echo("hwj");
System.out.println(echo);
}
}
重点关注:
addAdvisor
方法,手动添加Advisor
addAdvice
方法内部执行时,添加的是DefaultPointcutAdvisor
,使用的是默认的Pointcut.TRUE
,所有判断都返回true
,不会做任何拦截- 构建执行器链时,执行器链中的对象类型是 ``InterceptorAndDynamicMethodMatcher
- 执行调用时,会调用
MyDynamicMethodMatcherPointcut#matches
方法,可以验证方法、目标源类型、方法参数
Pointcut
的判断方法
public interface Pointcut {
ClassFilter getClassFilter();
MethodMatcher getMethodMatcher();
}
public interface ClassFilter {
boolean matches(Class<?> clazz);
}
public interface MethodMatcher {
boolean matches(Method method, Class<?> targetClass);
boolean isRuntime();
boolean matches(Method method, Class<?> targetClass, Object... args);
}
Pointcut
作为判断条件来判断是否为连接点使用通知,判断分为两种,一种是 ClassFilter
,一种是 MethodMatcher
,其中 MethodMatcher
又根据 boolean isRuntime();
方法分为静态 StaticMethodMatcher
和 DynamicMethodMatcher
,这里面共有三个 matches
方法,要注意根据入参进行区分。
以 JDK 动态代理 org.springframework.aop.framework.JdkDynamicAopProxy#invoke
方法实现来看,可以将代理执行方法分为两步:
-
获取拦截器链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
-
执行拦截器链
MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); // Proceed to the joinpoint through the interceptor chain. retVal = invocation.proceed();
其中只有第一个和第二个 matches
方法在第一步中执行,在第一步中,如果 boolean isRuntime();
返回 true
,执行链中会增加一个 InterceptorAndDynamicMethodMatcher
包装对象,并在第二步中执行第三个 matches
方法,在其中可以判断方法执行时的入参。
事件机制
public class AdvisorListenerDemo {
public static void main(String[] args) {
DefaultEchoService defaultEchoService = new DefaultEchoService();
// 注入目标对象(被代理)
ProxyFactory proxyFactory = new ProxyFactory(defaultEchoService);
proxyFactory.addListener(new AdvisedSupportListener() {
@Override
public void activated(AdvisedSupport advised) {
System.out.println("activated :: " + advised);
}
@Override
public void adviceChanged(AdvisedSupport advised) {
System.out.println("adviceChanged :: " + advised);
}
});
// ProxyFactory proxyFactory = new ProxyFactory();
// proxyFactory.setTarget(defaultEchoService);
// 添加 Advice 实现 MethodInterceptor < Interceptor < Advice
EchoServiceMethodInterceptor echoServiceMethodInterceptor = new EchoServiceMethodInterceptor();
proxyFactory.addAdvice(echoServiceMethodInterceptor);
proxyFactory.addAdvice(new SecondEchoServiceMethodInterceptor());
// 获取代理对象
// 创建代理后,开始激活监听器,并触发 activated 事件
EchoService echoService = (EchoService) proxyFactory.getProxy();
// 触发 adviceChanged 事件
proxyFactory.removeAdvice(echoServiceMethodInterceptor);
// 触发 adviceChanged 事件
proxyFactory.addAdvice(echoServiceMethodInterceptor);
String echo = echoService.echo("Hello,World");
System.out.println(echo);
}
}
- 创建代理后,开始激活监听器,并触发
activated
事件 - 添加、去除
Advisor
会触发adviceChanged
事件
ProxyFactoryBean
测试程序代码
<?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 id="echoService" class="study.my.aop.service.DefaultEchoService"/>
<bean id="myEchoService" class="study.my.aop.service.MyEchoService"/>
<bean id="echoServiceMethodInterceptor"
class="study.my.aop.advice.interceptor.EchoServiceMethodInterceptor"/>
<bean id="targetSource" class="org.springframework.aop.target.HotSwappableTargetSource">
<constructor-arg ref="echoService"/>
</bean>
<bean id="echoServiceProxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- <property name="targetName" value="echoService"/>-->
<property name="interceptorNames">
<value>echoServiceMethodInterceptor</value>
</property>
<property name="targetSource" ref="targetSource"/>
</bean>
</beans>
public class MyEchoService implements EchoService {
@Override
public String echo(String message) {
return "[My Echo] " + message;
}
}
public class ProxyFactoryBeanDemo {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:my-aop.xml");
EchoService echoService = context.getBean("echoServiceProxyFactoryBean", EchoService.class);
System.out.println(echoService.echo("Hello,World"));
HotSwappableTargetSource targetSource = context.getBean("targetSource", HotSwappableTargetSource.class);
targetSource.swap(context.getBean("myEchoService", EchoService.class));
System.out.println(echoService.echo("Hello,World"));
context.close();
}
}
代码解析
ProxyFactoryBean
的作用
ProxyFactoryBean
是ProxyFactory
与 Spring IOC 结合的产物ProxyFactoryBean
是ProxyFactory
都继承ProxyCreatorSupport
、AdvisedSupport
、ProxyConfig
父类,都实现了Advised
接口ProxyFactoryBean
额外实现了FactoryBean<Object>
、BeanClassLoaderAware
、BeanFactoryAware
接口,其中后两个接口与 Spring Bean 生命周期相关ProxyFactoryBean
同时配置了targetName
和targetSource
时,targetSource
无效,使用SingletonTargetSource
包装目标类- 通过测试程序,可以看出使用
TargetSource
包装目标类的好处,动态代理执行时,通过target = targetSource.getTarget();
获取目标类,中间可以进行一些操作,例如案例中的替换目标类
AspectJProxyFactory
测试程序代码
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class AspectBeforeAnnoConfig {
public AspectBeforeAnnoConfig() {
System.out.println("AspectBeforeAnnoConfig ...");
}
@Pointcut("execution(public * *(..))") // 匹配 Join Point
private void anyPublicMethod() { // 方法名即 Pointcut 名
System.out.println("@Pointcut at any public method.");
}
@Pointcut("execution(public String study.my.aop.service.EchoService.echo(..))") // 匹配 Join Point
private void echoMethod() { // 方法名即 Pointcut 名
System.out.println("@Pointcut at echo method.");
}
@Before("echoMethod()")
public void beforeMethod() {
System.out.println("AspectBeforeAnnoConfig beforeMethod ...");
}
}
import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;
import study.my.aop.aspect.AspectBeforeAnnoConfig;
import study.my.aop.service.DefaultEchoService;
import study.my.aop.service.EchoService;
public class AspectJProxyFactoryDemo {
public static void main(String[] args) {
DefaultEchoService defaultEchoService = new DefaultEchoService();
// 创建 Proxy 工厂(AspectJ)
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(defaultEchoService);
// 增加 Aspect 配置类
proxyFactory.addAspect(AspectBeforeAnnoConfig.class);
// 获取代理对象
EchoService echoService = proxyFactory.getProxy();
System.out.println(echoService.echo("Hello,World"));
System.out.println(echoService.echoTwice("Hello,World"));
}
}
代码解析
Aspect
Aspect
相当于 Pointcut
和 Advice
的结合体。AspectJ 表达式被转化为 AspectJExpressionPointcut
,内部的增强方法被转化为 AspectJMethodBeforeAdvice
Advisor 链
链中包含两个 Advisor :
org.springframework.aop.interceptor.ExposeInvocationInterceptor
addAspect
时调用了AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(advisors);
添加
org.springframework.aop.aspectj.AspectJPointcutAdvisor
- 内部调用 Aspect 定义的增强方法
IntroductionAdvisor
与 ProxyFactory
组合使用
测试程序代码
public interface WriteService {
String write(String content);
}
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.IntroductionInfo;
import org.springframework.aop.IntroductionInterceptor;
import study.my.aop.service.WriteService;
import java.lang.reflect.Method;
public class IntroductionMethodInterceptor implements IntroductionInterceptor, IntroductionInfo, WriteService {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Method method = invocation.getMethod();
System.out.println("IntroductionMethodInterceptor 拦截方法:" + method);
//当前方法的声明类是否实现了需要拓展功能的接口
if (implementsInterface(invocation.getMethod().getDeclaringClass())) {
//调用this的此方法
return invocation.getMethod().invoke(this, invocation.getArguments());
}
return invocation.proceed();
}
@Override
public boolean implementsInterface(Class<?> intf) {
Class<?>[] interfaces = this.getInterfaces();
for (Class clazz : interfaces) {
if (intf.isInterface() && intf.isAssignableFrom(clazz)) {
return true;
}
}
return false;
}
@Override
public Class<?>[] getInterfaces() {
return new Class[]{WriteService.class};
}
@Override
public String write(String content) {
return "IntroductionMethodInterceptor write ... " + content;
}
}
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultIntroductionAdvisor;
import study.my.aop.advice.interceptor.IntroductionMethodInterceptor;
import study.my.aop.service.DefaultEchoService;
import study.my.aop.service.EchoService;
import study.my.aop.service.WriteService;
public class IntroductionAdvisorDemo {
public static void main(String[] args) {
DefaultEchoService defaultEchoService = new DefaultEchoService();
// 注入目标对象(被代理)
ProxyFactory proxyFactory = new ProxyFactory(defaultEchoService);
// 添加 Advice 实现 MethodInterceptor < Interceptor < Advice
DefaultIntroductionAdvisor defaultIntroductionAdvisor = new DefaultIntroductionAdvisor(new IntroductionMethodInterceptor());
proxyFactory.addAdvisor(defaultIntroductionAdvisor);
// 获取代理对象
EchoService echoService = (EchoService) proxyFactory.getProxy();
String echo = echoService.echo("Hello,World");
System.out.println(echo);
WriteService writeService = (WriteService) echoService;
String hello = writeService.write("Hello");
System.out.println(hello);
}
}
代码解析
- 代码中代理的是
DefaultEchoService
,为代理本身增加了实现的接口WriteService
,实际实现WriteService
的功能代码在IntroductionMethodInterceptor
中 DefaultIntroductionAdvisor
内部的advice
就是自定义的IntroductionMethodInterceptor
,这个advice
的定义实际就是MethodInterceptor
,增强类型类似于 Around 通知
与 AspectJProxyFactory
组合使用
测试程序代码
public class DefaultWriteService implements WriteService {
@Override
public String write(String content) {
return "write :: " + content;
}
}
@Aspect
public class AspectIntroductionAnnoConfig {
//"+"表示person的所有子类;defaultImpl 表示默认需要添加的新的类
// @DeclareParents(value = "study.my.aop.service.EchoService+",defaultImpl = DefaultWriteService.class)
@DeclareParents(value = "study.my.aop.service.DefaultEchoService", defaultImpl = DefaultWriteService.class)
private WriteService writeService;
public AspectIntroductionAnnoConfig() {
System.out.println("AspectBeforeAnnoConfig ...");
}
@Pointcut("execution(public * *(..))") // 匹配 Join Point
private void anyPublicMethod() { // 方法名即 Pointcut 名
System.out.println("@Pointcut at any public method.");
}
@Pointcut("execution(public String study.my.aop.service.EchoService.echo(..))") // 匹配 Join Point
private void echoMethod() { // 方法名即 Pointcut 名
System.out.println("@Pointcut at echo method.");
}
@Before("echoMethod()")
public void beforeMethod() {
System.out.println("AspectBeforeAnnoConfig beforeMethod ...");
}
}
import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;
import study.my.aop.aspect.AspectIntroductionAnnoConfig;
import study.my.aop.service.DefaultEchoService;
import study.my.aop.service.EchoService;
import study.my.aop.service.WriteService;
public class AspectJIntroductionDemo {
public static void main(String[] args) {
DefaultEchoService defaultEchoService = new DefaultEchoService();
// 创建 Proxy 工厂(AspectJ)
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(defaultEchoService);
// 增加 Aspect 配置类
proxyFactory.addAspect(AspectIntroductionAnnoConfig.class);
// 获取代理对象
EchoService echoService = proxyFactory.getProxy();
System.out.println(echoService.echo("Hello,World"));
WriteService writeService = (WriteService) proxyFactory.getProxy();
System.out.println(writeService.write("Hello"));
}
}
代码解析
- 调用
writeService.write("Hello")
时不会触发前置通知 - 执行时被包装成
DeclareParentsAdvisor
和DelegatePerTargetObjectIntroductionInterceptor
AspectJ XML 模式
测试程序代码
public class AspectXmlConfig {
public Object aroundAnyPublicMethod(ProceedingJoinPoint pjp) throws Throwable {
Random random = new Random();
if (random.nextBoolean()) {
throw new RuntimeException("For Purpose from XML configuration.");
}
System.out.println("@Around any public method : " + pjp.getSignature());
return pjp.proceed();
}
public void beforeAnyPublicMethod() {
System.out.println("@Before any public method.");
}
public void finalizeAnyPublicMethod() {
System.out.println("@After any public method.");
}
public void afterAnyPublicMethod() {
System.out.println("@AfterReturning any public method.");
}
public void afterThrowingAnyPublicMethod() {
System.out.println("@AfterThrowing any public method.");
}
}
<?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
">
<aop:aspectj-autoproxy/>
<bean id="aspectXmlConfig" class="study.my.aop.aspect.AspectXmlConfig"/>
<aop:config>
<aop:aspect id="AspectXmlConfig" ref="aspectXmlConfig">
<aop:pointcut id="anyPublicMethod" expression="execution(public String study.my.aop.service.EchoService.echo(..))"/>
<aop:before method="beforeAnyPublicMethod" pointcut-ref="anyPublicMethod"/>
</aop:aspect>
</aop:config>
<bean id="echoService" class="study.my.aop.service.DefaultEchoService"/>
</beans>
public class AspectAopDemo {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:my-aop-aspect.xml");
EchoService echoService = context.getBean("echoService", EchoService.class);
System.out.println(echoService.echo("Hello,World"));
context.close();
}
}
代码解析
代理包装
后置处理器 org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator
的生命周期方法 postProcessAfterInitialization
会将对象包装为代理对象,内部使用的仍然是 ProxyFactory
判断对象是否需要代理
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary
方法里的以下代码会判断是否为容器内的对象包装代理
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
判断的依据:是否为基础架构对象、表达式是否判断符合
代理对象里的 Advisor
解析以下 XML 时,向容器中添加了 org.springframework.aop.aspectj.AspectJPointcutAdvisor
对象
<aop:aspect id="AspectXmlConfig" ref="aspectXmlConfig">
参考代码:org.springframework.aop.config.ConfigBeanDefinitionParser#parseAdvice
后置处理器处理 Bean 时,添加了 org.springframework.aop.interceptor.ExposeInvocationInterceptor
参考代码: org.springframework.aop.aspectj.AspectJProxyUtils#makeAdvisorChainAspectJCapableIfNecessary
所以,容器里的代理 Bean 会有两个 Advisor
AspectJPointcutAdvisor
AspectJPointcutAdvisor
的内部是 AspectJMethodBeforeAdvice
和 AspectJExpressionPointcut
AspectJ 注解模式
测试程序代码
@EnableAspectJAutoProxy
@Configuration
public class AspectAopConfig {
@Bean
public MyBean myBean() {
return new MyBean();
}
@Bean
public DefaultEchoService echoService() {
return new DefaultEchoService();
}
@Bean
public AspectBeforeAnnoConfig aspectBeforeAnnoConfig() {
return new AspectBeforeAnnoConfig();
}
}
@Aspect
public class AspectBeforeAnnoConfig {
public AspectBeforeAnnoConfig() {
System.out.println("AspectBeforeAnnoConfig ...");
}
@Pointcut("execution(public * *(..))") // 匹配 Join Point
private void anyPublicMethod() { // 方法名即 Pointcut 名
System.out.println("@Pointcut at any public method.");
}
@Pointcut("execution(public String study.my.aop.service.EchoService.echo(..))") // 匹配 Join Point
private void echoMethod() { // 方法名即 Pointcut 名
System.out.println("@Pointcut at echo method.");
}
@Before("echoMethod()")
public void beforeMethod() {
System.out.println("AspectBeforeAnnoConfig beforeMethod ...");
}
}
public class AspectAopAnnoDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AspectAopConfig.class);
EchoService echoService = context.getBean("echoService", EchoService.class);
System.out.println(echoService.echo("Hello,World"));
context.close();
}
}
DefaultAdvisorAutoProxyCreator
测试程序代码
<?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 id="echoService" class="study.my.aop.service.DefaultEchoService"/>
<bean id="echoServiceMethodInterceptor" class="study.my.aop.advice.interceptor.EchoServiceMethodInterceptor"/>
<!-- PointcutAdvisor Bean -->
<bean class="org.springframework.aop.support.DefaultPointcutAdvisor">
<constructor-arg ref="echoServiceMethodInterceptor"/>
</bean>
<!-- AutoProxy Bean -->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
</beans>
public class AutoCreatorXMLDemo {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:my-aop-auto.xml");
EchoService echoService = context.getBean("echoService", EchoService.class);
System.out.println(echoService.echo("Hello,World"));
context.close();
}
}
代码解析
- Bean 初始化后置处理时,对 Bean 进行代理
- 生命周期方法:
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization
@EnableAspectJAutoProxy
引入了org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator
,所以有自动创建代理的功能