springAOP之動態代理(三)

AOP的相關概念

這裏面的名詞解釋,可以結合上一章的內容(模擬Hibernate的事務處理和查看工資)來進行理解。
1. 切面
日誌、安全性、權限類以及事務類,總之和業務邏輯沒有關係的都可以做切面
2. 通知
切面中的方法。例如:事務中的beginTransaction和commit方法
3. 切入點
只有符合切入點,才能把通知和目標方法結合起來。例如:代理的判斷語句

if("admin".equals(this.privilege.getAccess())){
        //調用目標類的目標方法
        method.invoke(this.iSalaryManage, args);
    }else{
        System.out.println("您沒有權限");
    }


4. 連接點
客戶端調用的方法

 proxy.showSalary();//代理對象的代理方法

AOP做到了代碼的重用

springAOp切面編程的例子

結合上一節的“模擬Hibernate的事務處理”來進行拓展。因此,這裏只粘貼部分代碼。

Xml文件

使用AOP切面編程
1. 導入命名空間
2. 引入目標類

3. 定義切面類,過濾切入點。代理類的生成交給spring來完成
4. 設置通知方法

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<!-- 
    使用AOP切面編程
    1. 導入命名空間
    2. 引入目標類
    3. 定義切面類,過濾切入點
    4. 設置通知方法
-->
<bean id="personDao" class="com.lzl.test.aop_proxy.PersonDaoImpl"></bean>
<bean id="transaction" class="com.lzl.test.aop_proxy.Transaction"></bean>
<aop:config>
    <!-- 切面類
        expression(切面表達式) 
        com.lzl.test.aop_proxy.personDaoImpl下面的所有方法
     -->
    <aop:pointcut expression="execution(* com.lzl.test.aop_proxy.PersonDaoImpl.*(..))" id="perform"/>
    <!--
        切面 
     -->
    <aop:aspect ref="transaction">
        <!-- 前置通知
             * 在目標方法執行之前
        -->
        <aop:before method="beginTransaction" pointcut-ref="perform"/>
        <!-- 後置通知
            * 在目標方法執行之後執行
            * 通過returning來獲取返回的結果
            * 代理方法發生異常時,不執行該方法
         -->
        <aop:after-returning method="commit" pointcut-ref="perform" returning="val"></aop:after-returning>
        <!--
            最終通知
            * 目標方法執行之後
            * 無論是否發生異常,都會執行。類似於finally
            * 常用於資源的關閉等操作 
         -->
        <aop:after method="finallyMethod" pointcut-ref="perform"/>
        <!--
            異常通知
            * 目標方法發生異常時,觸發該方法。
            * throwing拋異常的參數
         -->
        <aop:after-throwing method="throwEx" throwing="ex" 
        pointcut-ref="perform"></aop:after-throwing>
        <!-- 環繞通知
            * 在目標方法執行之前執行
            * 可以控制那些對象執行目標方法                
         -->
         <aop:around pointcut-ref="perform" method="arroundAdvice"></aop:around>
    </aop:aspect>
</aop:config>   
</beans>

切入點類

public class Transaction {
/**
 * 前置通知
 * @param joinPoint
 */
public void beginTransaction(JoinPoint joinPoint){
    joinPoint.getArgs(); //獲取方法參數
    String methodName = joinPoint.getSignature().getName();
    System.out.println("=begin transaction...="+methodName);
}
/**
 * 後置通知
 * @param val
 */
public void commit(Object val){
    //List<Person> list = (List<Person>) val;
    //System.out.println("=commit...="+list.size());
    System.out.println("=commit...=");
}
/**
 * 最終通知
 */
public void finallyMethod(){
    System.out.println("finally Method...");
}
/**
 * 異常通知
 * @param ex
 */
public void throwEx(Throwable ex){
    System.out.println(ex.getMessage());
}
public void arroundAdvice(ProceedingJoinPoint pjp) throws Throwable{
    String methodName = pjp.getSignature().getName();
    if("savePerson".equals(methodName)){
        pjp.proceed();
    }
}
}

測試類

public class PersonTest extends SpringHelper{
static{
    path="com/lzl/test/aop_proxy/applicationContext.xml";
}
@Test
public void test(){
    PersonDao personDao = (PersonDao) fileResource.getBean("personDao");
    personDao.selectPerson();
}
}

說明
如果目標類實現了接口,spring就用JDKproxy代理,如果沒有實現接口,spring就使用cglib代理。
用SpringAOP重構查看工資的代碼

代碼的實現參照上一節。這裏只粘貼修改的代碼

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
    <bean id="salaryManage" class="com.lzl.test.spring.salary.SalaryManageImpl"></bean>
    <bean id="logger" class="com.lzl.test.spring.salary.Logger"></bean>
    <bean id="privilege" class="com.lzl.test.spring.salary.Privilege"></bean>
    <bean id="security" class="com.lzl.test.spring.salary.Security"></bean>
    <!--
         一個切入點有多個切面
         通知方法執行的順序,按照其配置的先後順序來執行的。
     -->
    <aop:config>
    <!-- 定義的目標類及方法 -->
        <aop:pointcut expression="execution(* com.lzl.test.spring.salary.SalaryManageImpl.*(..))" id="perform"/>
        <!-- 切面 -->
        <aop:aspect ref="logger">
            <!-- 前置通知 
                日誌系統
            -->
            <aop:before method="startLogger" pointcut-ref="perform"/>
        </aop:aspect>
        <aop:aspect ref="security">
            <!-- 前置通知 
                安全系統
            -->
            <aop:before method="startSecurity" pointcut-ref="perform"/>
        </aop:aspect>
        <aop:aspect ref="privilege">
            <!-- 前置通知
                權限驗證
            -->
            <aop:before method="openPrivilege" pointcut-ref="perform"/>
        </aop:aspect>
    </aop:config>   
</beans>

測試類

public class SalaryTest extends SpringHelper{
static{
    path="com/lzl/test/spring/salary/applicationContext.xml";
}
@Test
public void test(){
    ISalaryManage sm = (ISalaryManage) fileResource.getBean("salaryManage");
    sm.showSalary();
}
}

AOP註解

使用註解的方式實現AOP切面編程。(僅供瞭解)
這個例子還是MVC的那個例子。在PersonDaoImpl中添加了事務的處理。這裏只粘貼部分代碼。

XML文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
    <!--
        開啓註解解析器
     -->
    <context:component-scan base-package="com.lzl.test.annotation.mvc.aop"></context:component-scan>
    <!-- 開啓AOP的註解 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

事務類(切面類)

@Component("transaction")
@Aspect  //定義爲切面類
public class Transaction {
    //切入點
    @Pointcut("execution(* com.lzl.test.annotation.mvc.aop.PersonDaoImpl.*(..))")
    private void aa(){} //方法簽名  返回值必須是void 方法的修飾符最好是private
    @Before("aa()")
    public void beginTransaction(){
        System.out.println("=開啓事務...=");
    }
    @AfterReturning("aa()")
    public void commit(){
        System.out.println("=關閉事務..=");
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章