文章内容
一、什么是代理模式
代理模式,为目标对象提供一个替身,以控制对这个对象的访问,进行附加功能增强,从而达到扩展目标对象的功能。比如:添加日志、事务控制、程序耗时等等。
二、代理模式角色
- 抽象角色:定义代理角色和真实角色的公共对外方法。
- 真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理对象调用。
- 代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以增加前置和后置操作。
三、代理模式UML图

四、代理模式实现方式
- 静态代理:被代理对象(即目标对象)和代理对象需要实现共同的接口或继承共同的抽象类,同时代理对象需要关联目标对象。
- JDK动态代理:目标对象需要实现接口,代理对象不需要实现接口。利用JDK自带的Proxy类在运行时动态生成代理对象。
- Cglib动态代理:CGLIB代理也叫子类代理,在JVM运行时,在内存中动态的基于目标类创建一个子类对象,从而实现对目标对象的增强。CGLIB是通过使用字节码处理框架ASM来转换字节码并生成新的类。
五、静态代理优缺点
1、优点
- 避免了直接修改目标对象的功能,以代理模式对目标对象进行了功能扩展。
2、缺点
- 代理类需要与目标对象一一对应,可能会产生“类爆炸”,维护工作量巨大。
- 如果目标对象新增功能,代理类也要同步进行新增升级,可谓牵一发而动全身。
六、JDK动态代理Proxy类详解
JDK自带的代理类包路径java.lang.reflect.Proxy,调用静态方法newProxyInstance方法动态生成代理对象,该方法包括3个形参:
1 | public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException |
- ClassLoader loader: 指定目标对象所使用的类加载器,用于加载代理类。
- Class<?>[] interfaces: 目标对象实现的接口类,通过泛型确定类型,也是代理类实现的接口类。
- InvocationHandler h: 代理对象的调用处理程序,执行目标对象的方法,会把当前执行的目标对象 的方法作为参数传入。调用invoke方法进行增强业务处理。
1 | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; |
- Object proxy:代理对象,在该方法中基本不用。
- Method method:目标对象的方法,对接口中的方法进行封装的method对象。
- Object[] args:调用目标对象方法的实际参数。
七、CGLIB动态代理
1、为啥要使用CGLIB
如果需要被代理的目标对象没有实现接口,这时就不能使用静态代理或JDK动态代理来实现了。这时,CGLIB就要登场了,它提供了一个功能强大、高性能的代码生成包,它可以为没有实现接口的普通类提供代理,弥补了JDK动态代理的不足。
2、使用CGLIB代理注意事项
- 被代理的目标对象不能为final
- 被代理的目标对象的方法不能被final、static修饰
3、引入CGLIB jar 包
1 2 3 4 5 | < dependency > < groupId >cglib</ groupId > < artifactId >cglib</ artifactId > < version >2.2</ version > </ dependency > |
4、CGLIB 2个核心类
- net.sf.cglib.proxy.Enhancer:用于动态生成代理对象,作用类似JDK代理中的Proxy类。
- net.sf.cglib.proxy.MethodInterceptor:目标对象的拦截器,用于实现对目标对象的功能增强。
八、代理模式demo示例
1、Demo需求
以用户管理为例,对用户功能进行增强,添加方法入口日志和结束日志。
2、静态代理模式代码实现
1 2 3 4 5 6 7 8 | /** * 用户管理接口 */ public interface IUserService { void insert(); void print(); } |
01 02 03 04 05 06 07 08 09 10 11 12 13 14 | /** * 用户管理实现类 */ public class UserServiceImpl implements IUserService { @Override public void insert() { System.out.println( "新增一个用户" ); } @Override public void print() { System.out.println( "打印用户信息" ); } } |
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | /** * 用户管理静态代理类 * */ public class UserServiceProxy implements IUserService { private IUserService userService; public UserServiceProxy(IUserService userService) { this .userService = userService; } /** * 对原有insert功能进行增强,增加日志信息 */ @Override public void insert() { System.out.println( "新增用户开始" ); userService.insert(); System.out.println( "新增用户成功。" ); } /** * 对原有print功能进行增强,增加日志信息 */ @Override public void print() { System.out.println( "输出用户信息开始" ); userService.print(); System.out.println( "输出用户信息完成。" ); } } |
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 | public class ClientTest { public static void main(String[] args) { //创建目标对象 IUserService userService = new UserServiceImpl(); //创建代理对象 IUserService userServiceProxy = new UserServiceProxy(userService); //调用方法 userServiceProxy.print(); System.out.println( "====================================" ); userServiceProxy.insert(); } } |
控制台输入日志:
1 2 3 4 5 6 7 | 输出用户信息开始 打印用户信息 输出用户信息完成。 ==================================== 新增用户开始 新增一个用户 新增用户成功。 |
3、JDK动态代理模式代码实现
1 2 3 4 5 6 7 8 | /** * 用户管理接口 */ public interface IUserService { void insert(); void print(); } |
01 02 03 04 05 06 07 08 09 10 11 12 13 14 | /** * 用户管理实现类 */ public class UserServiceImpl implements IUserService { @Override public void insert() { System.out.println( "新增一个用户" ); } @Override public void print() { System.out.println( "打印用户信息" ); } } |
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | /** * 代理对象的工厂类 */ public class UserServiceProxyFactory { private IUserService userService; public UserServiceProxyFactory(IUserService userService) { this .userService = userService; } public IUserService getProxyObject(){ return (IUserService) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), userService.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println( "进入方法,记录日志" ); Object result = method.invoke(userService, args); System.out.println( "结束方法,记录日志" ); return result; } }); } } |
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 | public class Client { public static void main(String[] args) { //创建目标对象 IUserService userService = new UserServiceImpl(); // 创建代理对象 IUserService proxyObject = new UserServiceProxyFactory(userService).getProxyObject(); System.out.println(proxyObject.getClass()); System.out.println( "========================" ); //调用方法 proxyObject.insert(); System.out.println( "========================" ); proxyObject.print(); } } |
控制台输入日志:
1 2 3 4 5 6 7 8 9 | class com.sun.proxy.$Proxy0 ======================== 进入方法,记录日志 新增一个用户 结束方法,记录日志 ======================== 进入方法,记录日志 打印用户信息 结束方法,记录日志 |
可以看到动态代理对象的class 带有 $Proxy 标识:class com.sun.proxy.$Proxy0
4、CGLIB动态代理模式代码实现
01 02 03 04 05 06 07 08 09 10 11 12 | /** * 用户管理类,被代理的目标类 */ public class UserService { public void add(String name) { System.out.println( "新增了一个用户: " + name); } public void print() { System.out.println( "打印用户信息..." ); } } |
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | /** * 用户代理对象工厂类,用来获取代理对象 */ public class UserProxyFactory<T> { //目标对象,使用泛型 private T target; /** * 初始化工厂类使,指定被代理的目标对象 * @param target */ public UserProxyFactory(T target) { this .target = target; } /** * 获取代理对象 * * @return */ public T getProxyObj(){ // 创建enhancer对象,等价于JDK代理中的Proxy类 Enhancer enhancer = new Enhancer(); //设置父类的字节码对象 enhancer.setSuperclass(UserService. class ); //设置回调函数 enhancer.setCallback( new MethodInterceptor() { /** * 用于实现对目标对象的功能增强,类似于JDK代理中的InvocationHandler中的invoke方法 * * @param o * @param method * @param objects * @param methodProxy * @return * @throws Throwable */ @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println( "调用方法前,写入日志" ); Object result = method.invoke(target, objects); System.out.println( "调用方法结束,写入日志" ); return result; } }); // 生成代理对象 return (T) enhancer.create(); } } |
01 02 03 04 05 06 07 08 09 10 11 | /** * CGLIB 客户端测试类 * */ public class CGLIBClient { public static void main(String[] args) { UserService userService = new UserProxyFactory<UserService>( new UserService()).getProxyObj(); System.out.println( "代理对象class= " + userService.getClass()); System.out.println( "=======================" ); userService.add( "lisi" ); } } |
控制台输入日志:
1 2 3 4 5 | 代理对象class= class com.ford.proxy.dynamic.cglib.UserService$$EnhancerByCGLIB$$91d7e1dc ======================= 调用方法前,写入日志 新增了一个用户: lisi 调用方法结束,写入日志 |
可以看到,CGLIB代理对象带有:$$EnhancerByCGLIB$$,而JDK动态代理的代理对象代用:$Proxy,这一点可以判断代理对象到底使用了哪种代理实现方式。