【Spring】IOC/DI、AOP底層原理
阿新 • • 發佈:2020-09-08
Spring IOC/DI和動態代理AOP底層原理(底層程式碼實現)
(1)Spring IOC/DI原理 思想:反轉控制,依賴注入,將物件建立和物件屬性賦值的權利,從當前的程式碼中轉移spring工廠中 原理: 工廠設計模式+反射+配置檔案 public class BeanFactory{ public Object getObject(String name){ //根據name獲得對應的全類名(properties配置檔案) String className = ...; Class clazz = Class.forName(className); return clazz.newInstance(); } } 應用好處(使用): 解耦和,將物件建立和屬性賦值的耦合解開 比如開發中Service,Controller,DAO物件,連線池,事務管理器,都可以從spring工廠中獲得,實現瞭解耦和效果 (2)SpringAOP底層實現原理 AOP思想:面向切面程式設計,在不修改目的碼的情況的情況下,動態為其增加額外功能。 SpringAOP技術本質:使用了動態代理的設計模式,為目標類的程式碼,生成一個代理類,產生代理物件,替換目標物件接受呼叫 靜態代理 ① 編碼: 與目標物件相同的介面、有額外功能、擁有目標物件,呼叫目標物件的方法 ② 程式碼: public class UserServiceProxy implements UserService{ private UserService userService = new UserServiceImpl(); public void regist(){ System.out.println("前置增強"); userService.regist(); //呼叫目標物件的方法 System.out.println("前置增強"); } } ③ 解釋: 作用:實現了事務,日誌,許可權,效能程式碼解耦和 缺點:所有靜態代理類,都是程式設計師人工編寫,為每個目標類,都要書寫一個代理類,程式碼冗餘 Jdk動態代理[基於介面的] 動態代理:代理類是通過程式碼自動生成的。 特點: 要求目標類必須有介面 Object proxy = Proxy.newProxyInstance(ClassLoader,目標類的介面,增強功能類); //直接生成代理類,生成物件 重要引數:ClassLoader: 動態位元組碼技術,動態生成一個類資訊的byte[],藉助於classloader,將byte[]轉化為Class物件 目標類介面:UserService public class Proxy0 implements UserService{ public void regist(){ //核心程式碼 } } 增強功能類:書寫額外功能,類似Spring的MethodInterceptor 代理類產生過程 類載入 JDK動態代理的程式碼實現: 目標物件:UserServiceImpl 額外功能增強的類:InvocationHandler 生成代理類:Object proxy = Proxy.newProxyInstance(類載入器,目標類的介面,增強功能); public static void main(String[] args) { //① 準備目標物件 final UserService us = new UserServiceImpl(); //② 準備額外功能(介面實現) InvocationHandler handler = new InvocationHandler() { /** proxy: 產生當前代理物件 * method: 目標物件的方法 * args: 目標物件的方法實際傳入的引數 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //前置額外增強程式碼 //目標物件的目標方法呼叫 Object o = method.invoke(us, args); //相當於mi.proceed(); //後置額外增強程式碼 return o; } }; //③ 生成代理類,產生代理物件 Object proxy = Proxy.newProxyInstance(us.getClass().getClassLoader(), us.getClass().getInterfaces(), handler); System.out.println(proxy.getClass().getSimpleName()); UserService usproxy = (UserService) proxy; usproxy.regist(); //呼叫方法 } 基於繼承的靜態代理: 代理類核心要素:與目標類有相同的方法[繼承目標類,覆蓋父類方法]、額外功能程式碼、呼叫目標物件方法 靜態代理第二種實現: 目標類: public class YellowLaodaye{ public void saleHouse() { System.out.println("籤合同,收錢,交易過程。"); } } 代理類: public class $Proxy1 extends YelloLaodaye{ @Override public void saleHouse(){ //增添的額外功能 super.方法(); } } Cglib的動態代理: cglib動態代理技術: 生成基於繼承的代理類,及其物件 編碼步驟: 額外功能:InvocationHander(cglib包下) 目標物件:目標類 target = new 目標類(); 組裝生成代理類: 增強器: EnHancer ① 繫結父類:父類.class ② 組合額外功能:handler ③ 生成代理類的物件:eh.create(); 示例程式碼: //① 目標物件 final YellowLaodaye yld = new YellowLaodaye(); //② 增強功能 InvocationHandler handler = new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //前置增強。 System.out.println("1. 發廣告!"); System.out.println("2. 看房子!"); //呼叫目標物件的目標方法。 Object obj = method.invoke(yld, args); return obj; } }; //③ 組裝生成代理類的物件 Enhancer eh = new Enhancer(); eh.setSuperclass(YellowLaodaye.class); //繫結父類 eh.setCallback(handler); //繫結額外功能物件 Object proxy = eh.create(); //生成代理類物件 YellowLaodaye proxylaodaye = (YellowLaodaye) proxy; proxylaodaye.saleHouse(); 總結Springaop原理(重要): 1) 本質:(李代桃僵)為目標類,使用動態位元組碼技術(jdk動態代理,cglib動態代理)動態生成代理類,反射建立代理類的物件,替換原有的目標物件。 注意: ① 如果目標類有介面,spring預設會使用jdk動態代理, ② 如果目標類沒有介面,但是能夠被繼承(沒有被final修飾),spring會自動切換使用cglib動態代理技術, ③ 如果目標類,沒有介面且被final修飾,無法完成代理類生成。 2) Jdk動態代理:基於介面的方式生成代理類、要求目標類必須有介面 3) Cglib動態代理:基於繼承的方式生成代理類、要求目標類必須能夠被繼承【不能用final修飾】 4) 補充:動態代理效能 Jdk版本每次更新,都會大幅度提升Jdk動態代理效能,jdk1.8以後,Jdk動態代理效能完勝cglib