分享一波:程序員賺外快-必看的巔峰干貨
概念
通過代理控制對象的訪問,可以詳細訪問某個對象的方法,在這個方法調用處理,或調用后處理(類似于AOP)。
代理設計模式應用場景:AOP、權限控制、事務
常見代理的分類有:靜態代理,動態代理(JDK動態代理,Cglib等)
注意:本文所指的“代理”為設計模式中的“代理設計模式”,跟正向、反向代理并非一個概念,不要混淆。
靜態代理
由程序員創建或工具生成代理類的源碼,再編譯代理類。所謂靜態也就是在程序運行前就已經存在代理類的字節碼文件,代理類和委托類的關系在運行前就確定了。
public interface IUserDao {
void save();
}
public class UserDao implements IUserDao {
public void save() {
System.out.println(“已經保存數據…”);
}
}
/**
-
代理類
*/
public class UserDaoProxy implements IUserDao {
private IUserDao target;public UserDaoProxy(IUserDao iuserDao) {
this.target = iuserDao;
}public void save() {
System.out.println(“開啟事物…”);
target.save();
System.out.println(“關閉事物…”);
}
}
靜態代理需要每個被代理類都有一個代理類,因此代碼量較多,實際開發中非必須情況盡量少用。
動態代理
JDK動態代理
1)原理:是根據類加載器和接口創建代理類(此代理類是接口的實現類,所以必須使用接口 面向接口生成代理,位于java.lang.reflect包下)
2)實現方式:
-
通過實現InvocationHandler接口創建自己的調用處理器 IvocationHandler handler = new InvocationHandlerImpl(…);
-
通過為Proxy類指定ClassLoader對象和一組interface創建動態代理類Class clazz = Proxy.getProxyClass(classLoader,new Class[]{…});
-
通過反射機制獲取動態代理類的構造函數,其參數類型是調用處理器接口類型Constructor constructor = clazz.getConstructor(new Class[]{InvocationHandler.class});
-
通過構造函數創建代理類實例,此時需將調用處理器對象作為參數被傳入Interface Proxy = (Interface)constructor.newInstance(new Object[] (handler));
缺點:jdk動態代理,必須是面向接口,目標業務類必須實現接口
public class InvocationHandlerImpl implements InvocationHandler {
/** 目標代理對象 */
private Object target;public InvocationHandlerImpl(Object target) {this.target = target;
}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 反射執行方法Object invoke = method.invoke(target, args);return invoke;
}
public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException,IllegalAccessException, IllegalArgumentException, InvocationTargetException {// 被代理對象IUserDao userDao = new UserDao();InvocationHandlerImpl invocationHandlerImpl = new InvocationHandlerImpl(userDao);ClassLoader loader = userDao.getClass().getClassLoader();Class<?>[] interfaces = userDao.getClass().getInterfaces();// 主要裝載器、一組接口及調用處理動態代理實例IUserDao newProxyInstance = (IUserDao) Proxy.newProxyInstance(loader, interfaces, invocationHandlerImpl);newProxyInstance.save();
}
}
Cglib動態代理
原理:利用asm開源包,對代理對象類的class文件加載進來,通過修改其字節碼生成子類來處理。
使用cglib[Code Generation Library]實現動態代理,并不要求委托類必須實現接口,底層采用asm字節碼生成框架生成代理類的字節碼
引入依賴:
org.apache.commons commons-lang3 3.8.1 cglib cglib 3.1創建代理:
public class CglibProxy implements MethodInterceptor {
/** 代理對象 */
private Object target;public Object getInstance(Object target) {// 固定代碼,創建訪問對象this.target = target;Enhancer enhancer = new Enhancer();enhancer.setSuperclass(target.getClass());enhancer.setCallback(this);return enhancer.create();
}public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {Object invoke = methodProxy.invoke(target, args);return invoke;
}public static void main(String[] args) {CglibProxy cglibProxy = new CglibProxy();UserDao userDao = (UserDao) cglibProxy.getInstance(new UserDao());userDao.save();
}
}
Cglib和jdk動態代理的區別
java動態代理是利用反射機制生成一個實現代理接口的匿名類,在調用具體方法前調用InvokeHandler來處理。
而cglib動態代理是利用asm開源包,對代理對象類的class文件加載進來,通過修改其字節碼生成子類來處理。
Spring中。
1、如果目標對象實現了接口,默認情況下會采用JDK的動態代理實現AOP
2、如果目標對象實現了接口,可以強制使用CGLIB實現AOP
3、如果目標對象沒有實現了接口,必須采用CGLIB庫,spring會自動在JDK動態代理和CGLIB之間轉換
JDK動態代理只能對實現了接口的類生成代理,而不能針對類 。
CGLIB是針對類實現代理,主要是對指定的類生成一個子類,覆蓋其中的方法 。
因為是繼承,所以該類或方法最好不要聲明成final ,final可以阻止繼承和多態。
分享一波:程序員賺外快-必看的巔峰干貨
如果以上內容對你覺得有用,并想獲取更多的賺錢方式和免費的技術教程
請關注微信公眾號:HB荷包
一個能讓你學習技術和賺錢方法的公眾號,持續更新