@[toc]
代理模式
什麼是代理模式
通過代理控制對象的通路,可以詳細通路某個對象的方法,在這個方法調用處理,或調用後處理。既(AOP微實作) ,AOP核心技術面向切面程式設計。
代理模式應用場景
SpringAOP、事物原理、日志列印、權限控制、遠端調用、安全代理 可以隐蔽真實角色
代理的分類
- 動态代理(動态生成代理類)
- Jdk自帶動态代理
- Cglib 、javaassist(位元組碼操作庫)**
靜态代理
什麼是靜态代理
由程式員建立或根據生成的代理類源碼,再變異代理類。所謂靜态也就是再程式運作前就已經存在代理類的位元組碼檔案,代理類和委托類的關系在運作前就确定類
interface IUserDao{
void save();
}
/**
* 接口實作類
*/
public class UserDaoImpl implements IUserDao{
@Override
public void save() {
System.out.println("已經儲存資料...");
}
}
/**
* 代理類
*/
class UserDaoProxy implements IUserDao{
private IUserDao userDao;
public UserDaoProxy(IUserDao userDao) {
this.userDao = userDao;
}
@Override
public void save() {
System.out.println("開啟事物...");
userDao.save();
System.out.println("關閉事物...");
}
}
public static void main(String[] args) {
IUserDao userDao = new UserDaoImpl();
UserDaoProxy userDaoProxy = new UserDaoProxy(userDao);
userDaoProxy.save();
}
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnL3kTMwQjM1ITMwIjMxAjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
動态代理
什麼是動态代理
**1.代理對象,不需要實作接口
2.代理對象的生成,是利用JDK的API,動态的在記憶體中建構代理對象(需要我們指定建立代理對象/目标對象實作的接口的類型)
3.動态代理也叫做:JDK代理,接口代理**
JDK動态代理
- 原理:是根據類加載器和接口建立代理類(此代理類是接口的實作類,是以必須使用接口
- 面向接口生成代理,位于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動态代理,必須是面向接口,目标業務類必須實作接口
/**
* JDK動态代理
*/
public class InvocationHandlerImpl implements InvocationHandler {
// 每次生成動态代理類對象時,實作了InvocationHandler接口的調用處理器對象
// 這其實業務實作類對象,用來調用具體的業務方法
private Object target;
public InvocationHandlerImpl(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
System.out.println("動态代理 -- 開啟事物");
result = method.invoke(target, args);
System.out.println("動态代理 -- 送出事物");
return result;
}
}
interface IUserDao{
void save();
}
/**
* 接口實作類
*/
class UserDaoImpl implements IUserDao{
@Override
public void save() {
System.out.println("已經儲存資料...");
}
}
public static void main(String[] args) {
IUserDao userDao = new UserDaoImpl();
InvocationHandlerImpl invocationHandler = new InvocationHandlerImpl(userDao);
ClassLoader classLoader = userDao.getClass().getClassLoader();
Class<?>[] interfaces = userDao.getClass().getInterfaces();
IUserDao newUserDao= (IUserDao)Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
newUserDao.save();
}
CGLIB動态代理
- 原理: 利用asm 開源包,對代理對象類的class 檔案加載進來,通過修改其位元組碼生成子類來處理。
什麼是CGLIB動态代理
- 使用cglib[Code Generation Library]實作動态代理,并不要求委托類必須實作接口,底層采用asm位元組碼生成架構生成代理類的位元組碼
public class CglibProxy implements MethodInterceptor {
private Object obj;
public Object getInstance(Object obj) {
this.obj = obj;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(obj.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("CGLIB 動态代理 -- 開啟事物");
Object result = method.invoke(obj, objects);
System.out.println("CGLIB 動态代理 -- 送出事物");
return result;
}
}
interface IUserDao{
void save();
}
/**
* 接口實作類
*/
class UserDaoImpl implements IUserDao{
@Override
public void save() {
System.out.println("已經儲存資料...");
}
}
public static void main(String[] args) {
CglibProxy cglibProxy = new CglibProxy();
IUserDao userDao = (IUserDao)cglibProxy.getInstance(new UserDaoImpl());
userDao.save();
}
CGLIB動态代理與JDK動态差別
java動态代理是利用反射機制生成一個實作代理接口的匿名類,在調用具體方法前調用InvokeHandler來處理, 而 cglib 動态代理是利用 asm 開源包,對代理對象類對class檔案加載進來,通過修改其位元組碼生成子類來處理。
Spring中:
- 如果目标對象實作類接口,預設情況下會采用JDK的動态代理實作AOP
- 如果目标對象實作類接口,可以強制使用CGLIB實作AOP
-
如果目标對象沒有實作了接口,必須采用CGLIB庫,spring 會字段在JDK動态代理和CGLIB轉換,JDK動态代理隻能對實作了接口對類生成代理,而不能針對類,
CGLIB是針對類實作代理,主要是對指定對類生成一個子類,覆寫其中對方法
因為是繼承,是以該類或方法最好不要聲明成final,final可以阻止繼承和多态
個人部落格位址:
http://blog.yanxiaolong.cn/