动态代理设计模式
這個時候講一下動態的代理,動態和靜態到底有什么區別呢,其實剛才我已經詳細給大家說一下,靜態代理需要生成目標代理對象,動態代理是不需要生成目標代理對象,如果你們用動態的話,就不會有UserServiceProxy這一層了,這一層是在內存里面動態虛擬出來的,所以給你們講一下,你們也知道,動態代理核心是通過JDK動態代理和CGLIB這個方式進行實現的,那這個時候我再回顧一遍,JDK動態代理是采用反射虛擬生成,CGLIB是基于ASM字節碼技術虛擬生成代理類,這我們講一下,這個代碼我就不去寫了,寫的話就比較浪費時間,核心就講事務里面去,動態代理我就不細說了,動態代理是不需要生成代理類對象的,那么怎么做呢,第一種方式是JDK動態代理方式,底層是采用反射的機制,這段代碼我們來講一下
package com.learn.proxy001;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;import com.learn.service.MemberService;
import com.learn.service.UserService;
import com.learn.service.impl.MemberServiceImpl;
import com.learn.service.impl.UserServiceImpl;/*** 每次生成動態代理類對象時,實現了InvocationHandler接口的調用處理器對象* 實現動態代理的時候都需要實現這樣的一個接口* 實現接口它是干嘛用的呢* * @author Leon.Sun**/
public class InvocationHandlerImpl implements InvocationHandler {/*** 首先要把這樣的一個目標代理對象傳進來* */private Object target;// 這其實業務實現類對象,用來調用具體的業務方法// 通過構造函數傳入目標對象public InvocationHandlerImpl(Object target) {this.target = target;}/*** 在實現方法之前或之后做一個處理* * 在你方法之前和之后* 做了攔截* 使用JDK* * * */public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object result = null;/*** 使用JDK動態代理開啟事務*/System.out.println("使用jdk動態代理 開啟事務");result = method.invoke(target, args);/*** 使用JDK動態代理提交事務*/System.out.println("使用jdk動態代理 提交事務");/*** 這里返回一個result結果*/return result;}/*** 這里我寫了一個main函數* @param args* @throws NoSuchMethodException* @throws SecurityException* @throws InstantiationException* @throws IllegalAccessException* @throws IllegalArgumentException* @throws InvocationTargetException*/public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException,IllegalAccessException, IllegalArgumentException, InvocationTargetException {// 被代理對象// IUserDao userDao = new UserDao();/*** 這里寫一個UserService的實現* 在這里為就可以拿到UserService* 拿到UserService之后* 然后在這邊怎么處理呢* * 我只要把我們的目標代理對象傳進去就=行了* 它會自動的在你方法之前之后做這樣的處理* 就是這樣的* 有些人可能沒有學過AOP編程* 沒有學過代理設計模式* 像靜態代理是需要有一個接口的* 什么接口呢* 你必須有個接口* CGLIB可能不需要你有這個接口* 這個大體我說一下* 后面我們使用Spring事務的時候比這個簡單* 我們在AOP的基礎上使用事務* 就方便多了* 如果你真的需要寫的情況下* 那這些代碼都要寫的* 這里可以傳入任何的類* 這樣就可以在方法之前和之后做處理的* 這個就比較簡單* 你們注意看* 靜態代理是有這么一個靜態代理類對象的* 他每一個都要這么去寫的* 記住動態代理是不需要寫目標代理對象的* 是沒有寫代理對象的* 而且你們要記住啊* 我這里可以支持很多方法和任何接口* 都可以做一個這樣的代理的* * */UserService userService = new UserServiceImpl();
// InvocationHandlerImpl invocationHandlerImpl = new InvocationHandlerImpl(userService);/*** ClassLoader有多少人了解過* 可能不了解ClassLoader是干嘛用的* 他其實可以加載類的信息* 加載到JVM的內存里面去* 這個我記得是昨天剛講了* 這個我相信你們都記得* 熱部署其實就是通過ClassLoader進行實現的* 動態的把最新的字節碼文件讀取到JVM里面去* 就是這樣的一個原理*/
// ClassLoader loader = userService.getClass().getClassLoader();
// Class<?>[] interfaces = userService.getClass().getInterfaces();// 主要裝載器、一組接口及調用處理動態代理實例/*** 這里我們可以強轉一下UserService*/
// UserService newProxyInstance = (UserService) Proxy.newProxyInstance(loader, interfaces,
// invocationHandlerImpl);/*** 然后ADD方法就OK了* 不過這個例子非常簡單* */
// newProxyInstance.add();/*** new一個MemberServiceImpl* 是不是這樣的* 注意這里不需要代理對象* 我們這里沒有封裝* 正常只需要傳一個類進來* * */MemberService memberServiceImpl = new MemberServiceImpl();InvocationHandlerImpl invocationHandlerImpl = new InvocationHandlerImpl(memberServiceImpl);ClassLoader loader = memberServiceImpl.getClass().getClassLoader();Class<?>[] interfaces = memberServiceImpl.getClass().getInterfaces();// 主要裝載器、一組接口及調用處理動態代理實例MemberService newProxyInstance = (MemberService) Proxy.newProxyInstance(loader, interfaces,invocationHandlerImpl);/*** JDK動態代理開啟事務* 這里是方法業務* 在方法之前和之后做一些業務處理* 只要任何有接口的類* 我這里是寫死的* 因為只是講DEMO* 還有CGLIB就先不講了* 因為時間有限* 也是一樣的道理* 也是比較簡單* 只不過底層用的ASM* 就是通過字節碼技術生成一個代理類的* 目標類寫死沒關系的* 這只是舉個列子* */newProxyInstance.memberAdd();}
}
package com.learn.service;public interface MemberService {public void memberAdd();
}
package com.learn.service.impl;import com.learn.service.MemberService;/*** 如果我們要實現靜態代理的話* 我們就需要再寫一個代理類* 那就寫的很麻煩* * * @author Leon.Sun**/
public class MemberServiceImpl implements MemberService {public void memberAdd() {System.out.println("memberAdd");}}
動態代理
什么是動態代理
1.代理對象,不需要實現接口
2.代理對象的生成,是利用JDK的API,動態的在內存中構建代理對象(需要我們指定創建代理對象/目標對象實現的接口的類型)
3.動態代理也叫做:JDK代理,接口代理
JDK動態代理
1)原理:是根據類加載器和接口創建代理類(此代理類是接口的實現類,所以必須使用接口 面向接口生成代理,
位于java.lang.reflect包下)
2)實現方式:
1. 通過實現InvocationHandler接口創建自己的調用處理器
IvocationHandler handler = new InvocationHandlerImpl(…);
2. 通過為Proxy類指定ClassLoader對象和一組interface創建動態代理類
Class clazz = Proxy.getProxyClass(classLoader,new Class[]{…});
3. 通過反射機制獲取動態代理類的構造函數,其參數類型是調用處理器接口類型
Constructor constructor = clazz.getConstructor(new Class[]{InvocationHandler.class});
4. 通過構造函數創建代理類實例,此時需將調用處理器對象作為參數被傳入
Interface Proxy = (Interface)constructor.newInstance(new Object[] (handler));
缺點:jdk動態代理,必須是面向接口,目標業務類必須實現接口
CGLIB動態代理
原理:利用asm開源包,對代理對象類的class文件加載進來,通過修改其字節碼生成子類來處理。
什么是CGLIB動態代理
使用cglib[Code Generation Library]實現動態代理,并不要求委托類必須實現接口,底層采用asm字節碼生成框架生成代理類的字節碼
CGLIB動態代理與JDK動態區別
java動態代理是利用反射機制生成一個實現代理接口的匿名類,在調用具體方法前調用InvokeHandler來處理。
而cglib動態代理是利用asm開源包,對代理對象類的class文件加載進來,通過修改其字節碼生成子類來處理。
Spring中。
1、如果目標對象實現了接口,默認情況下會采用JDK的動態代理實現AOP
2、如果目標對象實現了接口,可以強制使用CGLIB實現AOP
3、如果目標對象沒有實現了接口,必須采用CGLIB庫,spring會自動在JDK動態代理和CGLIB之間轉換
JDK動態代理只能對實現了接口的類生成代理,而不能針對類 。
CGLIB是針對類實現代理,主要是對指定的類生成一個子類,覆蓋其中的方法 。
因為是繼承,所以該類或方法最好不要聲明成final ,final可以阻止繼承和多態。
?
超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術人生總結
- 上一篇: 静态代理设计模式
- 下一篇: 单列设计模式 懒汉式及多线程debug