1. 程式人生 > >spring---aop(6)---Spring AOP中ProxyFactoryBean介紹

spring---aop(6)---Spring AOP中ProxyFactoryBean介紹

except trace col fine erl 參數 owa per face

寫在前面

  這篇文章裏面就要說說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所生產的代理[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介紹