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 implements AService{ @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{ @Override public 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所生产的代理类。所以我们不能使用@Resource(它是按类型注入),所以要使用按名称注入,我们怎么获取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编程。