Spring AOP实现主要过程

本文针对的是icomac-spring项目,是自己重现了tianxiaono的仿写toy-spring项目,最开始的版本是黄亿华前辈实现的 tiny-spring ,该项目时间节点是 2014.1

具体参考:自己动手实现的 Spring IOC 和 AOP - 下篇

AOP 原理

AOP 是基于动态代理模式实现的,具体实现上可以基于 JDK 动态代理或者 Cglib 动态代理。其中 JDK 动态代理只能代理实现了接口的对象,而 Cglib 动态代理则无此限制。所以在为没有实现接口的对象生成代理时,只能使用 Cglib。在 icomac-spring 项目中,暂时只实现了基于 JDK 动态代理的代理对象生成器。

关于 AOP 原理这里就不多说了,下面说说 icomac-spring 中 AOP 的实现步骤。还是像上面一样,先列流程:

  1. AOP 逻辑介入 BeanFactory 实例化 bean 的过程
  2. 根据 Pointcut 定义的匹配规则,判断当前正在实例化的 bean 是否符合规则
  3. 如果符合,代理生成器将切面逻辑 Advice 织入 bean 相关方法中,并为目标 bean 生成代理对象
  4. 将生成的 bean 的代理对象返回给 BeanFactory 容器,到此,AOP 逻辑执行结束

对于上面的4步流程,熟悉 Spring AOP 的朋友应该能很容易理解。如果有朋友不理解也没关系,在后续章节,我会详细介绍相关流程的具体实现。

基于 JDK 动态代理的 AOP 实现

本节说说基于 JDK 动态代理的代理对象生成器具体实现。在 icomac-spring 项目中,代理对象生成器的逻辑主要写在了 JdkDynamicAopProxy 类中,这个类的有两个方法,其中 getProxy 方法用于生成代理对象。invoke 方法是 InvocationHandler 接口的具体实现,包含了将通知(Advice)织入相关方法中,是上面所列流程中第3步流程的具体实现。

JdkDynamicAopProxy 实现代码:

package com.icomac.spring.aop;

import org.aopalliance.intercept.MethodInterceptor;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 基于 JDK 动态代理的代理对象生成器
 * Created by icomac on 19/4/10.
 */
final public class JdkDynamicAopProxy extends AbstractAopProxy implements InvocationHandler {

    public JdkDynamicAopProxy(AdvisedSupport advised) {
        super(advised);
    }

    /**
     * 为目标 bean 生成代理对象
     *
     * @return bean 的代理对象
     */
    @Override
    public Object getProxy() {
        return Proxy.newProxyInstance(getClass().getClassLoader(), 
        								advised.getTargetSource().getInterfaces(), this);
    }

    /**
     * InvocationHandler 接口中的 invoke 方法具体实现,封装了具体的代理逻辑
     *
     * @param proxy
     * @param method
     * @param args
     * @return 代理方法或原方法的返回值
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        MethodMatcher methodMatcher = advised.getMethodMatcher();

        // 使用方法匹配器 methodMatcher 测试 bean 中原始方法 method 是否符合匹配规则
        if (methodMatcher != null && methodMatcher.matchers(method, 
        											advised.getTargetSource().getTargetClass())) {

            // 获取 Advice。MethodInterceptor 的父接口继承了 Advice
            MethodInterceptor methodInterceptor = advised.getMethodInterceptor();

            // 将 bean 的原始 method 封装成 MethodInvocation 实现类对象,
            // 将生成的对象传给 Adivce 实现类对象,执行通知逻辑
            return methodInterceptor.invoke(
                    new ReflectiveMethodInvocation(advised.getTargetSource().getTarget(), method, args));
        } else {
            // 当前 method 不符合匹配规则,直接调用 bean 中的原始 method
            return method.invoke(advised.getTargetSource().getTarget(), args);
        }
    }
}

下面用个流程图对通知织入逻辑进行总结:

AOP 通知织入流程图

最后对 JdkDynamicAopProxy 进行简单的测试,测试代码及结果如下

测试类

package com.icomac.spring.aop;

import com.icomac.spring.HelloService;
import com.icomac.spring.HelloServiceImpl;
import com.icomac.spring.aop.AdvisedSupport;
import com.icomac.spring.aop.JdkDynamicAopProxy;
import com.icomac.spring.aop.TargetSource;

import org.junit.Test;

import java.lang.reflect.Method;

/**
 * 对JdkDynamicAopProxy进行测试
 * Created by icomac on 19/4/10.
 */
public class JdkDynamicAopProxyTest {

    @Test
    public void getProxy() throws Exception {
        System.out.println("---------- no proxy ----------");	//无代理
        HelloService helloService = new HelloServiceImpl();		//目标对象实例化
        helloService.sayHelloWorld();

        System.out.println("\n----------- proxy -----------");	//启动代理
        AdvisedSupport advisedSupport = new AdvisedSupport();	//实例化advisedSupport(集合目标对象以及方法拦截器和匹配法则)
        advisedSupport.setMethodInterceptor(new LogInterceptor());	//添加方法拦截器,相当于织入执行通知
        //目标资源类(这集合了目标对象以及类和接口)实例化
        TargetSource targetSource = new TargetSource(
                helloService, HelloServiceImpl.class, HelloServiceImpl.class.getInterfaces());
        advisedSupport.setTargetSource(targetSource);	//添加目标对象
        advisedSupport.setMethodMatcher((Method method, Class beanClass) -> true);	//添加匹配法则
        //advisedSupport获得代理,并生成代理对象helloService
        helloService = (HelloService) new JdkDynamicAopProxy(advisedSupport).getProxy();
        helloService.sayHelloWorld();
    }
}

测试结果

猜你喜欢

转载自blog.csdn.net/sinat_33801679/article/details/89196545
今日推荐