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 里的属性 targetSourceinterfaces ,因为设置了 interfaces ,所以会选择 JDK 动态代理

ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(defaultEchoService);

如果以这种方式初始化,因为没有设置 interfaces ,选择代理时,会选择 CGLIB 动态代理

设置通知信息

proxyFactory.addAdvice(new EchoServiceMethodInterceptor());

作用:设置 AdvisedSupport 里的属性 advisorsadvisorArray

关键代码:org.springframework.aop.framework.AdvisedSupport#addAdvice(int, org.aopalliance.aop.Advice)

  • 判断 Advice 的具体类型,此处判断了 IntroductionInfoDynamicIntroductionAdvice
  • 添加 Advice 对应的 Advisor
    • Advice 类型为 IntroductionInfoIntroductionAdvisor,添加 DefaultIntroductionAdvisor
      • IntroductionInfo 不是 Advice 的子接口,这里应该是判断是否为 IntroductionAdvisor
    • 类型为 DynamicIntroductionAdvice ,抛出异常
    • 否则,添加 DefaultPointcutAdvisor
      • 设置 pointcutPointcut.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 获取 interceptorListinterceptorList 里的对象类型可能是 InterceptorInterceptorAndDynamicMethodMatcher

  • advisor 类型为 PointcutAdvisor
    • 使用 PointcutAdvisor 里的 Pointcut 内部的 ClassFilterMethodMatcher 判断
      • 校验 Class 和 Method
      • 判断 MethodMatcher#isRuntime ,如果为 true ,添加 InterceptorAndDynamicMethodMatcher
        • InterceptorAndDynamicMethodMatcher 中包含 MethodInterceptorMethodMatcher
  • 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 对象作为入参传入了 MethodInterceptorMethodInterceptorinvoke 方法再调用 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(); 方法分为静态 StaticMethodMatcherDynamicMethodMatcher ,这里面共有三个 matches 方法,要注意根据入参进行区分。

以 JDK 动态代理 org.springframework.aop.framework.JdkDynamicAopProxy#invoke 方法实现来看,可以将代理执行方法分为两步:

  1. 获取拦截器链

    List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
    
  2. 执行拦截器链

    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 的作用

  • ProxyFactoryBeanProxyFactory 与 Spring IOC 结合的产物
  • ProxyFactoryBeanProxyFactory 都继承 ProxyCreatorSupportAdvisedSupportProxyConfig 父类,都实现了 Advised 接口
  • ProxyFactoryBean 额外实现了 FactoryBean<Object>BeanClassLoaderAwareBeanFactoryAware 接口,其中后两个接口与 Spring Bean 生命周期相关
  • ProxyFactoryBean 同时配置了 targetNametargetSource 时,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 相当于 PointcutAdvice 的结合体。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") 时不会触发前置通知
  • 执行时被包装成 DeclareParentsAdvisorDelegatePerTargetObjectIntroductionInterceptor

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 的内部是 AspectJMethodBeforeAdviceAspectJExpressionPointcut

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 ,所以有自动创建代理的功能
posted @ 2021-09-30 18:07  流星<。)#)))≦  阅读(74)  评论(0编辑  收藏  举报