1. 程式人生 > 實用技巧 >【Spring】IOC/DI、AOP底層原理

【Spring】IOC/DI、AOP底層原理

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