1. 程式人生 > >Java設計模式之代理模式的動態代理下篇

Java設計模式之代理模式的動態代理下篇

前言

上篇我們演示了使用JDK的InvocationHandler實現動態代理,本文我們採用cglib來實現動態代理。

 

動態代理示例

運用JDK的InvocationHandler是根據抽象介面來實現的,然而基於cglib來實現動態代理,被代理角色可以是一個普通的類,也可以是一個介面的實現類,總之,是基於類來實現的。

首先我們在pom檔案中增加cglib依賴:

1 <dependency>
2     <groupId>cglib</groupId>
3     <artifactId>cglib</artifactId>
4
<version>3.2.9</version> 5 </dependency>

我們增加一個沒有介面的真實角色:

 1 public class RealConsumer {
 2 
 3     private String name = null;
 4 
 5     public RealConsumer(String name){
 6         this.name = name;
 7     }
 8 
 9     public RealConsumer() {
10     }
11 
12
public void login(String name, String password) { 13 14 System.out.println("登入使用者["+name+"]登陸成功"); 15 } 16 17 public void order() { 18 19 20 System.out.println("登入賬號:"+ this.name +"生成訂單成功"); 21 22 } 23 24 public void pay() { 25 26 System.out.println("登入賬號:"+ this
.name +"訂單支付成功"); 27 28 } 29 30 }

我們再來新增一個實現代理的攔截類,這個攔截類需要實現MethodInterceptor介面。

 1 package com.example.pattern.proxy.dynamic.cglib;
 2 
 3 
 4 
 5 
 6 
 7 import net.sf.cglib.proxy.Enhancer;
 8 import net.sf.cglib.proxy.MethodInterceptor;
 9 import net.sf.cglib.proxy.MethodProxy;
10 
11 import java.lang.reflect.Method;
12 
13 public class ConsumerIntercepor implements MethodInterceptor {
14 
15 
16     private Object proxiedInstance;
17 
18     public Object getInstance (Object proxiedInstance) {
19         this.proxiedInstance = proxiedInstance;
20 
21         Enhancer enhancer = new Enhancer();
22         enhancer.setSuperclass(this.proxiedInstance.getClass());
23 
24         enhancer.setCallback(this);
25         return enhancer.create();
26     }
27 
28     @Override
29     public Object intercept(Object object, Method method, Object[] args, MethodProxy proxy) throws Throwable {
30 
31         System.out.println("前置操作");
32 
33         proxy.invokeSuper(object, args);
34 
35         System.out.println("後置操作");
36 
37         return null;
38     }
39 }

第13行,這個攔截類實現了MethodInterceper介面。

第16行,宣告被代理物件。

第18行,獲取到代理物件。

第21行,建立加強器,用於建立動態代理類。

第22行,指定代理類的父類,也就是被代理類。

第24行,設定回撥,這個回撥就是呼叫上面的interceper方法。

第25行,建立動態代理類物件並且返回。

 

我們再來建立一個場景類。

 1 public class Client {
 2 
 3     public static void main(String[] args) {
 4         RealConsumer realConsumer = new RealConsumer("抒盡");
 5 
 6         ConsumerIntercepor intercepor = new ConsumerIntercepor();
 7         RealConsumer proxy = (RealConsumer)intercepor.getInstance(realConsumer);
 8 
 9         proxy.login("shujin", "123456");
10         proxy.order();
11         proxy.pay();
12 
13 
14     }
15 }

 

我們先來看一下執行結果。

 1 ---------前置操作---------
 2 登入使用者[shujin]登陸成功
 3 ---------後置操作---------
 4 
 5 ---------前置操作---------
 6 登入賬號:null生成訂單成功
 7 ---------後置操作---------
 8 
 9 ---------前置操作---------
10 登入賬號:null訂單支付成功
11 ---------後置操作---------

 

出現了一個問題,我們最先賦值的[抒盡]為什麼是空值呢??

因為name是成員屬性,是跟隨著物件而存在,原始物件和代理物件不是同一個物件,因此代理物件proxy中的name當然為空。除非proxy.setName("xxx");之後,name在代理物件中才不會為空。

這個現象也從側面說明了jdk實現和cglib實現的不同。cglib實現的動態代理是繼承了被代理物件,因此代理和被代理的關係等價於子類和父類之間的關係。另外因為是使用繼承關係實現動態代理,那麼被final修飾的類不可以被代理。

 

最後,要實現動態代理,如果是jdk實現,必須要有一個介面,而cglib實現,介面不是必須的