实现SpringAOP

一、动态代理模式简单理解:

动态代理生成一个对象的代理,这个代理对象拥有和原对象的所有属性和行为,而且还多出另外功能。举个例子:现在有一个对象A1,A1有个方法test(),用动态代理生成对等代理对象A2,A2可以像A1调用test()方法,但是A2会在调用过程插入一些额外的操作。

二、动态代理(JDK)

  • 代理对象接口和实现类,下面代码中的TestService和TestServiceImpl
  • 代理类,下面代码中的ProxyUtils,需要实现InvocationHandle,实现invoke()方法
  • 客户端使用ProxyUtils生成TestService代理对象,调用方法,代码中的test()方法

三、代码实现(推荐在本地跑下,加深理解)

代码实现过程中加入了对SpringAOP的解析,加入了Interceptor拦截器,在代理对象生成类中invoke()方法中实现SpringAOP中的@Before、@After、@AfterReturning、@AfterThrowing注解

  1. 代理对象接口和实现类TestService和TestServiceImpl
public interface TestService {
    public void test();
}


public class TestServiceImpl implements TestService {
    @Override
    public void test() {
        System.out.println("测试开始#############");
    }
}
  1. 代理类ProxyUtils,需要实现InvocationHandle,实现invoke()方法
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 生成代理对象工具类
 * @param <T>
 */
public class ProxyUtils<T> implements InvocationHandler {

    private TestService testService;

    private Interceptor interceptor;

    /**
     * 生成代理对象
     *
     * @param testService
     * @param interceptor
     * @return
     */
    public Object getProxy (TestService testService, Interceptor interceptor) {

        this.testService = testService;
        this.interceptor = interceptor;

        ClassLoader testServiceClassLoader = testService.getClass().getClassLoader();

        Class[] testServiceInterfaces = testService.getClass().getInterfaces();

        return Proxy.newProxyInstance(testServiceClassLoader, testServiceInterfaces, this);
    }


    /**
     * 执行真实方法步骤:
     * 1、先执行before方法
     * 2、通过method.invoker执行test()方法
     * 3、如果执行test()成功,执行afterReturning方法;否则执行afterThrowing方法
     * 4、最终执行after方法
     *
     * @param proxy
     * @param method
     * @param args
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //标记是否出现异常
        boolean error = false;

        interceptor.before();      //实现SpringAOP中的Before()方法

        try{
            method.invoke(args);
        }
        catch (Exception e) {
            error = true;
            e.printStackTrace();
        }
        finally {
            interceptor.after(); 			//实现SpringAOP中的After()方法

        }

        if (error){
            interceptor.afterThrowing();			//实现SpringAOP中的AfterThrowing()方法

        }
        else {
            interceptor.afterReturning();				//实现SpringAOP中的AfterReturning()方法

        }

        return null;
    }
}
  1. 客户端使用ProxyUtils生成TestService代理对象,调用方法,代码中的test()方法
/**
 * 动态代理测试客户端
 */
public class Client {
    public static void main(String[] args) {

        TestService testService = new TestServiceImpl();

        Interceptor interceptor = new TestServiceInterceptor();

        ProxyUtils proxyUtils = new ProxyUtils();

        TestService proxy = (TestService) proxyUtils.getProxy(testService, interceptor);

        System.out.println("proxy = " + proxy.getClass().getName());
        proxy.test();
    }
}

四、源码解析

代理对象生成类中两大关键点:

Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h);

生成代理对象的过程如下:

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h);
 {
        Objects.requireNonNull(h);

        final Class<?> caller = System.getSecurityManager() == null
                                    ? null
                                    : Reflection.getCallerClass();

        /*
         * Look up or generate the designated proxy class and its constructor.
         */
        Constructor<?> cons = getProxyConstructor(caller, loader, interfaces);

        return newProxyInstance(caller, cons, h);
    }

说明:上述代码其实是使用反射机制ClassLoader获取对象的Constructor,然后使用Constructor生成类的对象,对等下面的代码:

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h);
 {
        Constructor constructor = testServiceClassLoader.getClass().getConstructor(param);
        return constructor.newInstance();
    }

返回的代理对象proxy实现了newProxyInstance方法中的参数interfaces接口,并且proxy封装了其他行为,感兴趣的同学可以看看$Proxy0类的实现,当我们执行proxy.test()方法时,首先会经过 $Proxy0调用InvocationHandle中的invoke()方法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章