當前位置:
首頁 >
前端技术
> javascript
>内容正文
javascript
Spring AOP源码分析(七)ProxyFactoryBean介绍
生活随笔
收集整理的這篇文章主要介紹了
Spring AOP源码分析(七)ProxyFactoryBean介绍
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
2019獨角獸企業重金招聘Python工程師標準>>>
這篇文章里面就要說說Spring自己的AOP,搞清楚哪種方式是Spring自己實現的AOP,哪種方式是Spring引入aspectj的AOP。Spring自己的AOP實現在于ProxyFactoryBean。先看下使用案例(仍和之前的案例是一樣的):接口AService、實現類AServiceImpl、通知MyBeforeAdvice
public interface AService {public void fooA(String _msg); public void barA(); }
public class AServiceImpl implements AService{@Overridepublic void fooA(String _msg) {System.out.println("AServiceImpl.fooA(msg:"+_msg+")");}@Overridepublic void barA() {System.out.println("AServiceImpl.barA()"); }}
public class MyBeforeAdvice implements MethodBeforeAdvice{@Overridepublic void before(Method method, Object[] args, Object target)throws Throwable {System.out.println("run my before advice");}}
然后就是xml的配置:
<bean id="aServiceImpl" class="com.lg.aop.service.impl.AServiceImpl"/><bean id="myBeforAdvice" class="com.lg.aop.MyBeforeAdvice"/><bean class="org.springframework.aop.framework.ProxyFactoryBean"><property name="interfaces" value="com.lg.aop.service.AService"/><property name="target"><ref bean="aServiceImpl"/></property><property name="interceptorNames"> <list> <value>myBeforAdvice</value> </list> </property> </bean>
然后就可以使用了:
@Autowiredprivate AService aService;@Testpublic void testAOP(){aService.barA();}
運行這個單元測試,然后你就會看到報如下錯誤:
No qualifying bean of type [com.lg.aop.service.AService] is defined: expected single matching bean but found 2: aServiceImpl,org.springframework.aop.framework.ProxyFactoryBean#0
原因就是對于接口AService,有兩個實現類aServiceImpl和ProxyFactoryBean所生產的代理類。所以我們不能使用@Autowired(它是按類型注入),所以要使用按名稱注入,我們怎么獲取ProxyFactoryBean所產生的代理類的名稱呢?其實就是ProxyFactoryBean配置的名稱。因為ProxyFactoryBean實現了FactoryBean接口,對于這種接口從容器中獲取該bean,不是獲取的本身而是獲取他的getObject方法所返回的值,看FactoryBean的文檔:
/*** Interface to be implemented by objects used within a {@link BeanFactory}* which are themselves factories. If a bean implements this interface,* it is used as a factory for an object to expose, not directly as a bean* instance that will be exposed itself.** <p><b>NB: A bean that implements this interface cannot be used as a* normal bean.</b> A FactoryBean is defined in a bean style, but the* object exposed for bean references ({@link #getObject()} is always* the object that it creates.
所以通過beanName找到了ProxyFactoryBean,然而不是返回該對象,而是返回他的getObject方法的返回值,所以我們通過ProxyFactoryBean的id就可以獲取到它所產生的代理對象,所以更改如下:
<bean id="aServiceImplProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> 其他略
在使用注入的時候按名稱注入
@Resource(name="aServiceImplProxy")private AService aService;
然后就可以正常運行了如下:
run my before advice AServiceImpl.barA()
然后我們就要源碼分析下這一過程,先看下是如何產生代理對象的,在ProxyFactoryBean的getObject方法中:
public Object getObject() throws BeansException { //重點1initializeAdvisorChain();if (isSingleton()) { //重點2return getSingletonInstance();}else {if (this.targetName == null) {logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +"Enable prototype proxies by setting the 'targetName' property.");}return newPrototypeInstance();}}
重點1:就是根據我們配置的interceptorNames來獲取對應的bean,并卻轉化成Advisor。如下:
private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {if (this.advisorChainInitialized) {return;}if (!ObjectUtils.isEmpty(this.interceptorNames)) {if (this.beanFactory == null) {throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +"- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames));}// Globals can't be last unless we specified a targetSource using the property...if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) &&this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {throw new AopConfigException("Target required after globals");}// Materialize interceptor chain from bean names.for (String name : this.interceptorNames) {if (logger.isTraceEnabled()) {logger.trace("Configuring advisor or advice '" + name + "'");}if (name.endsWith(GLOBAL_SUFFIX)) {if (!(this.beanFactory instanceof ListableBeanFactory)) {throw new AopConfigException("Can only use global advisors or interceptors with a ListableBeanFactory");}addGlobalAdvisor((ListableBeanFactory) this.beanFactory,name.substring(0, name.length() - GLOBAL_SUFFIX.length()));}else {// If we get here, we need to add a named interceptor.// We must check if it's a singleton or prototype.Object advice;if (this.singleton || this.beanFactory.isSingleton(name)) {// Add the real Advisor/Advice to the chain.advice = this.beanFactory.getBean(name);}else {// It's a prototype Advice or Advisor: replace with a prototype.// Avoid unnecessary creation of prototype bean just for advisor chain initialization.advice = new PrototypePlaceholderAdvisor(name);}addAdvisorOnChainCreation(advice, name);}}}this.advisorChainInitialized = true;}
this.advisorChainInitialized:標示是否已進行過初始化,若以初始化則不再進行初始化。然后就是將interceptorNames轉化成Advisor。根據interceptorNames所包含的字符串到容器中進行查找,如果含有*則,則表示進行一定的匹配,符合的都會納入。如官方文檔中說的:
<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean"><property name="target" ref="service"/><property name="interceptorNames"><list><value>global*</value></list></property> </bean><bean id="global_debug" class="org.springframework.aop.interceptor.DebugInterceptor"/> <bean id="global_performance" class="org.springframework.aop.interceptor.PerformanceMonitorInterceptor"/>
這中間頁經過了Advice到Advisor的轉換,如下:
private void addAdvisorOnChainCreation(Object next, String name) {// We need to convert to an Advisor if necessary so that our source reference// matches what we find from superclass interceptors.Advisor advisor = namedBeanToAdvisor(next);if (logger.isTraceEnabled()) {logger.trace("Adding advisor with name '" + name + "'");}addAdvisor(advisor);}
private Advisor namedBeanToAdvisor(Object next) {try {return this.advisorAdapterRegistry.wrap(next);}}}
public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {if (adviceObject instanceof Advisor) {return (Advisor) adviceObject;}if (!(adviceObject instanceof Advice)) {throw new UnknownAdviceTypeException(adviceObject);}Advice advice = (Advice) adviceObject;if (advice instanceof MethodInterceptor) {// So well-known it doesn't even need an adapter.return new DefaultPointcutAdvisor(advice);}for (AdvisorAdapter adapter : this.adapters) {// Check that it is supported.if (adapter.supportsAdvice(advice)) {return new DefaultPointcutAdvisor(advice);}}throw new UnknownAdviceTypeException(advice);}
這個包裹過程已經見過很多遍了,采用了適配器的模式。
之后又是和其他的AOP方式接軌了,設置一些列要實現的接口和參數,使用DefaultAopProxyFactory先創建出AopProxy,要么是JdkDynamicAopProxy,要么是CglibAopProxy,然后就可以調用AopProxy的getProxy方法來獲取代理對象了。這個過程詳見上一篇博客http://lgbolgger.iteye.com/blog/2119810。
這種方式實現的AOP還是比較麻煩的,同時配置一個ProxyFactoryBean僅能實現對一個目標對象的攔截,要想攔截多個目標對象,需要配置多個ProxyFactoryBean。所以大部分還是使用Spring引進的aspectj的AOP方式來進行AOP編程。
若想轉載請注明出處: http://lgbolgger.iteye.com/blog/2122993
作者:iteye的乒乓狂魔
轉載于:https://my.oschina.net/Sheamus/blog/393601
總結
以上是生活随笔為你收集整理的Spring AOP源码分析(七)ProxyFactoryBean介绍的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SQL优化(二) 快速计算Distinc
- 下一篇: 声明式事务和编程式事务