spring基礎知識總結----AOP代理模式的實現

代理模式
問題的提出:
當項目的一些方法完成後,需要增加一些功能如安全性檢查,若在原來方法上增加這些功能,就需要修改源代碼。
最好的辦法是使用一個程序,完成增加的功能,並能調用原來方法 ,這樣就不需要修改原來的代碼。該程序就是代理。 spring可以通過增加一個橫切性關注點,比如權限驗證,日誌,安全性檢查。

代理原則:可控制原對象,但不會改變原對象的接口
代理的種類:靜態代理(能看到的,實際存在的代理類)
動態代理:是在運行期生成出來的
對被代理對象的要求:以實現接口的方式完成方法的創建

靜態代理:
代理對象和目標對象有共同的接口,實現了相同的方法,並且代理對象有個屬性是目標對象的接口,我們可以通過spring配置或註解注入接口的實現類(真正的目標類),這樣我們就可以通過操作代理對象的方法取操作目標對象的方法,比如對其增加安全檢查。顯示的調用目標類的方法,便實現了靜態代理。

動態代理:
目標對象類實現接口,代理對象類實現InvocationHandler接口及其invoke(),並定義立一個目標對象類的引用,建立一個方法newProxy()返回代理對象,這個方法的參數(和目標對象類相同的類裝載器,代理對象實現的接口,回調對象)。可以在這個代理對象的類中新增方法(功能),在應用層創建代理對象,調用相應的方法,spring對自動調用invoke(),在這裏通過反射執行目標對象的方法,給目標對象的方法增加新的功能(織入),這樣會給目標對象的每個方法都會織入。
invoke()方法的參數:代理對象,代理對象相應的方法,方法的參數

public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {}

1 定義一個目標對象的的引用,保存傳遞過來的目標對象
2 newProxyInstance(同一個類加載器,同一個接口,目標對象的地址)
3 測試類中創建代理

AOP

 AOP中的術語簡介
 Cross cutting concern 橫切性關注點—檢查安全性 (checkSecurity)
 Aspect 切面(模塊化的類–SecurityHandler)
 Advice 橫切性關注點的實現–checkSecurity
 Pointcut 應用Advice的過濾條件
 Joinpoint 連接點—織入的點(如adduser(..)方法)
 Weave織入–把關注點的方法應用到目標方法的過程
 Target Object 目標對象
 Proxy 代理對象
 Introduction 在類中動態的增加方法

實現方法
1:Annotation (註解)的方式對AOP的支持
—- SPRING_HOME/lib/aspectj/*.jar
—– 定義切面,@Aspect
—— 定義pointcut(舉例:@Pointcut(“execution(* add*(..)) || execution(* del*(..))”)
—— 定義advice(舉例:@Before(“allAddMethod()”) )
—— 啓用對Annotation的支持,applicationContext.xml中加入
—– 把Aspect和目標對象配置在IOC容器中,applicationContext.xml中
配置切面
<bean id="securityHandler" class="com.bjsxt.spring.SecurityHandler"/>
配置userManager的實現
<bean id="userManager" class="com.bjsxt.spring.UserManagerImpl"/>
這樣spring就會自動的創建切面對象,並採用動態代理機制把它自動的應用到目標對象上去(創建動態代理類)
—— 測試

2:配置文件的方式對AOP的支持
—— 引入相關的庫
—— 定義切面類
—– applicationContext.xml文件中進行配置

配置文件:
<!-- 將對象納入spring管理使用bean標籤 -->
<bean id="securityHandler" class="com.isunnyvinson.spring.SecurityHandler"/>
    <bean id="userManager" class="com.isunnyvinson.spring.UserManagerImpl"/>
    <aop:config>
        <aop:aspect id="security" ref="securityHandler">     <!-- 切面類的對象叫做切面,在這裏就是security -->
            <aop:pointcut id="allAddMethod" 
                          expression="execution(* com.isunnyvinson.spring.UserManagerImpl.add*(..))"/>

            <!-- method=""一定是本切面裏面的一個方法    pointcut-ref="allAddMethod",作用於allAddMethod標識的pointcut中-->
            <aop:before method="checkSecurity" pointcut-ref="allAddMethod"/>
        </aop:aspect>
    </aop:config>   

解釋:
配置信息創建了切面類對象,由這個對象的註解知道了切面、advise、poincut — 給pointcut標識的方法,織入advise。而織入是在方法執行之前, 要完成織入,必須先創建代理對象 ,使用invoke(),要創建代理對象,必須先創建繼承了Invocation接口的類的對象 。
所以,一共創建一下四個對象:切面類對象 目標對象 代理對象 實現了Invocation接口的類對象。

附1:
Aspect默認情況下不用實現接口,但對於目標對象(UserManagerImpl.java),在默認情況下必須實現接口,如果沒有實現接口必須引入CGLIB庫。一句話總結:目標對象沒有實現接口,使用CGLIB代理對象;目標對象實現了接口,使用JDK的動態代理。

附2:
可以通過Advice中添加一個JoinPoint參數,這個值會由spring自動傳入,從JoinPoint中可以取得
參數值、方法名等等

    private void checkSecurity(JoinPoint joinPoint) {
        Object[] args = joinPoint.getArgs();
        for (int i=0; i<args.length; i++) {
            System.out.println(args[i]);
        }

        System.out.println("方法名:  "+joinPoint.getSignature().getName());
        System.out.println("----------checkSecurity()---------------");
    }
發佈了24 篇原創文章 · 獲贊 11 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章