從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)
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é)果