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

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

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

服務(wù)器之家 - 編程語言 - Java教程 - 淺談Java代理(jdk靜態(tài)代理、動(dòng)態(tài)代理和cglib動(dòng)態(tài)代理)

淺談Java代理(jdk靜態(tài)代理、動(dòng)態(tài)代理和cglib動(dòng)態(tài)代理)

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

下面小編就為大家?guī)硪黄獪\談Java代理(jdk靜態(tài)代理、動(dòng)態(tài)代理和cglib動(dòng)態(tài)代理)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧

一、代理是Java常用的設(shè)計(jì)模式,代理類通過調(diào)用被代理類的相關(guān)方法,并對(duì)相關(guān)方法進(jìn)行增強(qiáng)。加入一些非業(yè)務(wù)性代碼,比如事務(wù)、日志、報(bào)警發(fā)郵件等操作。

二、jdk靜態(tài)代理

1、業(yè)務(wù)接口

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

2、業(yè)務(wù)實(shí)現(xiàn)類

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

3、代理類

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

private UserServiceImpl userImpl;

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

public void addUser() {
System.out.println("代理類方法,進(jìn)行了增強(qiáng)。。。");
System.out.println("事務(wù)開始。。。");
// 調(diào)用委托類的方法;
userImpl.addUser();
System.out.println("處理結(jié)束。。。");
}

public void editUser() {
System.out.println("代理類方法,進(jìn)行了增強(qiáng)。。。");
System.out.println("事務(wù)開始。。。");
// 調(diào)用委托類的方法;
userImpl.editUser();
System.out.println("事務(wù)結(jié)束。。。");
}

}
  

4、測(cè)試類

?
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、結(jié)果

代理類方法,進(jìn)行了增強(qiáng)。。。

事務(wù)開始。。。
增加一個(gè)用戶。。。
處理結(jié)束。。。

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

代理類方法,進(jìn)行了增強(qiáng)。。。
事務(wù)開始。。。
編輯一個(gè)用戶。。。
事務(wù)結(jié)束。。。
  

三、jdk動(dòng)態(tài)代理

1、業(yè)務(wù)接口

 

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

2、業(yè)務(wù)接口實(shí)現(xiàn)類

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

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 {
 
  // 目標(biāo)對(duì)象
  private Object target;
 
  public ServiceInvocationHandler(Object target) {
    super();
    this.target = target;
  }
 
  /**
   * 創(chuàng)建代理實(shí)例
   * @return
   * @throws Throwable
   */
  public Object getProxy() throws Throwable {
    return Proxy.newProxyInstance(Thread.currentThread()
        .getContextClassLoader(), this.target.getClass()
        .getInterfaces(), this);
    // 這樣寫只返回了目標(biāo)對(duì)象,沒有生成代理對(duì)象。
    // return target;
  }
 
  /**
   * 實(shí)現(xiàn)InvocationHandler接口方法
   * 執(zhí)行目標(biāo)對(duì)象的方法,并進(jìn)行增強(qiáng)
   */
  public Object invoke(Object proxy, Method method, Object[] args)
      throws Throwable {
    Object result = null;
    System.out.println("代理類方法,進(jìn)行了增強(qiáng)。。。");
    System.out.println("事務(wù)開始。。。");
    // 執(zhí)行目標(biāo)方法對(duì)象
    result = method.invoke(target, args);
    System.out.println("事務(wù)結(jié)束。。。");
    return result;
  }
 
}

4、測(cè)試類

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Test {
  /**
   * jdk動(dòng)態(tài)代理會(huì)生成一個(gè)動(dòng)態(tài)代理類,生成相應(yīng)的字節(jié)碼,然后通過ClassLoader加載字節(jié)碼。
   * 該實(shí)例繼承了Proxy類,并實(shí)現(xiàn)了業(yè)務(wù)接口,在實(shí)現(xiàn)的方法里通過反射調(diào)用了InvocationHandler接口實(shí)現(xiàn)類
   * 的invoke()回調(diào)方法。
   * @param args
   * @throws Throwable
   */
  public static void main(String[] args) throws Throwable {
    UserService userService = new UserServiceImpl();
    ServiceInvocationHandler handler = new ServiceInvocationHandler(userService);
    // 根據(jù)目標(biāo)生成代理對(duì)象
    UserService proxy = (UserService) handler.getProxy();
    proxy.addUser();
//   proxy.editUser();
 
  }
 
}

5、測(cè)試結(jié)果

代理類方法,進(jìn)行了增強(qiáng)。。。
事務(wù)開始。。。
增加一個(gè)用戶。。。
事務(wù)結(jié)束。。。

四、cglib動(dòng)態(tài)代理

需要引入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、業(yè)務(wù)類,沒有實(shí)現(xiàn)接口

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

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動(dòng)態(tài)代理
 * @author pc
 *
 */
public class UserServiceCglib implements MethodInterceptor{
 
  private Object target;
   
  /**
   * 創(chuàng)建代理實(shí)例
   * @param target
   * @return
   */
  public Object getInstance(Object target){
    this.target = target;
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(this.target.getClass());
    // 設(shè)置回調(diào)方法
    enhancer.setCallback(this);
    // 創(chuàng)建代理對(duì)象
    return enhancer.create();
  }
   
  /**
   * 實(shí)現(xiàn)MethodInterceptor接口要重寫的方法。
   * 回調(diào)方法
   */
  public Object intercept(Object obj, Method method, Object[] args,
      MethodProxy proxy) throws Throwable {
    System.out.println("事務(wù)開始。。。");  
    Object result = proxy.invokeSuper(obj, args);  
    System.out.println("事務(wù)結(jié)束。。。");  
    return result;  
  }
 
}

3、測(cè)試類

?
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、結(jié)果:

事務(wù)開始。。。
增加一個(gè)用戶。。。
事務(wù)結(jié)束。。。

5、如果業(yè)務(wù)實(shí)現(xiàn)類被定義成final類,就會(huì)報(bào)以下錯(cuò)誤

?
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)

五、總結(jié)

1、原理

jdk靜態(tài)代理實(shí)現(xiàn)比較簡(jiǎn)單,一般是直接代理對(duì)象直接包裝了被代理對(duì)象。

jdk動(dòng)態(tài)代理是接口代理,被代理類A需要實(shí)現(xiàn)業(yè)務(wù)接口,業(yè)務(wù)代理類B需要實(shí)現(xiàn)InvocationHandler接口。

jdk動(dòng)態(tài)代理會(huì)根據(jù)被代理對(duì)象生成一個(gè)繼承了Proxy類,并實(shí)現(xiàn)了該業(yè)務(wù)接口的jdk代理類,該類的字節(jié)碼會(huì)被傳進(jìn)去的ClassLoader加載,創(chuàng)建了jdk代理對(duì)象實(shí)例,

jdk代理對(duì)象實(shí)例在創(chuàng)建時(shí),業(yè)務(wù)代理對(duì)象實(shí)例會(huì)被賦值給Proxy類,jdk代理對(duì)象實(shí)例也就有了業(yè)務(wù)代理對(duì)象實(shí)例,同時(shí)jdk代理對(duì)象實(shí)例通過反射根據(jù)被代理類的業(yè)務(wù)方法創(chuàng)建了相應(yīng)的Method對(duì)象m(可能有多個(gè))。當(dāng)jdk代理對(duì)象實(shí)例調(diào)用業(yè)務(wù)方法,如proxy.addUser();這個(gè)會(huì)先把對(duì)應(yīng)的m對(duì)象作為參數(shù)傳給invoke()方法(就是invoke方法的第二個(gè)參數(shù)),調(diào)用了jdk代理對(duì)象實(shí)例的invoke()回調(diào)方法,在invoke方法里面再通過反射來調(diào)用被代理對(duì)象的因?yàn)榉椒ǎ磖esult = method.invoke(target, args);。

cglib動(dòng)態(tài)代理是繼承代理,通過ASM字節(jié)碼框架修改字節(jié)碼生成新的子類,重寫并增強(qiáng)方法的功能。

2、優(yōu)缺點(diǎn)

jdk靜態(tài)代理類只能為一個(gè)被代理類服務(wù),如果需要代理的類比較多,那么會(huì)產(chǎn)生過多的代理類。jdk靜態(tài)代理在編譯時(shí)產(chǎn)生class文件,運(yùn)行時(shí)無需產(chǎn)生,可直接使用,效率好。

jdk動(dòng)態(tài)代理必須實(shí)現(xiàn)接口,通過反射來動(dòng)態(tài)代理方法,消耗系統(tǒng)性能。但是無需產(chǎn)生過多的代理類,避免了重復(fù)代碼的產(chǎn)生,系統(tǒng)更加靈活。

cglib動(dòng)態(tài)代理無需實(shí)現(xiàn)接口,通過生成子類字節(jié)碼來實(shí)現(xiàn),比反射快一點(diǎn),沒有性能問題。但是由于cglib會(huì)繼承被代理類,需要重寫被代理方法,所以被代理類不能是final類,被代理方法不能是final。

因此,cglib的應(yīng)用更加廣泛一點(diǎn)。

以上這篇淺談Java代理(jdk靜態(tài)代理、動(dòng)態(tài)代理和cglib動(dòng)態(tài)代理)就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持服務(wù)器之家。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: www.在线观看视频 | 国产欧美精品专区一区二区 | 2019中文字幕 | 996热视频 | 青草免费在线 | 精品免费tv久久久久久久 | 国产成人青草视频 | 国产精品国产精品国产三级普 | japanese日本护士 | 爱情岛论坛亚洲一号路线 | 欧美粗黑巨大gay | 亚洲国产99在线精品一区69堂 | 91在线免费播放 | h肉动漫在线视频无修无遮挡 | 国产日产韩产麻豆1区 | 高清不卡日本v在线二区 | 好男人好资源在线观看 | 精品久久成人 | 国产一区二区视频在线播放 | pregnant欧美孕交xxx | 放荡的女老板bd中文字幕 | 五月天婷婷网亚洲综合在线 | 猫影视tv接口| 亚洲男人的天堂网站 | 白丝女仆被啪到深夜漫画 | 国产乱码在线精品可播放 | 青青青国产手机在线播放 | 午夜香蕉成视频人网站高清版 | 美女视频在线观看视频 | 农夫69小说小雨与农村老太 | 2019自拍偷拍视频 | 91好色| 欧美一区二区三区视视频 | 狠狠色综合久久久久尤物 | www.羞羞答答 | 黑人日白人 | 国产午夜亚洲精品一区网站 | 女班长的放荡日记高h | 三级伦理在线播放 | 亚洲精品免费在线观看 | 亚洲视频在线免费看 |