spring---aop(6)---Spring AOP中ProxyFactoryBean介紹
寫在前面
這篇文章裏面就要說說Spring自己的AOP,搞清楚哪種方式是Spring自己實現的AOP,哪種方式是Spring引入aspectj的AOP。
簡單例子
Spring自己的AOP實現在於ProxyFactoryBean。先看下使用案例(仍和之前的案例是一樣的):接口AService、實現類AServiceImpl、通知MyBeforeAdvice 。
public interface AService { public void barA(); public void barB(); }
public class AServiceImpl implementsAService{ @Override public void barA() { System.out.println("AServiceImpl.barA()"); this.barB(); } @Override public void barB() { System.out.println("AServiceImpl.barB()"); } }
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.xxx.plus.aop.demo.AServiceImpl"/> <bean id="myBeforAdvice" class="com.xxx.plus.aop.demo.MyBeforeAdvice"/> <bean id="aServiceImplProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="interfaces" value="com.xxx.plus.aop.demo.AService"/> <property name="target"> <ref bean="aServiceImpl"/> </property> <property name="interceptorNames"> <list> <value>myBeforAdvice</value> </list> </property> </bean>
然後就可以使用了:
@Resource private AService aService; @Test public void testAOP(){ aService.barA(); }
運行這個單元測試,然後你就會看到報如下錯誤:
No qualifying bean of type [com.xxx.aop.service.AService] is defined: expected single matching bean but found 2: aServiceImpl,org.springframework.aop.framework.ProxyFactoryBean#0
原因就是對於接口AService,有兩個實現類aServiceImpl和ProxyFactoryBean所生產的代理[email protected](它是按類型註入),所以要使用按名稱註入,我們怎麽獲取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. * * <p>FactoryBeans can support singletons and prototypes, and can * either create objects lazily on demand or eagerly on startup. * The {@link SmartFactoryBean} interface allows for exposing * more fine-grained behavioral metadata. * * <p>This interface is heavily used within the framework itself, for * example for the AOP {@link org.springframework.aop.framework.ProxyFactoryBean} * or the {@link org.springframework.jndi.JndiObjectFactoryBean}. * It can be used for application components as well; however, * this is not common outside of infrastructure code. * * <p><b>NOTE:</b> FactoryBean objects participate in the containing * BeanFactory‘s synchronization of bean creation. There is usually no * need for internal synchronization other than for purposes of lazy * initialization within the FactoryBean itself (or the like). */ public interface FactoryBean<T> {}
所以通過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 class ProxyFactoryBean extends ProxyCreatorSupport implements FactoryBean<Object>, BeanClassLoaderAware, BeanFactoryAware { @Override public Object getObject() throws BeansException { //重點一 initializeAdvisorChain(); if (isSingleton()) { //重點二 return 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。
this.advisorChainInitialized:標示是否已進行過初始化,若以初始化則不再進行初始化。然後就是將interceptorNames轉化成Advisor。根據interceptorNames所包含的字符串到容器中進行查找,如果含有*則,則表示進行一定的匹配,符合的都會納入。
如下:
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; }
這中間頁經過了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); } catch (UnknownAdviceTypeException ex) { // We expected this to be an Advisor or Advice, // but it wasn‘t. This is a configuration error. throw new AopConfigException("Unknown advisor type " + next.getClass() + "; Can only include Advisor or Advice type beans in interceptorNames chain except for last entry," + "which may also be target or TargetSource", ex); } }
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); }
public class DefaultPointcutAdvisor extends AbstractGenericPointcutAdvisor implements Serializable { public DefaultPointcutAdvisor(Advice advice) { this(Pointcut.TRUE, advice); } }
這個包裹過程已經見過很多遍了,采用了適配器的模式。
之後又是和其他的AOP方式接軌了,設置一些列要實現的接口和參數,使用DefaultAopProxyFactory先創建出AopProxy,要麽是JdkDynamicAopProxy,要麽是CglibAopProxy,然後就可以調用AopProxy的getProxy方法來獲取代理對象了
這種方式實現的AOP還是比較麻煩的,同時配置一個ProxyFactoryBean僅能實現對一個目標對象的攔截,要想攔截多個目標對象,需要配置多個ProxyFactoryBean。所以大部分還是使用Spring引進的aspectj的AOP方式來進行AOP編程。
spring---aop(6)---Spring AOP中ProxyFactoryBean介紹