Spring AOP 自動建立代理

俺就不起網名發表於2018-08-29

目錄

 

1、概述

2、實現類介紹

3、BeanNameAutoProxyCreator的使用

4、DefaultAdvisorAutoProxyCreator


1、概述

在學習切面的時候,都是通過ProxyFactoryBean建立織入切面的代理,每個需要被代理Bean都需要使用一個ProxyFactoryBean進行配置,很是麻煩。Spring為我們提供了自動代理機制,Spring 使用BeanPostProcessor自動地完成這項工作,讓容器為我們自動生成代理,把我們從煩瑣的配置工作中解放出來。

 BeanPostProcessor介面如下,定義了兩個方法

 public interface BeanPostProcessor {
 		Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
		Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}

2、實現類介紹

這些基於BeanPostProcessor的自動代理建立器的實現類,將根據一些規則自動在容器例項化Bean時為匹配的Bean生成代理例項。這些自動代理建立器可以分為3類。

a、基於Bean配置名規則的自動代理建立器:允許為一組特定配置名的Bean自動建立代理例項的代理建立器,實現類為BeanNameAutoProxyCreator;

b、基於Advisor匹配機制的自動代理建立器:它會對容器中所有的Advisor進行掃描,自動將這些切面應用到匹配的Bean中(即為目標Bean建立代理例項),實現類為DefaultAdvisorAutoProxyCreator;

c、基於Bean中AspjectJ註解標籤的自動代理建立器:為包含AspectJ註解的Bean自動建立代理例項,它的實現類是AnnotationAwareAspectJAutoProxyCreator。

3、BeanNameAutoProxyCreator的使用

程式碼例子依舊使用前面建立切面的程式碼,建立切面的例子中是使用ProxyFactoryBean對Waiter的Bean建立代理物件(建立切面程式碼地址:https://blog.csdn.net/u012385190/article/details/81952302)。下面通過BeanNameAutoProxyCreator以更優雅、更便捷的方式來建立代理物件

xml配置如下

    <!-- 前置增強 -->
    <bean id="greetBeforeAdvice" class="demo04.advisor.GreetBeforeAdivce"/>

    <!-- Waiter目標類 -->
    <bean id="waiterTarget" class="demo04.advisor.Waiter"/>
    <!-- Seller目標類 -->
    <bean id="seller" class="demo04.advisor.Seller"/>
    <!--根據beanName建立代理物件-->
    <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"
          p:beanNames="*Target"
          p:interceptorNames="greetBeforeAdvice"
          p:optimize="true"/>

測試類

    //一組特定配置名的Bean自動建立代理例項的代理建立器
    @Test
    public void test() {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("beans/beans2.xml");
        Waiter waiter = ctx.getBean("waiterTarget", Waiter.class);
        Seller seller = ctx.getBean("seller", Seller.class);
        waiter.greetTo("JayChou");
        waiter.serverTo("JayChou");
        seller.greetTo("JayChou");
    }

輸出(beanNames="*Target",該bean的方法都會使用增強)

How are you JayChou ?(切點方法為:public void demo04.advisor.Waiter.greetTo(java.lang.String))
Waiter Greet to JayChou
How are you JayChou ?(切點方法為:public void demo04.advisor.Waiter.serverTo(java.lang.String))
Waiter Server to JayChou
Seller Greet to JayChou

從輸出結果可以看出,BeanNameAutoProxyCreator有一個beanNames屬性,它允許使用者指定一組需要自動建立代理的Bean名稱,Bean名稱可以使用 * 萬用字元。但是使用匹配符可能會匹配到多餘的bean,所以也可以使用beanNames=“bean1,bean2”,用逗號分隔開多個要生成代理物件的bean。

4、DefaultAdvisorAutoProxyCreator

Advisor是切點和增強的複合體(切面),Advisor本身已經包含了足夠的資訊:橫切邏輯(要織入什麼)以及連線點(織入到哪裡)。DefaultAdvisorAutoProxyCreator能夠掃描容器中的Advisor,並將Advisor自動織入到匹配的目標Bean中,即為匹配的目標Bean自動建立代理。

<!--定義一個切面Advisor-->
<bean id="regexpAdvisor2" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"
          p:pattern=".*greet.*"
          p:advice-ref="greetingAdvice"/>
<!--該bean負責將容器中的Advisor織入匹配的目標bean中-->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>

測試

    @Test
    public void test() {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("beans/beans2.xml");
        Waiter waiter = ctx.getBean("waiterTarget", Waiter.class);
        Seller seller = ctx.getBean("seller", Seller.class);
        waiter.greetTo("JayChou");
        waiter.serverTo("JayChou");
        seller.greetTo("JayChou");
    }

輸出

How are you JayChou ?(切點方法為:public void demo04.advisor.Waiter.greetTo(java.lang.String))
Waiter Greet to JayChou
Waiter Server to JayChou
How are you JayChou ?(切點方法為:public void demo04.advisor.Seller.greetTo(java.lang.String))
Seller Greet to JayChou

Waiter#serverTo()方法沒有被織入增強,而Waiter和Seller的greetTo()方法都被織入了增強,由此可見,增強被正確的織入匹配的連線點中了。

 

 

相關文章