Spring(八)jdk動態代理(AOP簡單實現)
Spring(九)CGLIB位元組碼增強
這兩篇文章寫了兩種方式的手動組建代理程式。我們應該如何使用spring自動組建代理程式呢 spring編寫代理(半自動)
我們首先使用spring來類比我們自己產生的代理步驟即半自動 目標類
public interface UserService { public void addUser(); public void updateUser(); public void deleteUser();}切面類
切面類中確定通知,需要實現不同介面,介面就是規範,從而就確定方法名稱。
採用“環繞通知” MethodInterceptor
public class MyAspect implements MethodInterceptor{ @Override public Object invoke(MethodInvocation mi) throws Throwable { System.out.println("前方法"); Object obj=null; //執行目標類 obj=mi.proceed(); System.out.println("後方法"); return obj; }} spring配置
在建立代理類時,使用工廠bean factorybean 底層調用getObject返回特殊bean
proxyFactoryBean用於建立代理工廠bean 產生特殊代理對象。
interfaces : 確定介面們
通過可以設定多個值
只有一個值時,可以使用value=””
target : 確定目標類
interceptorNames : 通知 切面類的名稱,類型String[],如果設定一個值 value=””
在上兩篇文章中我們分別使用了jdk動態代理和cglib動態代理
在spring中我們可以通過設定<property name="optimize" value="true"></property> 強制使用cglib 而在不聲明optimize時
spring底層將判斷目標類是否有介面,如果沒有介面 使用cglib位元組碼增強,否則使用jdk動態代理。
<?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"> <!-- 建立目標類 --> <bean id="userServiceId" class="com.scx.autoproxy.test.UserServiceImpl"></bean> <!-- 建立切面類 --> <bean id="myAspectId" class="com.scx.autoproxy.test.MyAspect"></bean> <!-- 建立代理類--> <bean id="proxyServiceId" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="interfaces" value="com.scx.autoproxy.test.UserService"></property> <property name="target" ref="userServiceId"></property> <property name="interceptorNames" value="myAspectId"></property> </bean></beans>
測試
public void testProxy(){ String xmlPath="com/scx/autoproxy/test/applicationContext.xml"; ApplicationContext applicationContext=new ClassPathXmlApplicationContext(xmlPath); UserService userService=(UserService) applicationContext.getBean("proxyServiceId"); userService.addUser(); userService.updateUser(); userService.deleteUser(); }
運行結果:
spring編寫代理(全自動)
全自動和半自動相比較在於xml設定檔的代理類的編寫
在半自動中,我們是通過類比jdk動態代理的方式組建代理程式。在全自動中
使用aop命名空間實現。 spring配置
<?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.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- 建立目標類 --> <bean id="userServiceId" class="com.scx.autoproxy.test.copy.UserServiceImpl"></bean> <!-- 建立切面類(通知) --> <bean id="myAspectId" class="com.scx.autoproxy.test.copy.MyAspect"></bean> <!-- 建立代理類--> <aop:config proxy-target-class="true"> <aop:pointcut expression="execution(* com.scx.autoproxy.test.copy.*.*(..))" id="myPointCut"/> <aop:advisor advice-ref="myAspectId" pointcut-ref="myPointCut"/> </aop:config></beans>
在aop-config配置中,可以聲明proxy-target-class=”true”使用cglib代理
aop:pointcut 切入點 從目標對象獲得具體方法
aop:advisor 特殊的切面 只有一個通知和一個切入點
切入點運算式
execution(* com.scx.autoproxy.test.copy.*.*(..))/* 解釋如下: execution選擇方法 * 傳回值任意 com.scx.autoproxy.test.copy 包名 * 類名任意 * 方法名任意 .. 參數任意*/
測試
public void testProxy(){ String xmlPath="com/scx/autoproxy/test/copy/applicationContext.xml"; ApplicationContext applicationContext=new ClassPathXmlApplicationContext(xmlPath); UserService userService=(UserService) applicationContext.getBean("userServiceId"); userService.addUser(); userService.updateUser(); userService.deleteUser(); }運行結果: