Java設計模式之代理模式的動態代理下篇
阿新 • • 發佈:2018-11-30
前言
上篇我們演示了使用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 12public 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實現,介面不是必須的。