Spring-Aop兩種代理方式:
1、JDK動態代理:用於目標類實現了接口;
2、Cglib動態代理:用於目標類沒有實現接口;
spring會依據目標類是否實現接口來選擇使用哪種代理方式(目標類:相當於需要被增強的類);
模擬場景:目標類:步兵類,需要上戰場打仗(手提精心打造的木棍)
通知類(增強類):高級商店類,只要有士兵來就免費提供(精心打造的暴風大劍)
代理工廠類:需要一個士兵來使用商店的東西(這樣才能把士兵與商店聯系起來,士兵與商店本來是單獨存在的相互不知道)
JDK動態代理實現:
創建maven項目引入spring-aop依賴,使用的是5.1版本
1、目標類需要實現接口,所以先創建一個接口:SoldierInterface(士兵類的接口)
package top.free; /** * 士兵接口 */ public interface SoldierInterface { public void begin(); }
2、創建目標類(步兵類去實現接口),也可以有其他的類(弓箭兵。。。)只要實現了士兵類,都是士兵。
package top.free; /* *步兵類 */ public class Soldier implements SoldierInterface { @Override public void begin() { System.out.println("弓箭士兵開始戰斗"); } }
3、通知(也叫增強):商店類
package top.free.advice; public class Store { public void Before(){ System.out.println("為士兵換上暴風大劍。。。"); } public void After(){ System.out.println("士兵勝利歸來。。。"); } }
4、創建代理工廠:需要傳遞過來一個士兵(不管是步兵還是弓箭兵),返回一個被商店加強的士兵
package top.free.proxy; import top.free.SoldierInterface; import top.free.advice.Store; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy;
public class MyProxyFactory { //傳遞的soldier就是需要被增強的士兵類, public SoldierInterface MyProxyFactory(SoldierInterface soldier){ //通知,此時的商店類,在工廠中new出的實列 Store store = new Store(); SoldierInterface proxysoldier = (SoldierInterface) Proxy.newProxyInstance( MyProxyFactory.class.getClassLoader(),//第一個參數:使用當前類的類加載器 soldier.getClass().getInterfaces(),//第二個參數:傳遞的soldier士兵對象的接口 new InvocationHandler() {//第三個參數,匿名內部類形式 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //前置調用商店的配置 store.Before(); //調用目標方法,soldier就是傳遞的士兵對象,args參數默認無參 Object invoke = method.invoke(soldier, args); //后置,士兵執行完方法后調用 store.After(); return invoke; } } ); return proxysoldier; } }
5、測試運行:
package top.free; import top.free.proxy.MyProxyFactory; public class App { public static void main(String[] args) { //創建工廠 MyProxyFactory myProxyFactory = new MyProxyFactory(); //創建目標類(士兵對象),具體的實現是步兵類 SoldierInterface soldier = new Soldier(); //將創建的士兵傳遞給工廠,工廠中有商店幫忙打造士兵,用新士兵接收 SoldierInterface newSoldier = myProxyFactory.MyProxyFactory(soldier); //開始 newSoldier.begin(); } }
Cglib動態代理實現:
寫Jdk代理時已引入spring相關依賴,此時maven項目中已有spring-core包,Spring5.1版本中,spring-core包中有關於Cglib的類,不需要引入cglib依賴
1、Cglib代理使用的是沒有接口的目標類,所以直接創建弓箭兵:
package top.free; /** * Cglib目標類,沒有接口,弓箭兵類 */ public class BowsSoldier { public void begin(){ System.out.println("開始射殺敵人。。。"); } }
2、通知(商店類):
package top.free.advice; public class Store { public void Before(){ System.out.println("為士兵換上霸王弓。。。"); } public void After(){ System.out.println("士兵勝利歸來。。。"); } }
3、創建代理工廠:需要一個弓箭兵,返回一個裝備好的弓箭兵
package top.free.proxy; import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; import top.free.BowsSoldier; import top.free.advice.Store; import java.lang.reflect.Method; public class MyCglibProxyFactory { public BowsSoldier MyCglibProxyFactory(BowsSoldier solider){ //創建通知類 Store store = new Store(); //創建Enhance對象 Enhancer enhancer = new Enhancer(); //設置弓箭兵類對象 enhancer.setSuperclass(solider.getClass()); //設置回調方法 enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { //放在方法執行前,就是前置增強,裝備弓箭 store.Before(); //執行方法,solider就是傳遞過來的弓箭兵對象 Object invoke = method.invoke(solider); //后置增強 store.After(); return invoke; } }); //創建裝備好的士兵 BowsSoldier target1= (BowsSoldier) enhancer.create(); return target1; } }
4、測試:
package top.free; import top.free.proxy.MyCglibProxyFactory; import top.free.proxy.MyProxyFactory; public class App { public static void main(String[] args) {//創建代理工廠 MyCglibProxyFactory myCglibProxyFactory = new MyCglibProxyFactory(); //創建一個普通的弓箭兵 BowsSoldier soldier = new BowsSoldier(); //傳遞弓箭兵到工廠,工廠裝備好后返回,接收一個裝備精良的弓箭兵 BowsSoldier target = myCglibProxyFactory.MyCglibProxyFactory(soldier); //裝備精良的弓箭兵開始戰斗 target.begin(); } }