代理模式是一种设计模式,提供了对目标对象额外的访问方式,即通过代理对象访问目标对象,这样可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。
简言之,代理模式就是设置一个中间代理来控制访问原目标对象,以达到增强原对象的功能和简化访问方式。
代理模式UML类图
动态代理JDK版
动态代理利用了JDK标准库API,动态地在内存中构建代理对象,从而实现对目标对象的代理功能。动态代理又被称为JDK代理或接口代理。
静态代理与动态代理的区别主要在:
1、静态代理在编译时就已经实现,编译完成后代理类是一个实际的class文件
2、动态代理是在运行时动态生成的,即编译完成后没有实际的class文件,而是在运行时动态生成类字节码,并加载到JVM中
特点:
动态代理对象不需要实现接口,但是要求目标对象必须实现接口,否则不能使用动态代理。
JDK中生成代理对象主要涉及的类
java.lang.reflect.Proxy
/** * 创建代理实例 * * @param loader 目标对象类加载器 * @param interfaces 目标对象实现的接口类 * @param invocationHandler 事件处理器 * @return 返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序 */ public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler invocationHandler);
java.lang.reflect.InvocationHandler
/** * 代理实例上处理方法调用并返回结果 * * @param proxy 代理对象 * @param method 方法 * @param args 方法参数 * @return Object * @throws Throwable 异常 */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
动态代理JDK版代码示例
AccountDao接口类
package com.github.xuchengen.proxy.statics; /** * 账户表数据访问层接口 * 作者:徐承恩 * 邮箱:xuchengen@gmail.com * 日期:2020/4/1 2:03 下午 */ public interface AccountDao { /** * 保存 */ void save(); }
AccountDaoImpl接口实现类
package com.github.xuchengen.proxy.statics; /** * 账户表数据访问层接口实现 * 作者:徐承恩 * 邮箱:xuchengen@gmail.com * 日期:2020/4/1 2:04 下午 */ public class AccountDaoImpl implements AccountDao { @Override public void save() { System.out.println("保存账户数据"); } }
ProxyFactory代理工厂类
package com.github.xuchengen.proxy.statics; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; /** * 代理工厂类 * 作者:徐承恩 * 邮箱:xuchengen@gmail.com * 日期:2020/4/1 3:33 下午 */ public class ProxyFactory { private Object target; public ProxyFactory(Object target) { this.target = target; } /** * 为目标对象生成代理对象 * * @param invocationHandler 事件处理器 * @return Object */ public Object getProxyInstance(InvocationHandler invocationHandler) { return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), invocationHandler); } }
JDKDynamicProxyTest测试类
package com.github.xuchengen.proxy.statics; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * JDK动态代理测试 * 作者:徐承恩 * 邮箱:xuchengen@gmail.com * 日期:2020/4/1 3:39 下午 */ public class JDKDynamicProxyTest { public static void main(String[] args) { AccountDao accountDao = new AccountDaoImpl(); ProxyFactory proxyFactory = new ProxyFactory(accountDao); AccountDao proxyInstance = (AccountDao) proxyFactory.getProxyInstance(new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { System.out.println("开启事务"); method.invoke(accountDao, args); System.out.println("提交事务"); } catch (Exception e) { System.out.println("事务回滚"); } return null; } }); proxyInstance.save(); } }
控制台输出
开启事务 保存账户数据 提交事务