前言
上篇我们演示了使用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 = 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("登录账号:"+ +"生成订单成功");
21
22 }
23
24 public void pay() {
25
26 System.out.println("登录账号:"+ +"订单支付成功");
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实现,接口不是必须的。