Spring AOP程式設計(二)-AOP實現的三種方式
阿新 • • 發佈:2018-11-25
AOP的實現有三種方式:
l aop底層將採用代理機制進行實現。
l 介面 + 實現類 :spring採用 jdk 的動態代理Proxy。
l 實現類:spring 採用 cglib位元組碼增強。
一.手工方式
1.JDK動態代理
JDK動態代理 對“裝飾者”設計模式 簡化。使用前提:必須有介面
1.目標類:介面 + 實現類
2.切面類:用於存通知 MyAspect
3.工廠類:編寫工廠生成代理
4.測試
1.目標類
UserService.java
package com.zk.a_jdk; public interface UserService { public void addUser(); public void updateUser(); public void deleteUser(); }
UserServiceImpl.java
package com.zk.a_jdk; public class UserServiceImpl implements UserService{ @Override public void addUser() { // TODO Auto-generated method stub System.out.println("proxy addUser"); } @Override public void updateUser() { // TODO Auto-generated method stub System.out.println("proxy updateUser"); } @Override public void deleteUser() { // TODO Auto-generated method stub System.out.println("proxy deleteUser"); } }
2.切面類
MyAspect.java
package com.zk.a_jdk; public class MyAspect { public void before(){ System.out.println("雞頭"); } public void after(){ System.out.println("牛後"); } }
3.工廠
package com.zk.a_jdk; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class MyBeanFactory { //手工代理 public static UserService createService(){ //1.目標類 final UserService userservice=new UserServiceImpl(); //2.切面類 final MyAspect myAspect=new MyAspect(); //3.代理類:將目標類(切入點)和切面類(通知)結合-->切面 //Proxy.newProxyInstance /* * 引數一:loader類載入器,動態代理類,執行時建立,任何類都需要類載入器將其載入至記憶體。 * 一般情況下:當前類,class.getClassLoader(); * 目標類例項:getClass().get... * 引數二:interfaces,代理類需要實現的所有介面 * 方式一:目標類例項.getClass().getInterfaces();注意:只能獲得自己的介面,獲得不到父元素的介面 * 方式二:new Class[]{UserService.class} * 例如:jdbc驅動 * 引數三:InvocationHandler 處理類,介面,必須進行實現類,一般採用匿名內部類 * 提供invoke方法,代理類每一個方法執行時,都將去呼叫invoke * 引數三.1.Object proxy代理物件 * 引數三.2.Method method 代理物件當前方法的描述物件(反射) * 執行方法方法名:method.getName(); * 執行方法:method.invoke(物件,實際引數) * 引數三.3 Object[] args 方法實際引數 */ UserService proxyService=(UserService)Proxy.newProxyInstance (MyBeanFactory.class.getClassLoader(), userservice.getClass().getInterfaces(), new InvocationHandler(){ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // TODO Auto-generated method stub //前執行 myAspect.before(); //執行目標類的方法 Object obj=method.invoke(userservice, args); //後執行 myAspect.after(); return null; } }); return proxyService; } }
4.測試類
package com.zk.a_jdk; import org.junit.Test; public class TestJDK { @Test public void test(){ UserService userservice=MyBeanFactory.createService(); userservice.addUser(); userservice.deleteUser(); userservice.updateUser(); } }
執行效果:
2. CGLIB位元組碼增強
l 沒有介面,只有實現類。
l 採用位元組碼增強框架 cglib,在執行時 建立目標類的子類,從而對目標類進行增強。
l 匯入jar包:
1.目標類
UserService.java
package com.zk.a_jdk; public interface UserService { public void addUser(); public void updateUser(); public void deleteUser(); }
UserServiceImpl.java
package com.zk.a_jdk; public class UserServiceImpl implements UserService{ @Override public void addUser() { // TODO Auto-generated method stub System.out.println("proxy addUser"); } @Override public void updateUser() { // TODO Auto-generated method stub System.out.println("proxy updateUser"); } @Override public void deleteUser() { // TODO Auto-generated method stub System.out.println("proxy deleteUser"); } }
2.切面類
MyAspect.java
package com.zk.a_jdk; public class MyAspect { public void before(){ System.out.println("雞頭"); } public void after(){ System.out.println("牛後"); } }
3.MyBeanFactory.java工廠類
package com.zk.b_cglib; import java.lang.reflect.Method; import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; public class MyBeanFactory { //手工代理 public static UserService createService(){ //1.目標類 final UserServiceImpl userservice=new UserServiceImpl(); //2.切面類 final MyAspect myAspect=new MyAspect(); /*3.代理類 * 採用位元組碼增強框架-cglib,程式執行時建立目標類的子類,從而對目標類進行增強 * 匯入jar包 * intercept等效於jdk中invoke方法 * 引數一二三 與invoke相同 * 引數四方法的代理 */ Enhancer enhance=new Enhancer(); //確定父類 enhance.setSuperclass(userservice.getClass()); enhance.setCallback(new MethodInterceptor(){ //設定回撥函式,MethodInterceptor介面等效 jdk InvocationHandler介面 @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodproxy) throws Throwable { // TODO Auto-generated method stub //前before myAspect.before(); //執行目標類的方法 Object obj=method.invoke(userservice, args); //執行代理類的父類 methodproxy.invokeSuper(proxy, args); //後after myAspect.after(); return null; } }); //建立代理 UserServiceImpl proxyservice=(UserServiceImpl) enhance.create(); return proxyservice; } }
4.TestCglib.java測試
package com.zk.b_cglib; import org.junit.Test; public class Testcglib { @Test public void test(){ UserService userservice=MyBeanFactory.createService(); userservice.addUser(); userservice.deleteUser(); userservice.updateUser(); } }
執行效果圖:
二.半自動方式
讓spring 建立代理物件,從spring容器中手動的獲取代理物件。
匯入jar包:
AOP:AOP聯盟(規範)、spring-aop (實現)
1.目標類
UserService.java
public interface UserService { public void addUser(); public void updateUser(); public void deleteUser(); }
UserServiceImpl.java
package com.zk.springAop; public class UserServiceImpl implements UserService{ @Override public void addUser() { // TODO Auto-generated method stub System.out.println("addUser"); } @Override public void updateUser() { // TODO Auto-generated method stub System.out.println("updateUser"); } @Override public void deleteUser() { // TODO Auto-generated method stub System.out.println("deleteUser"); } }
2.切面類
/** * 切面類中確定通知,需要實現不同介面,介面就是規範,從而就確定方法名稱。 * * 採用“環繞通知” MethodInterceptor * */ public class MyAspect implements MethodInterceptor { @Override public Object invoke(MethodInvocation mi) throws Throwable { System.out.println("前3"); //手動執行目標方法 Object obj = mi.proceed(); System.out.println("後3"); return obj; } }
3.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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd "> <!-- 建立目標類 --> <bean id="userserviceid" class="com.zk.factorybean.UserServiceImpl"></bean> <!-- 建立切面類 --> <bean id="aspectid" class="com.zk.factorybean.MyAspect"></bean> <!-- 建立代理類 使用工廠bean factorybean,底層呼叫getObject(), 返回特殊bean ProxyBeanFactory用於建立代理工廠bean,生成特殊代理物件 interface確定介面 通過Array確定多個值 只有一個值時,value="" target確定目標類 interceptorNames:通知切面類名稱,型別String[],如果設定一個值, value="" optimize:強制使用cglib <property name="optimized value="true"></property> 底層機制: 如果目標類有介面,採用jdk代理 如果沒有介面,採用cglib代理 如果宣告式optimize=true,都使用cglib --> <bean id="proxyServiceid" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="interfaces" value="com.zk.factorybean.UserService"></property> <property name="target" ref="userserviceid"></property> <property name="interceptorNames" value="aspectid"></property> </bean> </beans>
4.Testfactorybean.java
package com.zk.factorybean; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Testfactorybean { @Test public void test(){ String path="com/zk/factorybean/ApplicationContext.xml"; ApplicationContext ac=new ClassPathXmlApplicationContext(path); UserService userservice=(UserService) ac.getBean("proxyServiceid"); userservice.addUser(); userservice.deleteUser(); userservice.updateUser(); } }
執行效果:
三.spring aop程式設計:全自動
從spring容器獲得目標類,如果配置aop,spring將自動生成代理。
要確定目標類,aspectj 切入點表示式,匯入jar包spring-framework-3.0.2.RELEASE-dependencies\org.aspectj\com.springsource.org.aspectj.weaver\1.6.8.RELEASE
1.目標類
UserService.java
public interface UserService { public void addUser(); public void updateUser(); public void deleteUser(); }
UserServiceImpl.java
package com.zk.springAop; public class UserServiceImpl implements UserService{ @Override public void addUser() { // TODO Auto-generated method stub System.out.println("addUser"); } @Override public void updateUser() { // TODO Auto-generated method stub System.out.println("updateUser"); } @Override public void deleteUser() { // TODO Auto-generated method stub System.out.println("deleteUser"); } }
2.切面類
/** * 切面類中確定通知,需要實現不同介面,介面就是規範,從而就確定方法名稱。 * * 採用“環繞通知” MethodInterceptor * */ public class MyAspect implements MethodInterceptor { @Override public Object invoke(MethodInvocation mi) throws Throwable { System.out.println("前3"); //手動執行目標方法 Object obj = mi.proceed(); System.out.println("後3"); return obj; } }
3.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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd "> <!-- 建立目標類 --> <bean id="userserviceid" class="com.zk.springAop.UserServiceImpl"></bean> <!-- 建立切面類 --> <bean id="aspectid" class="com.zk.springAop.MyAspect"></bean> <!-- Aop程式設計 1.匯入名稱空間 2.使用<aop:config>進行配置 proxy-target-class="true"宣告是使用cglib代理 <aop:pointcut>:切入點,從目標物件上獲取具體的方法 <aop:advisor>特殊的切面,只有一個通知和一個切入點 advise-ref 通知引用 pointcut-ref 切入點引用 advisor通知 3.切入點表示式 execution(* com.zk.springAop.*.*(..)) 選擇方法 *表示返回值任意 包 類名任意. 方法名任意 . 引數任意 . --> <aop:config> <aop:pointcut expression="execution(* com.zk.springAop.*.*(..))" id="myPointCut"/> <aop:advisor advice-ref="aspectid" pointcut-ref="myPointCut"/> </aop:config> </beans>