• 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 ,所以有自动创建代理的功能
  • 相关阅读:
    Ultra-wideband (UWB) secure wireless device pairing and associated systems
    程序员常用工具整理
    Net 使用UEditor笔记
    社交中的黄金法则,你要细细体会品味
    社交中的黄金法则,你要细细体会品味
    社交中的黄金法则,你要细细体会品味
    交际中你所不知道的说话的12个技巧!
    交际中你所不知道的说话的12个技巧!
    交际中你所不知道的说话的12个技巧!
    好好的活,简简单单过!
  • 原文地址:https://www.cnblogs.com/huangwenjie/p/15357826.html
Copyright © 2020-2023  润新知