上篇博客:白话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 实现类对象。
好了,关于创建代理的源码分析,就先说到这里吧。