參考鏈接:https://blog.csdn.net/liyifan687/article/details/90678729
1、AOP
1.1、面向切面編程,可分為靜態代理和動態代理
1.2、3個實現
AspectJ:靜態代理,我們在編寫一段獨立業務代碼時可以使用aspectj將邏輯加入
業務方法中(比如常用的操作日志記錄),在編譯后我們的class文件會
多出一段代碼,這段代碼就是aspectj在編譯時增加的aop代碼。這種做法可以稱為靜態代理
代理類在調用被代理類方法前后增加一些切面邏輯。
JDK動態代理:使用jdk的反射機制來完成aop的動態代理,有如下要求:
1)被代理類(我們實現業務的類)要實現統一接口
2)代理類要實現reflect包里面的InvacationHandler
3)通過jdk proxy提供的靜態方法newProxyInstance(xxx)來動態創建代理類
注:proxy是jdk動態生成的代理類,和service屬於同一個類,
但是save方法被動用時jdk為我們自動的實現類切面邏輯。
使用jdk反射機制,生成一個繼承Proxy的代理類。實現了InvocationHandler接口,
在調用方法時實際會先經過invoke方法轉發,所以可以在invoke方法上增加一些切面邏輯
1 // 統一接口 2 public interface IService { 3 void save(); 4 } 5 6 // 接口實現類 7 public class UserService implements IService{ 8 @Override 9 public void save() { 10 System.out.println("save a user ..."); 11 } 12 } 13 14 // 實現InvacationHandler 15 public class MyHandler implements InvocationHandler { 16 private Object target; 17 18 MyHandler(Object target) { 19 this.target = target; 20 } 21 //在這里實現我們的切面邏輯 22 @Override 23 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 24 System.out.println("before ..."); 25 Object result = method.invoke(target, args); 26 System.out.println("after ..."); 27 return result; 28 } 29 } 30 31 // 客戶端代碼 32 public static void main(String[] args) { 33 //創建被代理類 34 IService service = new UserService(); 35 //新建代理類,將被代理類注冊到里面 36 MyHandler aop = new MyHandler(service); 37 //Proxy為MyHandler動態創建一個符合某一接口的代理實例 38 //第一個參數:獲取被代理類的class loader 39 //第二個參數:獲取被代理類實現的接口, 由此可見被代理類需要實現統一的接口 40 //第三個參數:InvocationHandler的實例, 也就是我們做切面邏輯的類 41 IService proxy = (IService) Proxy 42 .newProxyInstance(service.getClass().getClassLoader(), 43 service.getClass().getInterfaces(), 44 aop); 45 //調用代理方法 46 proxy.save(); 47 } 48 49 // 輸出結果 50 before 51 save user 52 after
GGLIB:全稱Code Generation LIbrary,代碼生產庫。
基於字節碼技術,修改被代理類的.class文件生成代理類的子類,並重寫了代理類的方法。
實現了MethodInterceptor接口,在interceptor方法里增加切面邏輯
1 // 定義被代理類 2 public class UserService{ 3 public void save() { 4 System.out.println("save a user ..."); 5 } 6 } 7 8 // 實現MethodInterceptor接口(切面邏輯) 9 public class UserProxy implements MethodInterceptor { 10 @Override 11 public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { 12 //方法執行前的邏輯 13 System.out.println("before ..."); 14 e 15 Object result = methodProxy.invokeSuper(o, objects); 16 //方法執行后的邏輯 17 System.out.println("after ..."); 18 return result; 19 } 20 } 21 22 // 獲取被代理類工廠,該工廠專門生產加入了切面的被代理類 23 public class UserServiceFactory { 24 public static UserService getInstance(UserProxy proxy) { 25 Enhancer enhancer = new Enhancer(); 26 enhancer.setSuperclass(UserService.class); 27 //設置回調類,強化類調用回調類中的intercept方法來執行我們定義好的切面邏輯 28 enhancer.setCallback(proxy); 29 //返回一個添加了切面邏輯的增強類 30 return (UserService) enhancer.create(); 31 } 32 } 33 34 // 客戶端調用 35 public static void main(String[] args) { 36 UserProxy proxy=new UserProxy(); 37 //通過工廠方法模式獲取增強類 38 UserService service = UserServiceFactory.getInstance(proxy); 39 service.save(); 40 }
1.3、jdk動態代理和CGLIB區別
CGLIB是通過字節碼技術,在程序運行時為類創建了一個子類,重寫了父類的方法
並加入了切面邏輯(無法代理final方法)。
優點:繼承原對象並重寫方法,所有能代理普通類。
jdk動態代理是運用jdk反射機制,根據代理類和代理接口生成新的字節碼,然后進行加載並生成
對象。
優點:生成代理類相對較快,
缺點:但是運行切面邏輯沒有CGLIB快,且要實現統一接口擴展性較差。因為要繼承Proxy類
所以只能代理接口類。
2、IOC
2.1、控制反轉(獲得依賴對象的方式被反轉)
在業務中一般都需要至少兩個對象來完成,那么通常情況下每個對象在使用時都需要new,
這樣就導致對象之間的耦合度高了。IOC的思想就是Spring容器來實現這些相互依賴
對象的創建、協調,對象只需要關心業務邏輯本身就行了。
底層原理:反射技術