白话Spring源码(十一):Spring AOP源码分析-创建代理对象

上篇博客:白话Spring源码(十):Spring AOP源码分析-筛选合适的通知器分析了 Spring 是如何为目标 bean 筛选合适的通知器的。现在通知器选好了,接下来就要通过代理的方式将通知器(Advisor)所持有的通知(Advice)织入到 bean 的某些方法前后。

织入到 bean的原理是动态代理。那我们先了解一下动态代理:

动态代理

动态代理有两种实现方法:jdk动态代理,CGLIB 动态代理。

1.基于 JDK 的动态代理

下面我来演示一下 JDK 动态代理的使用方式,如下:

目标类定义:

public interface UserService {

    void save(User user);

    void update(User user);
}

public class UserServiceImpl implements UserService {

    @Override
    public void save(User user) {
        System.out.println("save user info");
    }

    @Override
    public void update(User user) {
        System.out.println("update user info");
    }
}

代理创建者定义:

public interface ProxyCreator {

    Object getProxy();
}

public class JdkProxyCreator implements ProxyCreator, InvocationHandler {

    private Object target;

    public JdkProxyCreator(Object target) {
        assert target != null;
        Class<?>[] interfaces = target.getClass().getInterfaces();
        if (interfaces.length == 0) {
            throw new IllegalArgumentException("target class don`t implement any interface");
        }
        this.target = target;
    }

    @Override
    public Object getProxy() {
        Class<?> clazz = target.getClass();
        // 生成代理对象
        return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        System.out.println(System.currentTimeMillis() + " - " + method.getName() + " method start");
        // 调用目标方法
        Object retVal = method.invoke(target, args);
        System.out.println(System.currentTimeMillis() + " - " + method.getName() + " method over");

        return retVal;
    }
}

如上,invoke 方法中的代理逻辑主要用于记录目标方法的调用时间,和结束时间。下面写点测试代码简单验证一下,如下:

public class JdkProxyCreatorTest {

    @Test
    public void getProxy() throws Exception {
        ProxyCreator proxyCreator = new JdkProxyCreator(new UserServiceImpl());
        UserService userService = (UserService) proxyCreator.getProxy();
        
        System.out.println("proxy type = " + userService.getClass());
        System.out.println();
        userService.save(null);
        System.out.println();
        userService.update(null);
    }
}

关于 JDK 动态代理,这里先说这么多。我们来看一下 CGLIB 动态代理。

2.基于 CGLIB 的动态代理

当我们要为未实现接口的类生成代理时,就无法使用 JDK 动态代理了。那么此类的目标对象生成代理时应该怎么办呢?当然是使用 CGLIB 了。在 CGLIB 中,代理逻辑是封装在 MethodInterceptor 实现类中的,代理对象则是通过 Enhancer 类的 create 方法进行创建。下面我来演示一下CGLIB 创建代理对象的过程,如下:

目标类:

public class Tank59 {

    void run() {
        System.out.println("极速前行中....");
    }

    void shoot() {
        System.out.println("轰...轰...轰...轰...");
    }
}

CGLIB 代理创建者

public class CglibProxyCreator implements ProxyCreator {

    private Object target;

    private MethodInterceptor methodInterceptor;

    public CglibProxyCreator(Object target, MethodInterceptor methodInterceptor) {
        assert (target != null && methodInterceptor != null);
        this.target = target;
        this.methodInterceptor = methodInterceptor;
    }

    @Override
    public Object getProxy() {
        Enhancer enhancer = new Enhancer();
        // 设置代理类的父类
        enhancer.setSuperclass(target.getClass());
        // 设置代理逻辑
        enhancer.setCallback(methodInterceptor);
        // 创建代理对象
        return enhancer.create();
    }
}

方法拦截器 - 坦克再制造:

public class TankRemanufacture implements MethodInterceptor {

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        if (method.getName().equals("run")) {
            System.out.println("正在重造59坦克...");
            System.out.println("重造成功,已获取 ✨59改 之 超音速飞行版✨");
            System.out.print("已起飞,正在突破音障。");

            methodProxy.invokeSuper(o, objects);

            System.out.println("已击落黑鸟 SR-71,正在返航...");
            return null;
        }

        return methodProxy.invokeSuper(o, objects);
    }
}

好了,下面开始演示,测试代码如下:

public class CglibProxyCreatorTest {

    @Test
    public void getProxy() throws Exception {
        ProxyCreator proxyCreator = new CglibProxyCreator(new Tank59(), new TankRemanufacture());
        Tank59 tank59 = (Tank59) proxyCreator.getProxy();
        
        System.out.println("proxy class = " + tank59.getClass() + "\n");
        tank59.run();
        System.out.println();
        System.out.print("射击测试:");
        tank59.shoot();
    }
}

好了,动态代理简单介绍到这里。那Spring AOP怎么选择哪种方式呢?

这里用到了工厂模式,我们来看一下源码:

AopProxy:获取代理接口

public interface AopProxy {
	/**
	 * Creates a new Proxy object for the given object, proxying
	 * the given interface. Uses the thread context class loader.
	 */
	public abstract Object getProxy();
	/**
	 * Creates a new Proxy object for the given object, proxying
	 * the given interface. Uses the given class loader.
	 */
	public abstract Object getProxy(ClassLoader cl);
}

AopProxy实现类:有两个实现方式JDK动态代理和CGLIB代理,所以有两个实现类:

这两个实现类现在先不展开,后面详细介绍。

AopProxyFactory:工厂接口

public interface AopProxyFactory {
	
	/**
	 * Return an AopProxy for the given AdvisedSupport object
	 * @param advisedSupport AOP configuration
	 * @return an AOP proxy
	 * @throws AopConfigException if the configuration is invalid
	 */
	AopProxy createAopProxy(AdvisedSupport advisedSupport) throws AopConfigException;

}

DefaultAopProxyFactory:工厂实现类:

public class DefaultAopProxyFactory implements AopProxyFactory {

	/**
	 * @see org.springframework.aop.framework.AopProxyFactory#createAopProxy(org.springframework.aop.framework.AdvisedSupport)
	 */
	public AopProxy createAopProxy(AdvisedSupport advisedSupport) throws AopConfigException {
		boolean useCglib = advisedSupport.getOptimize() || advisedSupport.getProxyTargetClass() || advisedSupport.getProxiedInterfaces().length == 0;
		if (useCglib) {
			return CglibProxyFactory.createCglibProxy(advisedSupport);
		}
		else {
			// Depends on whether we have expose proxy or frozen or static ts
			return new JdkDynamicAopProxy(advisedSupport);
		}
	}
	
	/**
	 * Inner class to just introduce a CGLIB dependency
	 * when actually creating a CGLIB proxy.
	 */
	private static class CglibProxyFactory {

		private static AopProxy createCglibProxy(AdvisedSupport advisedSupport) {
			return new Cglib2AopProxy(advisedSupport);
		}
	}

}

DefaultAopProxyFactory 根据一些条件决定生成什么类型的 AopProxy 实现类对象。

好了,关于创建代理的源码分析,就先说到这里吧。

猜你喜欢

转载自blog.csdn.net/haoxin963/article/details/89294956