1. 程式人生 > >spring的proxy-target-class詳解

spring的proxy-target-class詳解

proxy-target-class屬性值決定是基於介面的還是基於類的代理被建立。首先說明下proxy-target-class="true"和proxy-target-class="false"的區別,為true則是基於類的代理將起作用(需要cglib庫),為false或者省略這個屬性,則標準的JDK 基於介面的代理將起作用。

proxy-target-class在spring事務、aop、快取這幾塊都有設定,其作用都是一樣的。


在面向切面程式設計時,我們會使用< aop:aspect>;在進行事務管理時,我們會使用< aop:advisor>。而AOP適合於那些具有橫切邏輯的應用:如應用和sql效能監測,訪問控制,事務管理、快取、物件池管理以及日誌記錄。

  • < aop:aspect>:定義切面(切面包括通知和切點)
  • < aop:advisor>:定義通知器(通知器跟切面一樣,也包括通知和切點)

主要不同點2個:

1、實現方式不同

< aop:aspect>定義切面時,只需要定義一般的bean就行,而定義< aop:advisor>中引用的通知時,通知必須實現Advice介面。(因為advisor中重寫的是advice中的方法來表示通知位置無法在aop配置表示通知位置;而aspect不用重寫,aspect是在aop配置中表示通知位置的)

下面我們舉例說明。 
首先,我們定義一個介面Sleepable和這個介面的實現Human,程式碼如下:

public interface Sleepable {
    public void sleep();
}

public class Human implements Sleepable {

    @Override
    public void sleep() {
        System.out.println("我要睡覺了!");
    }
}

下面是< aop:advisor>的實現方式:

//定義通知
public class SleepHelper implements MethodBeforeAdvice,AfterReturningAdvice{
    @Override
    public
void before(Method arg0, Object[] arg1, Object arg2) throws Throwable { System.out.println("睡覺前要脫衣服!"); } @Override public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable { System.out.println("起床後要穿衣服!"); } } //aop配置 <bean id="sleepHelper" class="com.ghs.aop.SleepHelper"></bean> <aop:config> <aop:pointcut expression="execution(* *.sleep(..))" id="sleepPointcut"/> <aop:advisor advice-ref="sleepHelper" pointcut-ref="sleepPointcut"/> </aop:config> <bean id="human" class="com.ghs.aop.Human"/>

下面是< aop:aspect>的實現方式:

//定義切面
public class SleepHelperAspect{
    public void beforeSleep(){
        System.out.println("睡覺前要脫衣服!");
    }

    public void afterSleep(){
        System.out.println("起床後要穿衣服!");
    }
}

//aop配置
<bean id="sleepHelperAspect" class="com.ghs.aop.SleepHelperAspect"></bean>

<aop:config>
    <aop:pointcut expression="execution(* *.sleep(..))" id="sleepPointcut"/>
    <aop:aspect ref="sleepHelperAspect">
        <!--前置通知-->
        <aop:before method="beforeSleep" pointcut-ref="sleepPointcut"/>
        <!--後置通知-->
        <aop:after method="afterSleep" pointcut-ref="sleepPointcut"/>
    </aop:aspect>
</aop:config>

<bean id="human" class="com.ghs.aop.Human"/>

測試程式碼如下:

public class TestAOP {
    public static void main(String[] args) {
        method1();
//      method2();
    }

    private static void method1() {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext1.xml");
        Sleepable sleeper = (Sleepable) context.getBean("human");
        sleeper.sleep();
    }

    private static void method2() {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext2.xml");
        Sleepable sleeper = (Sleepable) context.getBean("human");
        sleeper.sleep();
    }

//執行結果
睡覺前要脫衣服!
我要睡覺了!
起床後要穿衣服!
}

2、使用場景不同

< aop:advisor>大多用於事務管理或應用和SQL效能監控。
例如:事物管理

<!-- 會重複讀,不會髒讀事務 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="*" timeout="120" propagation="REQUIRED" rollback-for="Exception" />
    </tx:attributes>
</tx:advice>

<aop:config proxy-target-class="true">
    <aop:pointcut id="txPointCut" expression="..."/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut" />
</aop:config>

< aop:aspect>大多用於日誌,快取

其實,不管是< aop:advisor>還是< aop:aspect>最終的實現邏輯是一樣的。< aop:advisor>和< aop:aspect>其實都是將通知和切面進行了封裝,原理基本上是一樣的,只是使用的方式不同而已。

關於如何利用Druid實現應用和SQL監控請檢視https://blog.csdn.net/linlzk/article/details/47418685