環(huán)境:Spring6.1.2
在Spring框架中,AOP(面向切面編程)是一種強(qiáng)大的編程范式,它允許開發(fā)者在不修改原有代碼的情況下,為程序添加額外的功能,如日志記錄、事務(wù)管理、安全控制等。
實(shí)際開發(fā)中常用實(shí)現(xiàn)AOP配置方式:
在早期的Spring版本中,開發(fā)者常常使用XML配置文件來定義切面、通知和目標(biāo)對(duì)象之間的關(guān)聯(lián)。通過配置<aop:config>、<aop:aspect>、<aop:before>等標(biāo)簽,可以輕松地實(shí)現(xiàn)AOP的各種功能。如下示例:
<aop:config> <aop:aspect id="myAspect" ref="aBean"> <aop:pointcut id="businessService" expression="execution(* com.pack.service.*.*(..))"/> <aop:before pointcut-ref="businessService" method="monitor"/> </aop:aspect></aop:config>
通過在切面類和方法上使用如@Aspect、@Before、@After等注解,可以更加簡潔地定義AOP的相關(guān)配置。這種方式不僅減少了XML配置的工作量,還使得代碼更加清晰易讀。如下示例:
@Component@Aspectpublic class LogAspect { @Pointcut("execution(* save(..))") private void logPc() {} @Around("logPc()") public Object process(ProceedingJoinPoint pjp) throws Throwable { Object ret = null ; System.out.println("before log...") ; ret = pjp.proceed() ; System.out.println("after log...") ; return ret ; }}
以上是Spring提供的2中方式來聲明AOP配置方式。但如果你需要一種更加靈活和可配置性,那么Spring還提供了一個(gè)非常方便強(qiáng)大的ProxyFactoryBean類,該類特別適合那些需要更多自定義和控制的場(chǎng)景,例如當(dāng)你需要為特定的Bean創(chuàng)建代理,或者需要在不修改原始代碼的情況下為現(xiàn)有類添加額外的功能時(shí)。
ProxyFactoryBean與其他Spring FactoryBean實(shí)現(xiàn)一樣,引入了一個(gè)間接級(jí)別。如果定義了名為pack的ProxyFactoryBean,那么引用pack的對(duì)象看不到ProxyFactoryBean實(shí)例本身,而是由ProxyFactoryBean#getObject()方法實(shí)現(xiàn)創(chuàng)建的對(duì)象。此方法創(chuàng)建一個(gè)AOP代理,用于包裝目標(biāo)對(duì)象。
ProxyFactoryBean提供了很多屬性,讓你可以靈活的配置代理對(duì)象。該對(duì)象繼承了ProxyConfig,一些關(guān)鍵的屬性是由ProxyConfig定義。
接下來將從2方面介紹ProxyFactoryBean的使用,代理接口與代理類。2.2 代理接口
要通過ProxyFactoryBean創(chuàng)建代理,你至少需要涉及到下面幾點(diǎn)(類):
如下示例:
public interface ICommonDAO { void save() ;}@Component("commonDAOTarget")public class CommonDAOImpl implements ICommonDAO { @Override public void save() { System.out.println("save operator...") ; }}@Componentpublic class LogInterceptor implements MethodInterceptor { @Override public Object invoke(MethodInvocation invocation) throws Throwable { System.out.println("before log...") ; Object ret = invocation.proceed() ; System.out.println("after log...") ; return ret ; }}@Configurationpublic class AppConfig { @Bean // 由于上面已經(jīng)定義了CommonDAOImpl,而這里的FactoryBean#getObject返回的 // 也是一個(gè)實(shí)現(xiàn)了ICommonDAO接口的對(duì)象,所以需要加上@Primary @Primary ProxyFactoryBean commonDAO(@Qualifier("commonDAOTarget") CommonDAOImpl commonDAOTarget) throws Exception { ProxyFactoryBean proxy = new ProxyFactoryBean() ; proxy.setProxyInterfaces(new Class<?>[] {ICommonDAO.class}) ; proxy.setTarget(commonDAOTarget) ; proxy.setInterceptorNames("logInterceptor") ; return proxy ; }}
測(cè)試
ICommonDAO dao = context.getBean(ICommonDAO.class) ;dao.save() ;// 輸出before log...save operator...after log...
如果我們的目標(biāo)沒有實(shí)現(xiàn)接口,那么我們只能通過CGLIB進(jìn)行代理,通過設(shè)置proxyTargetClass屬性為true。CGLIB代理通過在運(yùn)行時(shí)生成目標(biāo)類的子類來工作。Spring將這個(gè)生成的子類配置為將方法調(diào)用委托給原始目標(biāo)。如下示例:
@Component("commonDAOTarget")public class CommonDAO { public void save() { System.out.println("save operator...") ; }}@Bean@PrimaryProxyFactoryBean commonDAO(@Qualifier("commonDAOTarget") CommonDAO commonDAOTarget) throws Exception { ProxyFactoryBean proxy = new ProxyFactoryBean() ; proxy.setTarget(commonDAOTarget) ; proxy.setInterceptorNames("logInterceptor") ; // 代理類,可以不設(shè)置 proxy.setProxyTargetClass(true) ; return proxy ;}
查看最終的CommonDAO是否是通過CGLIB代理
CommonDAO dao = context.getBean(CommonDAO.class) ;System.out.println(dao.getClass()) ;
輸出結(jié)果
class com.pack.aop.create.ProxyFactoryBeanTest2$CommonDAO$$SpringCGLIB$$1
CGLIB代理通過在運(yùn)行時(shí)生成目標(biāo)類的子類來工作。但需要注意以下事項(xiàng):
在上面配置攔截器時(shí),我們都是指定的具體攔截器,其實(shí)我們還可以使用通配符,指定攔截器。如下示例:
@Component("global_log")public class LogInterceptor implements MethodInterceptor {}@Component("global_auth")public class AuthInterceptor implements MethodInterceptor {}// ProxyFactoryBena配置ProxyFactoryBean commonDAO() throws Exception { ProxyFactoryBean proxy = new ProxyFactoryBean() ; // 注意:這里的通配符必須是最后,你不能放到其它位置 proxy.setInterceptorNames("global_*") ; return proxy ;}
以上ProxyFactoryBean在初始化時(shí),會(huì)自動(dòng)查找容器中beanName以global_開頭的所有Bean對(duì)象。
本文鏈接:http://www.tebozhan.com/showinfo-26-86683-0.htmlSpring一個(gè)強(qiáng)大便捷的代理工廠類,你用過嗎?
聲明:本網(wǎng)頁內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com
上一篇: HTTP 協(xié)議是怎么來的?最開始是什么樣子?又是如何一步步發(fā)展 HTTP3
下一篇: 一種避免寫大量CRUD方法的新思路