手把手带你写一个 MiniSpring
郭屹
前 Sun Microsystems Java 研发工程师,开源软件 MiniSpring、MiniTomcat 开发者
6170 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 26 讲
手把手带你写一个 MiniSpring
15
15
1.0x
00:00/00:00
登录|注册

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

你好,我是郭屹,今天我们继续手写 MiniSpring,这也是 AOP 正文部分的最后一节。今天我们将完成一个有模有样的 AOP 解决方案。

问题的引出

前面,我们已经实现了通过动态代理技术在运行时进行逻辑增强,并引入了 Pointcut,实现了代理方法的通配形式。到现在,AOP 的功能貌似已经基本实现了,但目前还有一个较大的问题,具体是什么问题呢?我们查看 aplicationContext.xml 里的这段配置文件来一探究竟。
<bean id="realaction" class="com.test.service.Action1" />
<bean id="action" class="com.minis.aop.ProxyFactoryBean">
<property type="String" name="interceptorName" value="advisor" />
<property type="java.lang.Object" name="target" ref="realaction"/>
</bean>
看这个配置文件可以发现,在 ProxyFactoryBean 的配置中,有个 Object 类型的属性:target。在这里我们的赋值 ref 是 realactionbean,对应 Action1 这个类。也就是说,给 Action1 这个 Bean 动态地插入逻辑,达成 AOP 的目标。
在这里,一次 AOP 的配置对应一个目标对象,如果整个系统就只需要为一个对象进行增强操作,这自然没有问题,配置一下倒也不会很麻烦,但在一个稍微有规模的系统中,我们有成百上千的目标对象,在这种情况下一个个地去配置则无异于一场灾难。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

自动代理创建动态代理技术是一种解决AOP配置问题的创新方法。通过BeanPostProcessor自动创建代理,利用Bean的名称匹配规则自动生成代理,实现对每一个符合规则的Bean进行动态代理的工作。这种技术大大简化了AOP配置,提高了系统的可维护性和扩展性。文章介绍了如何修改getBean方法以应用BeanPostProcessor进行后期处理,对满足规则的Bean进行包装,改头换面成为一个Factory Bean。通过配置文件和代码示例展示了如何使用BeanNameAutoProxyCreator和Advisor来自动创建动态代理,并通过测试验证了其效果。这种基于JDK的AOP方案对于理解AOP原理很有帮助,并展示了IoC容器的强大之处。总的来说,这篇文章为读者提供了一种简单而有效的动态代理创建方法,为理解AOP原理和提高系统可维护性提供了有益的参考。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《手把手带你写一个 MiniSpring》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(9)

  • 最新
  • 精选
  • 马儿
    置顶
    这节课的代码能够做到不需要在beans.xml中额外专门配置来生成代理对象,已经接近spring的雏形了。但是按照之前的代码是跑不起来的,需要对之前的BeanPostProcessor的逻辑修改一下,应该是老师之前讲漏了的部分。主要工作在修改AbstractAutowireCapableBeanFactory类将属性中的beanPostProcessors改为面向接口的列表,其次是修改ClassPathXmlApplicationContext#registerBeanPostProcessors让其可以在配置文件中读到注册的BeanPostProcessors并注册到容器中。最后将我们之前用到的AutowiredAnnotationBeanPostProcessor注册到容器中管理就能够自动发现了。 代码修改可以参考:https://github.com/horseLk/mini-spring/commit/7186afebeaf30d622d79b4111970945abca97701

    作者回复: github上每一节的代码都是可运行的。文稿是写重点,会有漏掉细节。感谢你的补充。

    2023-04-26归属地:四川
  • peter
    问题放在第20课,但问题是关于第19课的: Q1:Join Point和Pointcut的区别是什么?两个看起来是一回事啊。 Q2:流程方面,Interceptor先拦截,拦截以后再进行增强操作。换一种说法,先是Interceptor工作,然后是Join Point、Pointcut、advice这些登场,对吗? Q3:19课的总结部分,是这样说的:“Advisor:通知者,它实现了 Advice”。19课的留言解答有这样一句话“advisor则是一个管理类,它包了一个advice,还能寻找到符合条件的方法名进行增强”。 留言的解释很不错,但总结部分,“实现了 Advice”,个人感觉这个措辞不是很合理啊,怎么是“实现”?这个词容易让人理解为接口与实现类的关系。

    作者回复: Peter总是很用心细致。 Join point跟Pointcut不是一回事,它是指在类中的位置,如是方法上?是构造器上?是属性上?pointcut是条件,如哪些符合条件的方法上加上增强。 流程你得理一下源代码,这些概念之间并没有流程。 口头讲课确实有一些随意,不那么精确,”实现”一词呢,因为advisor里面包了一个advice,就那么说了,不是代码意义上的“实现”。形象地说,advice是饭(真正的业务增强逻辑),advisor是碗筷(装饭给人吃的工具),人不能直接用嘴巴啃饭,要用一个工具把饭吃到嘴里。

    2023-04-27归属地:北京
    5
  • __@Wong
    补充一个点,这里需要保证AutowiredAnnotationBeanPostProcessor和BeanNameAutoProxyCreator两个BeanPostProcessor的优先级,AutowiredAnnotationBeanPostProcessor要在之前哦,在xml文件里面AutowiredAnnotationBeanPostProcessor的bean要放前面。

    作者回复: 是

    2023-06-24归属地:广东
    3
  • Geek_320730
    可以定义一个注解@Transaction并实现一个MethodMatcher,根据有没有这个注解来判断方法是否匹配,匹配的话,在方法执行前,手动开启事务,方法结束后,手动提交事务,有异常的话回滚事务。那事务方法调用事务方法的时候不知道会不会报错。。。 另外遇到Bean可以一直嵌套代理的问题,比如上一章手动配置的action,本身就是一个ProxyFactoryBean了,但是他的名字依然符合本章的action*的匹配规则,这样就又加了一层代理,注入的时候就会失败。需要在获取类的时候判断一下类型递归返回,或者在bean匹配规则的时候做一下类型判断,如果本身是个ProxyFactoryBean了,就不做操作返回。

    作者回复: 你这个bean嵌套代理的补充很好。

    2023-04-26归属地:北京
    1
  • __@Wong
    将原有的bean替换成代理后的bean那里,如果遇到循环引用会有问题吧, 引用的还是旧的bean。

    作者回复: 不会有问题的。因为getBean()也改写了: AbstractBeanFactory的getBean(): //beanpostprocessor //step 1 : postProcessBeforeInitialization singleton = applyBeanPostProcessorsBeforeInitialization(singleton, beanName); //这一步将bean改头换面成proxyfactorybean

    2023-06-20归属地:广东
    2
  • __Alucard
    完结撒花,谢谢指导

    作者回复: 恭喜,多谢。

    2023-05-29归属地:浙江
  • __Alucard
    动态代理失效的根本原因是@Autowired注解解析的时候,取到的spring bean还是没代理的对象; 我的临时解决方案是 在BeanNameAutoProxyCreator的postProcessBeforeInitialization手动把创建后的动态代理对象注入进spring ioc中, beanFactory.registerBean(beanName,proxyFactoryBean); 但是这样会导致BeanFactory又对外暴露了注册bean的接口,void registerBean(String beanName, Object obj);明显不合适,这个有没有更好的办法

    作者回复: 你讲的问题讲到点上了。我只能说Spring目前的方案就是挺合适的方案,我自己想不出别的合适的办法。

    2023-05-29归属地:浙江
    2
  • 浩仔是程序员
    老师你好,怎么github上面这块framework这个包下面有部分代码是重复的呢?建议可以来个代码结构的总结

    作者回复: 我检查一下,多谢提醒。

    2023-05-02归属地:广东
  • 天敌
    老师,关于使用 Proxy.newProxyInstance 生成的对象在进行 xml 中 ref 的属性绑定过程中,由于生成的代理对象并没有继承被代理对象的类,导致进行赋值时 IllegalArgumentException: argument type mismatch 这个问题,应该如何解决呢?
    2023-07-23归属地:四川
收起评论
显示
设置
留言
9
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部