Fork me on GitHub

tiny-spring-Aop 分析笔记(1)

tinySpring Aop 分析笔记(1)

项目学习地址:code4craft/tiny-spring

step-7-method-interceptor-by-jdk-dynamic-proxy

step 7 针对有接口的情况,采用 jdk 动态代理的方式实现 AOP。

另一种情况是:无接口时,创建子类,然后进行增强(调用父类的方法),实现动态代理的实现。即 cglib 动态代理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// JdkDynamicAopProxyTest.java

public void testInterceptor() throws Exception {
// --------- helloWorldService with AOP
// 1. 设置被代理对象(Joinpoint)
AdvisedSupport advisedSupport = new AdvisedSupport();
TargetSource targetSource = new TargetSource(helloWorldService, HelloWorldService.class);
advisedSupport.setTargetSource(targetSource);

// 2. 设置拦截器(Advice)
TimerInterceptor timerInterceptor = new TimerInterceptor();
advisedSupport.setMethodInterceptor(timerInterceptor);

// 3. 创建代理(Proxy)
JdkDynamicAopProxy jdkDynamicAopProxy = new JdkDynamicAopProxy(advisedSupport);
HelloWorldService helloWorldServiceProxy = (HelloWorldService) jdkDynamicAopProxy.getProxy();

// 4. 基于AOP的调用
helloWorldServiceProxy.helloWorld();

}

Joinpoint:被代理的对象,其实是指代码的横向插入点。

  1. 首先拿到TargetSource,然后拿到TimerInterceptor,设置到AdvisedSupport的成员属性中。

    • 其中的TargetSource是指被代理的对象,即等待增强功能的那个类(本文指 helloWorldService.java)。
    • 其中的TimerInterceptor代码如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    	public class TimerInterceptor implements MethodInterceptor {

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
    long time = System.nanoTime();
    System.out.println("Invocation of Method " + invocation.getMethod().getName() + " start!");
    Object proceed = invocation.proceed();
    System.out.println("Invocation of Method " + invocation.getMethod().getName() + " end! takes " + (System.nanoTime() - time)
    + " nanoseconds.");
    return proceed;
    }
    }
    • 在 invocation 执行前后分别往 console 输出一句话,而且计算时间差。
  2. 将上面拿到的advisedSupport设置到JdkDynamicAopProxy中,然后通过getProxy()的方法,获取代理。

    • 其中的getProxy()的方法会直接调用newProxyInstance()方法(见以下代码)。 方法中分别传入:① 类加载器;② 需要实现的接口数组;③ InvocationHandler接口。newProxyInstance()方法做了两件事情:
      1. 调用getProxyClass()方法,创建代理类cl(此时 cl 中仅有:$Proxy1 这一个 Class),并不是 HelloWorldService 这个类的代理。实现了 interfaces 的接口,同时继承了 Proxy 类,见以下代码:

        1
        Class<?> cl = getProxyClass0(loader, intfs);
      2. 实例化代理类。在构造方法中将JdkDynamicAopProxy类(这才是 HelloWorldService 这个类的代理)传入代理类中,

        1
        Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] { advised.getTargetSource().getTargetClass() }, this);

说明:

  1. 这个代理的逻辑是:

    1. 包装实现类;
      • HelloWorldService包装起来。
    2. 添加自定义逻辑;
      • 配置拦截器TimerInterceptor,设置前置代码和后置代码。
      • 将拦截器设置到代理类中。
    3. 在使用的时候,用代理类来生成实例。
      • 即由JdkDynamicAopProxy来执行方法(比如.helloWorld()方法)。
  2. 当执行.helloWorld()方法时,TimerInterceptor.invoke()方法会被触发(本代码中无论什么切点,都会执行此方法),然后将相关参数传入ReflectiveMethodInvocation()中,

    1
    2
    3
    4
    5
    6
    @Override
    public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
    MethodInterceptor methodInterceptor = advised.getMethodInterceptor();
    return methodInterceptor.invoke(new ReflectiveMethodInvocation(advised.getTargetSource().getTarget(), method,
    args));
    }
-------------The End-------------