当前位置: 首页 > news >正文

MiniSpring框架学习笔记-AutoProxyCreator:如何自动添加动态代理?

MiniSpring框架学习笔记-AutoProxyCreator:如何自动添加动态代理?

  • 20. AutoProxyCreator:如何自动添加动态代理?
    • 一、先看最终配置
    • 二、为什么使用 BeanPostProcessor
    • 三、先把自动代理处理器注册进容器
    • 四、实现 BeanNameAutoProxyCreator
    • 五、容器最终保存的到底是什么
    • 六、验证自动代理
    • 七、当前教学实现的边界
    • 小结

教程:https://github.com/YaleGuo/minis
极客时间:手把手带你写一个 MiniSpring

前言:本节的主线就是将之前由写在XML里面的代理匹配模式(直接写明action类这个需要代理),改成在IOC容器创建Bean的时候通过Bean后置处理器增强(通过Bean的名字去匹配),带着这个思路去看,很容易明白。

20. AutoProxyCreator:如何自动添加动态代理?

上一节中,我们已经能用Pointcut批量匹配需要增强的方法。不过,哪个 Bean 需要代理,仍然要逐个配置:

<beanid="realaction"class="com.chenhai.test.Action1"/><beanid="action"class="com.chenhai.aop.ProxyFactoryBean"><propertytype="java.lang.Object"name="target"ref="realaction"/><propertytype="String"name="interceptorName"value="advisor"/></bean>

这种方式代理一个对象没有问题。如果Action1Action2等一批对象都要使用同一个Advisor,就得反复配置ProxyFactoryBean

本节要把“为目标对象组装ProxyFactoryBean”这件事也交给容器。我们只配置一条 Bean 名称规则,容器创建 Bean 时自动判断它是否需要代理。

一、先看最终配置

项目中的beans.xml不再为每个业务对象手写代理工厂,而是增加一个BeanNameAutoProxyCreator

<beanid="beforeAdvice"class="com.chenhai.test.MyBeforeAdvice"/><beanid="advisor"class="com.chenhai.aop.NameMatchMethodPointcutAdvisor"><propertytype="com.chenhai.aop.Advice"name="advice"ref="beforeAdvice"/><propertytype="String"name="mappedName"value="do*"/></bean><beanid="autoProxyCreator"class="com.chenhai.aop.framework.autoproxy.BeanNameAutoProxyCreator"><propertytype="String"name="pattern"value="action*"/><propertytype="String"name="interceptorName"value="advisor"/></bean><beanid="action"class="com.chenhai.test.Action1"/><beanid="action2"class="com.chenhai.test.Action2"/>

这里有两层匹配,不要混在一起:

配置匹配对象作用
pattern=action*Bean 名称决定哪些 Bean 要创建代理
mappedName=do*方法名称决定代理中的哪些方法要执行通知

因此,actionaction2都会被自动代理;调用它们的doAction()doSomething()时,又都会命中do*,先执行beforeAdvice

整个过程可以先记成下面这条主线:

ApplicationContext.refresh() ↓ 提前注册 BeanNameAutoProxyCreator ↓ 容器创建 action / action2 ↓ BeanNameAutoProxyCreator 用 action* 匹配 beanName ↓ 命中后把真实 Bean 包装成 ProxyFactoryBean ↓ getBean() 识别到 FactoryBean,调用其 getObject() ↓ ProxyFactoryBean 根据 advisor 创建 JDK 动态代理对象 ↓ 业务代码最终拿到 IAction 代理对象

二、为什么使用 BeanPostProcessor

创建一个 Bean 时,当前 MiniSpring 会依次完成这些步骤:

实例化 Bean ↓ 填充 XML 属性 ↓ 执行 Aware 回调 ↓ 初始化前处理 ↓ 执行 init-method ↓ 初始化后处理 ↓ 注册单例

BeanPostProcessor正好提供了两个可以插入通用逻辑的扩展点:

publicinterfaceBeanPostProcessor{defaultObjectpostProcessBeforeInitialization(Objectbean,StringbeanName)throwsBeansException{returnbean;}defaultObjectpostProcessAfterInitialization(Objectbean,StringbeanName)throwsBeansException{returnbean;}}

这里的post可以理解为“附加处理”,不等于只能在初始化之后处理。真正的执行时机要看实现的是postProcessBeforeInitialization(),还是postProcessAfterInitialization()

后置处理器还可以返回另一个对象。容器会沿用这个返回值继续执行后面的创建流程,并最终把它放入单例池。自动代理正是利用这一点,把普通业务 Bean 替换成包装它的ProxyFactoryBean

当前项目在createBean()中调用后置处理器的代码如下:

privateObjectcreateBean(StringbeanName,BeanDefinitionbeanDefinition)throwsBeansException{try{Class<?>beanClass=Class.forName(beanDefinition.getClassName());Objectbean=instantiateBean(beanClass,beanDefinition.getConstructorArgumentValues());if(beanDefinition.isSingleton()){this.earlySingletonObjects.put(beanName,bean);}// 先完成 XML 属性注入。populateBean(beanDefinition,beanClass,bean);// 再回调 BeanFactoryAware 等 Aware 接口。invokeAwareMethods(bean);ObjectprocessedBean=applyBeanPostProcessorsBeforeInitialization(bean,beanName);if(processedBean!=null){bean=processedBean;}invokeInitMethod(beanDefinition,bean);processedBean=applyBeanPostProcessorsAfterInitialization(bean,beanName);if(processedBean!=null){bean=processedBean;}returnbean;}catch(BeansExceptione){throwe;}catch(Exceptione){thrownewBeansException("Create bean failed: "+beanName);}}

applyBeanPostProcessorsBeforeInitialization()会按注册顺序调用所有处理器,并把前一个处理器的返回值交给下一个处理器:

publicObjectapplyBeanPostProcessorsBeforeInitialization(ObjectexistingBean,StringbeanName)throwsBeansException{Objectresult=existingBean;for(BeanPostProcessorbeanProcessor:getBeanPostProcessors()){Objectcurrent=beanProcessor.postProcessBeforeInitialization(result,beanName);if(current==null){returnresult;}result=current;}returnresult;}

当前项目先注册AutowiredAnnotationBeanPostProcessor,再注册 XML 中的自动代理处理器。因此,业务对象会先完成@Autowired字段注入,再由BeanNameAutoProxyCreator包装。

三、先把自动代理处理器注册进容器

这里有一个先后顺序问题:如果普通 Bean 已经创建完了,再注册自动代理处理器,它就没有机会处理这些 Bean。

所以ApplicationContext.refresh()必须先注册BeanPostProcessor,再通过onRefresh()预实例化普通单例:

publicvoidrefresh()throwsBeansException,IllegalStateException{this.startupDate=System.currentTimeMillis();this.closed.set(false);this.active.set(true);postProcessBeanFactory(getBeanFactory());invokeBeanFactoryPostProcessors(getBeanFactory());// 先注册 BeanPostProcessor。registerBeanPostProcessors(getBeanFactory());initApplicationEventPublisher();registerListeners();// 再预实例化非懒加载单例。onRefresh();finishRefresh();}

ClassPathXmlApplicationContext除了注册内置的自动注入处理器,还会找出 XML 中声明的所有BeanPostProcessor

@OverrideprotectedvoidregisterBeanPostProcessors(ConfigurableListableBeanFactorybeanFactory)throwsBeansException{// 内置处理器:负责 @Autowired 字段注入。beanFactory.addBeanPostProcessor(newAutowiredAnnotationBeanPostProcessor(beanFactory));// XML 中声明的处理器:本章会找到 autoProxyCreator。Map<String,BeanPostProcessor>postProcessors=beanFactory.getBeansOfType(BeanPostProcessor.class);for(BeanPostProcessorpostProcessor:postProcessors.values()){beanFactory.addBeanPostProcessor(postProcessor);}}

getBeansOfType(BeanPostProcessor.class)会先根据类型找出autoProxyCreator,创建它,再放入后置处理器列表。因为BeanNameAutoProxyCreator实现了BeanFactoryAware,创建过程中容器还会把当前BeanFactory回调给它,后面就能按名称查找advisor

四、实现 BeanNameAutoProxyCreator

BeanNameAutoProxyCreator的核心职责只有三步:

  1. 根据pattern匹配beanName
  2. 排除 AOP 基础设施对象;
  3. 为命中的业务对象组装ProxyFactoryBean

项目中的实现如下:

packagecom.chenhai.aop.framework.autoproxy;importcom.chenhai.BeansException;importcom.chenhai.aop.Advice;importcom.chenhai.aop.Advisor;importcom.chenhai.aop.AopProxyFactory;importcom.chenhai.aop.DefaultAopProxyFactory;importcom.chenhai.aop.ProxyFactoryBean;importcom.chenhai.beans.factory.BeanFactory;importcom.chenhai.beans.factory.BeanFactoryAware;importcom.chenhai.beans.factory.FactoryBean;importcom.chenhai.beans.factory.config.BeanPostProcessor;importcom.chenhai.util.PatternMatchUtils;/** * 按 Bean 名称自动创建 AOP 代理。 */publicclassBeanNameAutoProxyCreatorimplementsBeanPostProcessor,BeanFactoryAware{// 要代理的 Bean 名称模式,例如 action*。privateStringpattern;// 容器中的 Advisor 或 Advice Bean 名称。privateStringinterceptorName;privateBeanFactorybeanFactory;privateAopProxyFactoryaopProxyFactory;publicBeanNameAutoProxyCreator(){this.aopProxyFactory=newDefaultAopProxyFactory();}publicvoidsetPattern(Stringpattern){this.pattern=pattern;}publicStringgetPattern(){returnthis.pattern;}publicvoidsetInterceptorName(StringinterceptorName){this.interceptorName=interceptorName;}publicStringgetInterceptorName(){returnthis.interceptorName;}publicvoidsetAopProxyFactory(AopProxyFactoryaopProxyFactory){this.aopProxyFactory=aopProxyFactory;}@OverridepublicvoidsetBeanFactory(BeanFactorybeanFactory)throwsBeansException{this.beanFactory=beanFactory;}@OverridepublicObjectpostProcessBeforeInitialization(Objectbean,StringbeanName)throwsBeansException{if(!isMatch(beanName,this.pattern)||isInfrastructureBean(bean)){returnbean;}ProxyFactoryBeanproxyFactoryBean=newProxyFactoryBean();proxyFactoryBean.setTarget(bean);proxyFactoryBean.setBeanFactory(this.beanFactory);proxyFactoryBean.setAopProxyFactory(this.aopProxyFactory);proxyFactoryBean.setInterceptorName(this.interceptorName);returnproxyFactoryBean;}/** * Advice、Advisor、FactoryBean 等基础设施对象 * 不能再次成为自动代理目标。 */privatebooleanisInfrastructureBean(Objectbean){returnbeaninstanceofBeanPostProcessor||beaninstanceofFactoryBean||beaninstanceofAdvice||beaninstanceofAdvisor;}protectedbooleanisMatch(StringbeanName,StringmappedName){returnPatternMatchUtils.simpleMatch(mappedName,beanName);}}

beanNameactionaction2时,action*匹配成功。此时target保存原始业务对象,interceptorName保存advisor的名称,真正创建代理时再从容器取得这个Advisor

如果没有匹配,或者当前对象本身就是BeanPostProcessorFactoryBeanAdviceAdvisor,则直接返回原对象。这个判断可以避免把自动代理处理器、代理工厂和通知等基础设施再次包装。

五、容器最终保存的到底是什么

原始业务对象被自动代理处理器命中后,几个对象很容易混淆:

action 对应的单例 └─ ProxyFactoryBean ├─ target → Action1 原始对象 ├─ interceptorName → advisor └─ getObject() ↓ JDK 生成的 IAction 代理对象 ↓ 方法调用交给 JdkDynamicAopProxy ↓ Advisor → Advice + Pointcut

createBean()返回的不是 JDK 代理对象,而是自动组装出来的ProxyFactoryBeangetBean()会先把它注册到单例池,再调用getObjectForBeanInstance()

Objectbean=createBean(beanName,beanDefinition);if(beanDefinition.isSingleton()){registerSingleton(beanName,bean);this.earlySingletonObjects.remove(beanName);}returngetObjectForBeanInstance(bean,beanName);

getObjectForBeanInstance()发现它实现了FactoryBean,才会调用getObject()取得产品对象:

protectedObjectgetObjectForBeanInstance(ObjectbeanInstance,StringbeanName){if(!(beanInstanceinstanceofFactoryBean)){returnbeanInstance;}FactoryBean<?>factory=(FactoryBean<?>)beanInstance;returngetObjectFromFactoryBean(factory,beanName);}

接下来,ProxyFactoryBean.getObject()根据targetadvisor创建并缓存 JDK 代理对象:

@OverridepublicObjectgetObject(){returngetSingletonInstance();}privatesynchronizedObjectgetSingletonInstance(){if(this.singletonInstance==null){this.singletonInstance=getProxy(createAopProxy());}returnthis.singletonInstance;}

所以需要分清:

  • ProxyFactoryBean是容器内部保存的代理工厂;
  • JdkDynamicAopProxy是实现InvocationHandler的代理处理器;
  • Proxy.newProxyInstance()返回的对象,才是业务代码最终拿到的IAction代理对象。

六、验证自动代理

Action1Action2都只实现业务接口,不需要包含任何 AOP 代码:

publicclassAction2implementsIAction{@OverridepublicvoiddoAction(){System.out.println("real action2 doAction........");}@OverridepublicvoiddoSomething(){System.out.println("real action2 doSomething........");}}

测试中可以直接判断容器返回的对象是不是 JDK 动态代理:

ClassPathXmlApplicationContextcontext=newClassPathXmlApplicationContext("beans.xml");IActionaction=(IAction)context.getBean("action");IActionaction2=(IAction)context.getBean("action2");assertTrue(Proxy.isProxyClass(action.getClass()));assertTrue(Proxy.isProxyClass(action2.getClass()));action.doAction();action.doSomething();action2.doAction();action2.doSomething();

由于action*同时命中两个 Bean,do*又命中两个业务方法,所以四次调用都会先执行前置通知,再执行真实方法。项目当前的AopAdviceTest同时验证了代理类型和执行顺序。

七、当前教学实现的边界

当前版本为了把自动代理的主线讲清楚,保留了几个简化条件:

  • 只支持一个 Bean 名称模式和一个interceptorName
  • 使用 JDK 动态代理,因此目标类必须实现接口;
  • 自动代理发生在postProcessBeforeInitialization()

最后一点需要特别说明。当前Action1Action2没有配置init-method,所以先包装成ProxyFactoryBean可以正常工作。但在当前createBean()中,初始化前处理器一旦返回包装对象,后面的init-method也会对这个包装对象执行。更完整的实现通常会在初始化完成后再创建代理,并额外处理循环依赖中的早期代理引用。本节先以项目现有代码为准,不继续展开这部分生命周期细节。

小结

这一节把“逐个配置ProxyFactoryBean”改成了“按 Bean 名称自动创建代理”:

BeanNameAutoProxyCreator:决定哪些 Bean 要代理 Pointcut:决定代理中的哪些方法要增强 Advice:决定具体执行什么增强 ProxyFactoryBean:组装并创建代理对象

最关键的顺序是:先注册自动代理处理器,再创建普通 Bean。这样容器在创建actionaction2时,才能根据action*自动完成包装,业务代码仍然只需要面向IAction调用。

http://www.jsqmd.com/news/1311396/

相关文章:

  • 白转黑维生素 B 深度测评,针对白发的作用一目了然
  • 2026 年现阶段冕宁评价高的食堂订餐带刷脸就餐系统实力厂家深度解析与优选指南,打饭还在掏饭卡?这玩意儿居然让食堂省了一半找零的麻烦 - 企业官方推荐【认证】
  • 计算机文件系统核心概念:目录、文件夹与路径的深度解析与实践指南
  • Depix实测:像素化文字还原原理、部署与实战调优指南
  • 2026年7月杭州代理记账公司哪家靠谱?正规财税机构推荐榜 - 行业深度分析
  • 10平米锦鲤池用六仓还是简化过滤?2026年别再花冤枉钱了
  • 2026 没有公网 IP 也能安全回家:Tailscale 远程访问 AdGuard Home / NAS / SSH 完整指南
  • 2026年8月护坡水泥砖/混凝土水泥砖公司推荐合集_高邑县东玉墙体材料厂 - 行业平台推荐
  • 单片机毕设选题推荐:基于单片机的多按键智能温控报警系统开发 基于物联网的家用热水设备远程监测平台设计(016701)
  • 2026 年现阶段,青海评价高的燃气辐射加热器制造厂选哪家,冬天室外搭帐篷取暖,这玩意儿居然比空调省半幅电费? - 企业推荐官【认证】
  • 2026年8月pph四通管件/江苏pph管帽管件厂家厂家推荐_江苏磊霆精密新材料有限公司 - 品牌宣传支持者
  • Windows原生SSH服务器部署与配置全指南:从原理到实战
  • 显卡驱动清理终极指南:DDU深度卸载工具完全教程 [特殊字符]
  • 《凌微经》的“静态自悖”概念到底是指什么?
  • GetQzonehistory:三步快速备份QQ空间全部历史说说的终极指南
  • 网络安全零基础到实战:从计算机基础到漏洞挖掘的完整学习路径
  • 电力监测系统厂家推荐:2026年靠谱品牌选择指南! - 优质品牌商家
  • 2026年天津活动搭建租赁厂家推荐:舞台搭建、桁架出租、场景布置、桌椅设备租赁选型指南 - 海棠依旧大
  • 2026年南京庭院改造勘测怎么做?排水坡度地下管网一次讲透
  • 如何一键抓取网页视频:猫抓浏览器扩展的终极使用指南
  • ClickHouse十大最佳实践技巧
  • C#程序脱壳实战:使用de4dot与dnSpy逆向分析.NET混淆代码
  • 零基础小白做抖店必看!1688 无货源一件代发实操步骤,搭配抖掌柜单人轻松运营店铺 - 电商分享
  • IP175G引脚图详解:硬件设计、PCB布局与故障排查指南
  • 单片机毕业设计-基于 STM32 与 OLED 的可调时交通灯监控系统设计 基于 STM32 与 TM1650 数码管交通倒计时装置设计(016101)
  • 2026年上海宝山装潢公司推荐:室内外装修、家装设计、旧房翻新、局部改造选型指南 - 海棠依旧大
  • 2026 年 7 月新发布:盐亭热门的弯管生产厂家深度解析,用了十年的老物件,居然是家装里看不见的隐形功臣-江东管道 - 领域鉴赏官
  • 华为Mate60账号锁终极解决方案:官方解锁全流程与风险避坑指南
  • 图解人工智能(92)人工智能前沿-预测新冠病毒传染性
  • 2026年8月石家庄轻集料混凝土小型空心砌块/复合自保温空心砌块公司推荐名单_高邑县东玉墙体材料厂 - 品牌宣传支持者