代理模式是一种设计模式,提供了对目标对象额外的访问方式,即通过代理对象访问目标对象,这样可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。
简言之,代理模式就是设置一个中间代理来控制访问原目标对象,以达到增强原对象的功能和简化访问方式。
代理模式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();
}
}
控制台输出
开启事务
保存账户数据
提交事务