写点什么

Spring AOP 源码分析——创建代理对象,绝对干货

作者:Java高工P7
  • 2021 年 11 月 10 日
  • 本文字数:3679 字

    阅读完需:约 12 分钟

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);


}


}


测试结果如下:



如上,从测试结果中。我们可以看出,我们的代理逻辑正常执行了。另外,注意一下 userService 指向对象的类型,并非是 xyz.coolblog.proxy.UserServiceImpl,而是 com.sun.proxy.$Proxy4。


关于 JDK 动态代理,这里先说这么多。下一节,我来演示一下 CGLIB 动态代理,继续往下看吧。

2.2.2 基于 CGLIB 的动态代理

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


本节的演示环节,打算调侃(无贬低之意)一下59式坦克,这是我们国家大量装备过的一款坦克。59 式坦克有很多种改款,一般把改款统称为59改,59 改这个梗也正是源于此。下面我们先来一览59式坦克的风采:



下面我们的工作就是为咱们的 59 创建一个代理,即 59 改。好了,开始我们的魔改吧。


目标类,59 式坦克:


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();


}


}


测试结果如下:



如上,"极速前行中...." 和 "轰...轰...轰...轰..." 这两行字符串是目标对象中的方法打印出来的,其他的则是由代理逻辑打印的。由此可知,我们的代理逻辑生效了。


好了,最后我们来看一下,经过魔改后的 59,也就是超音速59改的效果图:



本节用 59 式坦克举例,仅是调侃,并无恶意。作为年轻的一代,我们应感谢那些为国防事业做出贡献的科技人员们。没有他们贡献,我们怕是不会有像今天这样安全的环境了(尽管不完美)。


到此,背景知识就介绍完了。下一章,我将开始分析源码。源码不是很长,主逻辑比较容易懂,所以一起往下看吧。


3.源码分析




为目标 bean 创建代理对象前,需要先创建 AopProxy 对象,然后再调用该对象的 getProxy 方法创建实际的代理类。我们先来看看 AopProxy 这个接口的定义,如下:


public interface AopProxy {


/** 创建代理对象 */


Object getProxy();


Object getProxy(ClassLoader classLoader);


}


在 Spring 中,有两个类实现了 AopProxy,如下:



Spring 在为目标 bean 创建代理的过程中,要根据 bean 是否实现接口,以及一些其他配置来决定使用 AopProxy 何种实现类为目标 bean 创建代理对象。下面我们就来看一下代理创建的过程,如下:


protected Object createProxy(


Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {


if (this.beanFactory instanceof ConfigurableListableBeanFactory)


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


{


AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);


}


ProxyFactory proxyFactory = new ProxyFactory();


proxyFactory.copyFrom(this);


/*


  • 默认配置下,或用户显式配置 proxy-target-class = "false" 时,

  • 这里的 proxyFactory.isProxyTargetClass() 也为 false


*/


if (!proxyFactory.isProxyTargetClass()) {


if (shouldProxyTargetClass(beanClass, beanName)) {


proxyFactory.setProxyTargetClass(true);


}


else {


/*


  • 检测 beanClass 是否实现了接口,若未实现,则将

  • proxyFactory 的成员变量 proxyTargetClass 设为 true


*/


evaluateProxyInterfaces(beanClass, proxyFactory);


}


}


// specificInterceptors 中若包含有 Advice,此处将 Advice 转为 Advisor


Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);


proxyFactory.addAdvisors(advisors);


proxyFactory.setTargetSource(targetSource);


customizeProxyFactory(proxyFactory);


proxyFactory.setFrozen(this.freezeProxy);


if (advisorsPreFiltered()) {


proxyFactory.setPreFiltered(true);


}


// 创建代理


return proxyFactory.getProxy(getProxyClassLoader());


}


public Object getProxy(ClassLoader classLoader) {


// 先创建 AopProxy 实现类对象,然后再调用 getProxy 为目标 bean 创建代理对象


return createAopProxy().getProxy(classLoader);


}


getProxy 这里有两个方法调用,一个是调用 createAopProxy 创建 AopProxy 实现类对象,然后再调用 AopProxy 实现类对象中的 getProxy 创建代理对象。这里我们先来看一下创建 AopProxy 实现类对象的过程,如下:


protected final synchronized AopProxy createAopProxy() {


if (!this.active) {


activate();


}


return getAopProxyFactory().createAopProxy(this);


}


public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {


@Override


public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {


/*


  • 下面的三个条件简单分析一下:

  • 条件 1:config.isOptimize() - 是否需要优化,这个属性没怎么用过,

  • 条件 2:config.isProxyTargetClass() - 检测 proxyTargetClass 的值,

  • 条件 3:hasNoUserSuppliedProxyInterfaces(config)


*/


if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {


Class<?> targetClass = config.getTargetClass();


if (targetClass == null) {


throw new AopConfigException("TargetSource cannot determine target class: " +


"Either an interface or a target is required for proxy creation.");


}


if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {


return new JdkDynamicAopProxy(config);


}


// 创建 CGLIB 代理,ObjenesisCglibAopProxy 继承自 CglibAopProxy


return new ObjenesisCglibAopProxy(config);


}


else {


// 创建 JDK 动态代理


return new JdkDynamicAopProxy(config);


}


}


}


如上,DefaultAopProxyFactory 根据一些条件决定生成什么类型的 AopProxy 实现类对象。生成好 AopProxy 实现类对象后,下面就要为目标 bean 创建代理对象了。这里以 JdkDynamicAopProxy 为例,我们来看一下,该类的 getProxy 方法的逻辑是怎样的。如下:


public Object getProxy() {


return getProxy(ClassUtils.getDefaultClassLoader());


}


public Object getProxy(ClassLoader classLoader) {

用户头像

Java高工P7

关注

还未添加个人签名 2021.11.08 加入

还未添加个人简介

评论

发布
暂无评论
Spring AOP 源码分析——创建代理对象,绝对干货