一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - 淺談Java代理(jdk靜態代理、動態代理和cglib動態代理)

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

2020-07-30 16:15jingxian Java教程

下面小編就為大家帶來一篇淺談Java代理(jdk靜態代理、動態代理和cglib動態代理)。小編覺得挺不錯的,現在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

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

二、jdk靜態代理

1、業務接口

?
1
2
3
4
5
6
7
8
9
10
11
12
13
/**
 * 業務接口
 * @author pc
 *
 */
public interface UserService {
   
  // 增加一個用戶
  public void addUser();
  // 編輯賬戶
  public void editUser();
 
}

2、業務實現類

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
 * 業務實現類
 * @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、測試類

?
1
2
3
4
5
6
7
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、業務接口

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
/**
 * 業務接口
 * @author pc
 *
 */
public interface UserService {
   
  // 增加一個用戶
  public void addUser();
  // 編輯賬戶
  public void editUser();
 
}

2、業務接口實現類

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
 * 業務接口實現類
 * @author pc
 *
 */
public class UserServiceImpl implements UserService {
 
  public void addUser() {
    System.out.println("增加一個用戶。。。");
  }
 
  public void editUser() {
    System.out.println("編輯一個用戶。。。");
  }
}

3、代理類

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
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、測試類

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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加入依賴:

?
1
2
3
4
5
6
<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
  <groupId>cglib</groupId>
  <artifactId>cglib</artifactId>
  <version>2.2.2</version>
</dependency>

  

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
 * 業務類
 * 沒有實現接口
 * 如果類是final的,則沒法生成代理對象,報錯。
 * 如果方法是final的,代理無效
 * @author pc
 *
 */
public class UserServiceImpl {
 
  public void addUser() {
    System.out.println("增加一個用戶。。。");
  }
 
  public void editUser() {
    System.out.println("編輯一個用戶。。。");
  }
}

2、代理類

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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、測試類

?
1
2
3
4
5
6
7
8
9
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類,就會報以下錯誤

?
1
2
3
4
5
6
7
8
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動態代理)就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持服務器之家。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 娇妻终于接受了3p的调教 | 男人的j放进女人的p全黄 | 日韩丝袜在线观看 | 性关系视频网站 | 国产一区二区三区在线 | ass老妇黑森林pic | 国产一区二区视频在线 | 欧美一级欧美一级高清 | 99爱视频 | 手机国产乱子伦精品视频 | 国产精品露脸国语对白手机视频 | 精品国产线拍大陆久久尤物 | 王雨纯羞羞 | 欧美成人福利 | 免费在线观看成年人视频 | 精品视频一区二区三区免费 | 疯狂伦交1一6小说 | 我们日本在线观看免费动漫下载 | caoporn超碰| 成人男女啪啪免费观看网站 | 日本国产在线视频 | 天天做日日爱 | 操日日| wc凹凸撒尿间谍女厕hd | 国产成人精品在线观看 | 全色黄大色黄大片爽一次 | 俄罗斯一级毛片免费播放 | avav男人天堂| 日本老师xxxxx18 | 国产福利一区二区精品视频 | 校园全黄h全肉细节文 | 欧美亚洲国产另类在线观看 | 日本免费三片在线播放 | 91寡妇天天综合久久影院 | 四虎成人国产精品视频 | 精品视频一区二区三区 | 亚洲上最大成网人站4438 | 久久伊人在 | 九九九国产视频 | 久久精品国产亚洲AV蜜臀 | 校花被拖到野外伦小说 |