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实现,接口不是必须的

posted @ 2018-11-30 19:38  冰糖小城  阅读(217)  评论(0编辑  收藏  举报