国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Java > 正文

淺談Java代理(jdk靜態代理、動態代理和cglib動態代理)

2019-11-26 13:11:51
字體:
來源:轉載
供稿:網友

一、代理是Java常用的設計模式,代理類通過調用被代理類的相關方法,并對相關方法進行增強。加入一些非業務性代碼,比如事務、日志、報警發郵件等操作。

二、jdk靜態代理

1、業務接口

/**  * 業務接口  * @author pc  *  */public interface UserService {      // 增加一個用戶   public void addUser();   // 編輯賬戶   public void editUser();  } 

2、業務實現類

/**  * 業務實現類  * @author pc  *  */public class UserServiceImpl implements UserService {    public void addUser() {     System.out.println("增加一個用戶。。。");   }    public void editUser() {     System.out.println("編輯一個用戶。。。");   }  } 

3、代理類

/**
* 代理類
*
* @author pc
*
*/
public class UserServiceProxy implements UserService {

private UserServiceImpl userImpl;

public UserServiceProxy(UserServiceImpl countImpl) {
this.userImpl = countImpl;
}

public void addUser() {
System.out.println("代理類方法,進行了增強。。。");
System.out.println("事務開始。。。");
// 調用委托類的方法;
userImpl.addUser();
System.out.println("處理結束。。。");
}

public void editUser() {
System.out.println("代理類方法,進行了增強。。。");
System.out.println("事務開始。。。");
// 調用委托類的方法;
userImpl.editUser();
System.out.println("事務結束。。。");
}

}
  

4、測試類

public static void main(String[] args) {   UserServiceImpl userImpl = new UserServiceImpl();   UserServiceProxy proxy = new UserServiceProxy(userImpl);   proxy.addUser();   System.out.println("----------分割線----------");   proxy.editUser(); } 

5、結果

代理類方法,進行了增強。。。

事務開始。。。
增加一個用戶。。。
處理結束。。。

----------分割線----------

代理類方法,進行了增強。。。
事務開始。。。
編輯一個用戶。。。
事務結束。。。
  

三、jdk動態代理

1、業務接口

/**  * 業務接口  * @author pc  *  */public interface UserService {      // 增加一個用戶   public void addUser();   // 編輯賬戶   public void editUser();  } 

2、業務接口實現類

/**  * 業務接口實現類  * @author pc  *  */public class UserServiceImpl implements UserService {    public void addUser() {     System.out.println("增加一個用戶。。。");   }    public void editUser() {     System.out.println("編輯一個用戶。。。");   } } 

3、代理類

import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy;  /**  *  * @author pc  *  */public class ServiceInvocationHandler implements InvocationHandler {    // 目標對象   private Object target;    public ServiceInvocationHandler(Object target) {     super();     this.target = target;   }    /**    * 創建代理實例    * @return    * @throws Throwable    */  public Object getProxy() throws Throwable {     return Proxy.newProxyInstance(Thread.currentThread()         .getContextClassLoader(), this.target.getClass()         .getInterfaces(), this);     // 這樣寫只返回了目標對象,沒有生成代理對象。     // return target;   }    /**    * 實現InvocationHandler接口方法    * 執行目標對象的方法,并進行增強    */  public Object invoke(Object proxy, Method method, Object[] args)       throws Throwable {     Object result = null;     System.out.println("代理類方法,進行了增強。。。");     System.out.println("事務開始。。。");     // 執行目標方法對象     result = method.invoke(target, args);     System.out.println("事務結束。。。");     return result;   }  } 

4、測試類

public class Test {   /**    * jdk動態代理會生成一個動態代理類,生成相應的字節碼,然后通過ClassLoader加載字節碼。    * 該實例繼承了Proxy類,并實現了業務接口,在實現的方法里通過反射調用了InvocationHandler接口實現類    * 的invoke()回調方法。    * @param args    * @throws Throwable    */  public static void main(String[] args) throws Throwable {     UserService userService = new UserServiceImpl();     ServiceInvocationHandler handler = new ServiceInvocationHandler(userService);     // 根據目標生成代理對象     UserService proxy = (UserService) handler.getProxy();     proxy.addUser(); //   proxy.editUser();    }  } 

5、測試結果

代理類方法,進行了增強。。。
事務開始。。。
增加一個用戶。。。
事務結束。。。

四、cglib動態代理

需要引入cglib的jar包,

在pom.xml加入依賴:

<!-- https://mvnrepository.com/artifact/cglib/cglib --> <dependency>   <groupId>cglib</groupId>   <artifactId>cglib</artifactId>   <version>2.2.2</version> </dependency> 

  

1、業務類,沒有實現接口

/**  * 業務類  * 沒有實現接口  * 如果類是final的,則沒法生成代理對象,報錯。  * 如果方法是final的,代理無效  * @author pc  *  */public class UserServiceImpl {    public void addUser() {     System.out.println("增加一個用戶。。。");   }    public void editUser() {     System.out.println("編輯一個用戶。。。");   } } 

2、代理類

import java.lang.reflect.Method;  import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy;  /**  * 使用Cglib動態代理  * @author pc  *  */public class UserServiceCglib implements MethodInterceptor{    private Object target;      /**    * 創建代理實例    * @param target    * @return    */  public Object getInstance(Object target){     this.target = target;     Enhancer enhancer = new Enhancer();     enhancer.setSuperclass(this.target.getClass());     // 設置回調方法     enhancer.setCallback(this);     // 創建代理對象     return enhancer.create();   }      /**    * 實現MethodInterceptor接口要重寫的方法。    * 回調方法    */  public Object intercept(Object obj, Method method, Object[] args,       MethodProxy proxy) throws Throwable {     System.out.println("事務開始。。。");       Object result = proxy.invokeSuper(obj, args);       System.out.println("事務結束。。。");       return result;     }  } 

3、測試類

public class TestCglib {    public static void main(String[] args) {     UserServiceCglib cglib = new UserServiceCglib();     UserServiceImpl bookFacadeImpl = (UserServiceImpl)cglib.getInstance(new UserServiceImpl());     bookFacadeImpl.addUser(); //   bookFacadeImpl.editUser();   } } 

4、結果:

事務開始。。。
增加一個用戶。。。
事務結束。。。

5、如果業務實現類被定義成final類,就會報以下錯誤

Exception in thread "main" java.lang.IllegalArgumentException: Cannot subclass final class class cn.xx.xx.cgilb.UserServiceImpl   at net.sf.cglib.proxy.Enhancer.generateClass(Enhancer.java:446)   at net.sf.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)   at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:216)   at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:377)   at net.sf.cglib.proxy.Enhancer.create(Enhancer.java:285)   at cn.pconline.proxy.cgilb.UserServiceCglib.getInstance(UserServiceCglib.java:30)   at cn.pconline.proxy.cgilb.TestCglib.main(TestCglib.java:7) 

五、總結

1、原理

jdk靜態代理實現比較簡單,一般是直接代理對象直接包裝了被代理對象。

jdk動態代理是接口代理,被代理類A需要實現業務接口,業務代理類B需要實現InvocationHandler接口。

jdk動態代理會根據被代理對象生成一個繼承了Proxy類,并實現了該業務接口的jdk代理類,該類的字節碼會被傳進去的ClassLoader加載,創建了jdk代理對象實例,

jdk代理對象實例在創建時,業務代理對象實例會被賦值給Proxy類,jdk代理對象實例也就有了業務代理對象實例,同時jdk代理對象實例通過反射根據被代理類的業務方法創建了相應的Method對象m(可能有多個)。當jdk代理對象實例調用業務方法,如proxy.addUser();這個會先把對應的m對象作為參數傳給invoke()方法(就是invoke方法的第二個參數),調用了jdk代理對象實例的invoke()回調方法,在invoke方法里面再通過反射來調用被代理對象的因為方法,即result = method.invoke(target, args);。

cglib動態代理是繼承代理,通過ASM字節碼框架修改字節碼生成新的子類,重寫并增強方法的功能。

2、優缺點

jdk靜態代理類只能為一個被代理類服務,如果需要代理的類比較多,那么會產生過多的代理類。jdk靜態代理在編譯時產生class文件,運行時無需產生,可直接使用,效率好。

jdk動態代理必須實現接口,通過反射來動態代理方法,消耗系統性能。但是無需產生過多的代理類,避免了重復代碼的產生,系統更加靈活。

cglib動態代理無需實現接口,通過生成子類字節碼來實現,比反射快一點,沒有性能問題。但是由于cglib會繼承被代理類,需要重寫被代理方法,所以被代理類不能是final類,被代理方法不能是final。

因此,cglib的應用更加廣泛一點。

以上這篇淺談Java代理(jdk靜態代理、動態代理和cglib動態代理)就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 大冶市| 固阳县| 永济市| 商南县| 集贤县| 乌海市| 定安县| 西畴县| 深圳市| 安丘市| 平舆县| 泰来县| 泗阳县| 永川市| 济源市| 凉山| 上林县| 金华市| 阿合奇县| 炉霍县| 陆河县| 进贤县| 阳东县| 威宁| 宜城市| 沾化县| 和田县| 金塔县| 嘉峪关市| 抚顺县| 夏河县| 祁门县| 延吉市| 乌审旗| 通河县| 香港| 彭水| 福建省| 乌兰县| 喀喇| 东乡县|