前言
上篇我们演示了使用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实现,接口不是必须的。