天天看點

設計模式--代理模式代理模式

@[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();
    }           
設計模式--代理模式代理模式

動态代理

什麼是動态代理

**1.代理對象,不需要實作接口

2.代理對象的生成,是利用JDK的API,動态的在記憶體中建構代理對象(需要我們指定建立代理對象/目标對象實作的接口的類型)

3.動态代理也叫做:JDK代理,接口代理**

JDK動态代理

  1. 原理:是根據類加載器和接口建立代理類(此代理類是接口的實作類,是以必須使用接口
  2. 面向接口生成代理,位于java.lang.reflect包下) 2)實作方式:
  3. 通過實作InvocationHandler接口建立自己的調用處理器 IvocationHandler handler = new InvocationHandlerImpl(…);
  4. 通過為Proxy類指定ClassLoader對象和一組interface建立動态代理類Class clazz = Proxy.getProxyClass(classLoader,new Class[]{…});
  5. 通過反射機制擷取動态代理類的構造函數,其參數類型是調用處理器接口類型Constructor constructor = clazz.getConstructor(new Class[]{InvocationHandler.class});
  6. 通過構造函數建立代理類執行個體,此時需将調用處理器對象作為參數被傳入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中:

  1. 如果目标對象實作類接口,預設情況下會采用JDK的動态代理實作AOP
  2. 如果目标對象實作類接口,可以強制使用CGLIB實作AOP
  3. 如果目标對象沒有實作了接口,必須采用CGLIB庫,spring 會字段在JDK動态代理和CGLIB轉換,JDK動态代理隻能對實作了接口對類生成代理,而不能針對類,

    CGLIB是針對類實作代理,主要是對指定對類生成一個子類,覆寫其中對方法

因為是繼承,是以該類或方法最好不要聲明成final,final可以阻止繼承和多态

個人部落格位址:

http://blog.yanxiaolong.cn/