20|AutoProxyCreator:如何自动添加动态代理? -- 知识铺
20 | AutoProxyCreator:如何自动添加动态代理?
你好,我是郭屹,今天我们继续手写MiniSpring,这也是AOP正文部分的最后一节。今天我们将完成一个有模有样的AOP解决方案。
问题的引出
前面,我们已经实现了通过动态代理技术在运行时进行逻辑增强,并引入了Pointcut,实现了代理方法的通配形式。到现在,AOP的功能貌似已经基本实现了,但目前还有一个较大的问题,具体是什么问题呢?我们查看applicationContext.xml里的这段配置文件来一探究竟。
|
|
AOP配置文件分析
在分析配置文件时,我们注意到ProxyFactoryBean
中有一个Object
类型的属性target
,其值通过ref
属性指向realactionbean
,即Action1
类。这意味着我们可以为Action1
这个Bean动态地插入逻辑,实现AOP的目标。
AOP配置的挑战
虽然为单个对象配置AOP逻辑并不复杂,但在一个大型系统中,如果需要为成百上千的对象进行增强操作,逐个配置将变得非常繁琐。因此,我们需要一个能够用简单的匹配规则代理多个目标对象的AOP解决方案。
匹配多个目标对象的思路
在之前的课程中,我们已经探讨了如何通过Pointcut
概念来匹配一个目标对象内部的多个方法,例如使用模式do*
或do*Action
等。这种模式匹配方法解决了目标对象内部方法匹配的问题,也为我们提供了解决匹配多个目标对象问题的灵感。
解决方案设想
我们期望实现的解决方案应该能够通过配置,使得一个AOP配置能够匹配并代理多个目标对象。具体配置方式如下:
|
|
利用BeanPostProcessor自动创建代理
在Spring框架中,IoC容器中的所有Bean都是相互独立且平等的。然而,我们可以通过特定机制让一个普通的Bean(例如GeneralProxy)影响到其他Bean,并根据规则给这些Bean动态地创建代理。
Bean创建过程回顾
当我们通过IoC容器创建一个Bean时,这个过程可以分解为以下几个步骤:
- IoC容器扫描配置文件并加载Bean定义。
- 当调用
getBean()
方法时,开始创建Bean实例,这一步骤包括:
-
创建Bean的基本实例(毛坯实例)。
-
填充Properties属性。
-
执行
postProcessBeforeInitialization
方法。 -
调用初始化方法(如果配置了
init-method
)。 -
执行
postProcessAfterInitialization
方法。
自动创建代理的关键点
上述过程中,postProcessBeforeInitialization
和postProcessAfterInitialization
这两个阶段是进行后期处理的理想时机。Spring提供了一个特殊的接口BeanPostProcessor
,它允许我们在Bean生命周期的这两个关键时刻对Bean进行修改或增强。
使用BeanNameAutoProxyCreator
为了实现根据Bean的名字匹配来自动创建动态代理的功能,我们可以创建一个名为BeanNameAutoProxyCreator
的类。这个类将实现BeanPostProcessor
接口,并利用模式串(如action*
)来匹配目标Bean,然后为匹配到的Bean生成代理。
实现思路
- BeanNameAutoProxyCreator 类需要实现
BeanPostProcessor
接口。 - 在
postProcessBeforeInitialization
或postProcessAfterInitialization
方法中,检查当前Bean的名字是否符合预设的模式串。 - 如果匹配成功,则使用
ProxyFactoryBean
或其他代理创建工具为该Bean创建一个代理对象。 - 返回创建好的代理对象替换原始Bean,以便后续操作都针对代理对象进行。 通过这种方式,我们可以确保只有符合条件的Bean才会被包装成具有额外行为(如事务管理、日志记录等)的代理对象,从而达到AOP编程的目的。
|
|
在postProcessBeforeInitialization
方法中,我们首先会判断Bean的名称是否与给定的规则相匹配。这一过程是通过调用isMatch(beanName, this.pattern)
来实现的。进一步探究后可以发现,这里的isMatch()
方法实际上是对PatternMatchUtils.simpleMatch()
方法的直接调用,这与我们在上一节课中学到的通配符模式匹配机制是一致的。
aaaaaaa 如果经过上述匹配过程,确定了某个Bean的名字符合我们的预设模式,接下来的操作就会创建一个针对该Bean的动态代理对象。这种做法允许我们为匹配到的特定Beans附加额外的行为或逻辑,而无需改变它们原有的实现细节。
整个流程如下:
- 在Spring容器初始化Bean之前,
postProcessBeforeInitialization
方法被触发。 - 使用
PatternMatchUtils.simpleMatch()
检查当前处理中的Bean名字是否满足指定模式。
当发现Bean名确实符合要求时,就采取类似于以往课程中介绍过的步骤来自动生成一个代理对象,以此来扩展或修改原Bean的功能。
|
|
在Spring框架中,我们经常使用ProxyFactoryBean
来创建动态代理,以实现AOP(面向切面编程)。以下是使用BeanPostProcessor
自动化这一过程的步骤:
-
理解
ProxyFactoryBean
:ProxyFactoryBean
是Spring提供的一个工厂Bean,用于创建动态代理对象。 -
BeanPostProcessor的作用:
BeanPostProcessor
是一个接口,它允许我们在Spring容器初始化Bean之后,执行自定义的逻辑。通过实现这个接口,我们可以对每个Bean进行动态代理。 -
自动化动态代理:将
BeanPostProcessor
应用到ProxyFactoryBean
,Spring容器会为每个符合规则的Bean自动创建动态代理,从而实现AOP功能。 -
配置XML文件:要使上述自动化过程生效,需要将
BeanPostProcessor
配置到Spring的XML配置文件中。这样,Spring容器就会自动为我们处理动态代理的创建。 通过这种方式,我们不再需要手动为每个Bean创建代理,Spring容器会为我们自动完成这一工作。
|
|
IoC容器扫描配置文件的时候,会把所有的BeanPostProcessor对象加载到Factory中生效,每一个Bean都会过一遍手。
getBean方法的修改
工具准备好了,这个BeanPostProcessor会自动创建动态代理。为了使用这个Processor,对应的AbstractBeanFactory类里的getBean()方法需要同步修改。你可以看一下修改后getBean的实现。
|
|
上述代码中主要修改这一行:
|
|
代码里会调用Processor的postProcessBeforeInitialization方法,并返回singleton。这一段代码的功能是如果这个Bean的名称符合某种规则,就会自动创建Factory Bean,这个Factory Bean里面会包含一个动态代理对象用来返回自定义的实例。于是,getBean的时候,除了创建Bean实例,还会用BeanPostProcessor进行后期处理,对满足规则的Bean进行包装,改头换面成为一个Factory Bean。到这里,我们就完成自动创建动态代理的工作了,简单测试一下。修改applicationContext.xml配置文件,增加一些配置。
|
|
这里我们配置了两个Bean,BeanPostProcessor和Advisor。
相应地,controller层的HelloWorldBean增加一段代码。
|
|
在这节课中,我们探讨了如何通过配置文件中的模式匹配来动态地为一组Bean创建代理,并对这些Bean的方法进行增强。以下是本课内容的总结:
Bean与方法的匹配
-
我们有两个Bean:
action
和action2
,每个都拥有doAction()
和doSomething()
两个方法。 -
在Processor的Pattern配置里,使用
action*
可以匹配所有以action
开头的Bean。 -
Advisor的MappedName配置里,利用
do*
来匹配所有以do
开头的方法。
动态代理的实现
-
当系统运行时,根据上述配置,会自动为匹配到的Bean及其方法添加额外逻辑。
-
这是通过BeanPostProcessor机制,在Bean初始化后但还未被使用前,对其进行后期处理实现的。
-
BeanPostProcessor接收一个模式字符串,该模式由用户在外部配置文件中指定。
-
isMatch()
方法用于基于名称进行模式匹配,匹配成功后,ProxyFactoryBean将用来创建动态代理。 -
最终,应用程序员配置的业务Bean会被IoC容器转换成包含动态代理的Factory Bean。
IoC容器的作用
-
本方案之所以可行,是因为IoC容器提供的BeanPostProcessor机制。
-
它展示了IoC容器的强大功能,能够灵活地管理对象的生命周期以及它们之间的依赖关系。
AOP架构完成
-
至此,基于JDK的AOP解决方案已经构建完毕。
-
此方案有助于深入理解AOP的基本原理。
-
更多详细信息及源代码,请参考GitHub上的minis项目。
课后思考题
-
AOP常用于数据库事务处理。请考虑如何运用当前所学的AOP架构实现简单的事务管理。
-
欢迎大家在评论区讨论你的想法,并分享给需要的朋友。
- 原文作者:知识铺
- 原文链接:https://index.zshipu.com/geek002/post/202410/20AutoProxyCreator%E5%A6%82%E4%BD%95%E8%87%AA%E5%8A%A8%E6%B7%BB%E5%8A%A0%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86--%E7%9F%A5%E8%AF%86%E9%93%BA/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。
- 免责声明:本页面内容均来源于站内编辑发布,部分信息来源互联网,并不意味着本站赞同其观点或者证实其内容的真实性,如涉及版权等问题,请立即联系客服进行更改或删除,保证您的合法权益。转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。也可以邮件至 sblig@126.com