4.3 基于代理類(lèi)的Aop實(shí)現(xiàn)

從4.2節(jié)可知,在Spring中默認(rèn)使用JDK動(dòng)態(tài)代理實(shí)現(xiàn)Aop編程。使用org.springframework.aop.framework.ProxyFactoryBean創(chuàng)建代理是Spring Aop實(shí)現(xiàn)的基本方式。

1.通知類(lèi)型

在講解ProxyFactoryBean之前,先了解一下Spring的通知類(lèi)型。根據(jù)Spring中通知在目標(biāo)類(lèi)方法的連接點(diǎn)位置,可以分為6中如下類(lèi)型:

1.環(huán)繞通知(org.aopaliance.intercept.MethodInterceptor)是在目標(biāo)方法執(zhí)行前和執(zhí)行后實(shí)施增強(qiáng),可以用于日志記錄、事務(wù)處理等功能。

2.前置通知(org.apringframework.aop.MethodBeforeAdvice)
是在目標(biāo)方法執(zhí)行前實(shí)施增強(qiáng),可以用于權(quán)限管理等功能。

3.后置返回通知(org.springframework.aop.AfterReturningAdvice)是在目標(biāo)方法成功執(zhí)行后實(shí)施增強(qiáng),可應(yīng)用于關(guān)閉流、刪除臨時(shí)文件等功能。

4.后置(最終)通知(org.springframework.aop.AfterAdvice)是在目標(biāo)方法執(zhí)行后實(shí)施增強(qiáng),與后置返回通知不同的是,不管是否發(fā)生異常都要執(zhí)行該通知,可應(yīng)用于釋放資源。

5.異常通知(org.springframework.aop.ThrowsAdvice)是在方法拋出異常后實(shí)施增強(qiáng),可應(yīng)用于處理異常、記錄日志等功能。

6.引入通知(org.springframework.aop.IntroductionInterceptor)是在目標(biāo)類(lèi)中添加一些新的方法和屬性,可應(yīng)用于修改目標(biāo)類(lèi)(增強(qiáng)類(lèi))。

2.ProxyFactoryBean

ProxyFactoryBean是org.springframework.aop.framework.ProxyFactoryBean接口實(shí)現(xiàn)類(lèi),F(xiàn)actoryBean負(fù)責(zé)實(shí)例化一個(gè)Bean實(shí)例,ProxyFactoryBean負(fù)責(zé)為其他Bean實(shí)例創(chuàng)建代理實(shí)例。
下面通過(guò)一個(gè)實(shí)現(xiàn)環(huán)繞通知的實(shí)例演示Spring使用ProxyFactoryBean創(chuàng)建AoP代理的過(guò)程。

目錄結(jié)構(gòu)

img

2.1導(dǎo)入相關(guān)jar包

在核心jar包基礎(chǔ)上,需要在向ch4應(yīng)用的/WEB-INF/lib目標(biāo)下導(dǎo)入jar包spring-aop-5.0.2.RELEASE.jar和aopalliance-1.0.jar(aopallication-1.0.jar是AoP聯(lián)盟提供的規(guī)范包)。

2.2創(chuàng)建切面類(lèi)

由于該類(lèi)實(shí)例實(shí)現(xiàn)環(huán)繞通知,所以切面類(lèi)需要實(shí)現(xiàn)org.aopaliance.intercept.MethodInterceptor接口。在src目錄下,創(chuàng)建一個(gè)spring.proxyfactorybean包,并在該包中創(chuàng)建切面類(lèi)MyAspect

MyAspect.java

package spring.proxyfactorybean;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
/**
 *切面類(lèi)
 */
public class MyAspect implements MethodInterceptor {

    @Override
    public Object invoke(MethodInvocation arg0) throws Throwable {
        // TODO Auto-generated method stub
        //增強(qiáng)方法
        check();
        except();
        //執(zhí)行目標(biāo)方法
        Object obj = arg0.proceed();
        //增強(qiáng)方法
        log();
        monitor();
        return obj;
    }
    public void check() {
        System.out.println("模擬權(quán)限控制");
    }
    
    public void except() {
        System.out.println("模擬異常處理");
    }
    
    public void log() {
        System.out.println("模擬日志記錄");
    }
    
    public void monitor() {
        System.out.println("性能檢測(cè)");
    }

}

2.3配置切面并指定助理

切面類(lèi)需要配置Bean實(shí)例,Spring容器才能識(shí)別為切面對(duì)象。在spring.proxyfactorybean包中,創(chuàng)建配置文件applicationContext.xml,
并在文件中配置切面和指定代理對(duì)象。

applicationContext.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       
http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 定義目標(biāo)對(duì)象 -->
    <bean id="testDao" class="dynamic.jdk.TestDaoImpl" />
    <!-- 創(chuàng)建一個(gè)切面 -->
    <bean id="myAspect" class="spring.proxyfactorybean.MyAspect" />
    <!-- 使用Spring代理工廠定義一個(gè)名為testDaoProxy的代理對(duì)象 -->
    <bean id="testDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <!-- 指定代理對(duì)象接口 -->
        <property name="proxyInterfaces" value="dynamic.jdk.TestDao" />
        <!-- 指定目標(biāo)對(duì)象 -->
        <property name="target" ref="testDao" />
        <!-- 指定切面,植入環(huán)繞通知 -->
        <property name="interceptorNames" value="myAspect" />
        <!-- 指定代理方法,true為指定CGLIB動(dòng)態(tài)代理,默認(rèn)為false,指定JDK動(dòng)態(tài)代理 -->
        <property name="proxyTargetClass" value="true" />
    </bean>
</beans>

2.4創(chuàng)建測(cè)試類(lèi)

在spring.proxyfactorybean包中,創(chuàng)建測(cè)試類(lèi)ProxyFactoryBeanTest,在主方法中使用Spring容器獲取代理對(duì)象,并執(zhí)行目標(biāo)方法。

ProxyFactoryBeanTest.java

package spring.proxyfactorybean;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import dynamic.jdk.TestDao;

public class ProxyfactoryBeanTest {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        ApplicationContext appCon = new ClassPathXmlApplicationContext("/spring/proxyfactorybean/applicationContext.xml");
        //從容器中,獲取增強(qiáng)后的目標(biāo)對(duì)象
        TestDao testDaoAdvice = (TestDao)appCon.getBean("testDaoProxy");
        //執(zhí)行方法
        testDaoAdvice.save();
        System.out.println("==============");
        testDaoAdvice.modify();
        System.out.println("==============");
        testDaoAdvice.delete();
    }

}

運(yùn)行結(jié)果

img

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容