前言
代理模式(英语:Proxy Pattern)是程序设计中的一种设计模式。
所谓的代理者是指一个类别可以作为其它东西的接口。代理者可以作任何东西的接口:网上连接、存储器中的大对象、文件或其它昂贵或无法复制的资源。
代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
在Java中,存在以下三种代理模式:
静态代理
在使用静态代理时,被代理对象与代理对象需要一起实现相同的接口或者是继承相同父类,因此要定义一个接口或抽象类.
代理类:
/*
* 静态代理实现
*
* 代理类
*/
public class DemoDAOProxy implements IDemoDAO{
// 被代理的目标对象
private DemoDAOImpl target = new DemoDAOImpl();
@Override
public int executeInsert() {
long beginTime = System.currentTimeMillis();
System.out.println("[增强功能]:executeInsert方法于" + new Date()+"开始执行....");
// 调用被代理对象(target)
int rows = target.executeInsert();
long endTime = System.currentTimeMillis();
System.out.println("[增强功能]:executeInsert方法于" + new Date()+"结束执行!!!!");
System.out.println("[增强功能]:共耗时" + (endTime - beginTime) + "毫秒!");
return rows;
}
@Override
public int executeUpdate() {
long beginTime = System.currentTimeMillis();
System.out.println("[增强功能]:executeInsert方法于" + new Date()+"开始执行....");
// 调用被代理对象(target)
int rows = target.executeUpdate();
long endTime = System.currentTimeMillis();
System.out.println("[增强功能]:executeInsert方法于" + new Date()+"结束执行!!!!");
System.out.println("[增强功能]:共耗时" + (endTime - beginTime) + "毫秒!");
return rows;
}
}
被代理类:
/*
* 被代理类(target)
*/
public class DemoDAOImpl implements IDemoDAO{
@Override
public int executeInsert() {
System.out.println("[数据访问操作]:1.连接数据库");
System.out.println("[数据访问操作]:2.执行Insert SQL");
System.out.println("[数据访问操作]:3.处理结果");
//int number = 1/0;
return -1;
}
@Override
public int executeUpdate() {
System.out.println("[数据访问操作]:1.连接数据库");
System.out.println("[数据访问操作]:2.执行Update SQL");
System.out.println("[数据访问操作]:3.处理结果");
return -1;
}
}
接口:
public interface IDemoDAO {
public int executeInsert();
public int executeUpdate();
}
特点总结:
优点:可以实现对目标代理。
缺点:需要一一代理,所以会产生很多代理类。而且,一旦接口增加方法,所有目标对象与代理对象都需要维护。
动态代理
动态代理工厂
基于JDK的反射机制: 需要Proxy类 + 实现InvocationHandler接口
public class JdkProxyFactory implements InvocationHandler {
// 目标对象
private Object target;
// 构造方法
// 传入目标对象
public JdkProxyFactory(Object target) {
this.target = target;
}
// 创建"动态代理对象"
public Object createProxy() {
// 1.获取目标对象的Class对象
Class targetClass = target.getClass();
// 2. 通过 java.lang.reflect.Proxy 创建一个新的动态代理实例对象
// 参数1:目标对象的Class对象的ClassLoader
// 参数2:目标对象的实现接口(数组)
// 参数3: InvocationHandler接口实现类(当前类)
Object newProxy = Proxy.newProxyInstance(targetClass.getClassLoader(),
targetClass.getInterfaces(),
this);
return newProxy;
}
/*
* 参数1 proxy :当前产生的代理对象
* 参数2 method :目标方法
* 参数3 args : 目标方法的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long beginTime = System.currentTimeMillis();
System.out.println("[增强功能]:" + method.getName() + "方法于" + new Date() + "开始执行....");
System.out.println("[增强功能]:目标方法=>" + method);
System.out.println("[增强功能]:方法参数=>" + Arrays.toString(args));
// 完成目标方法的执行(反射)
// method.invoke(目标对象,方法参数);
Object returnVal = method.invoke(target, args);
long endTime = System.currentTimeMillis();
System.out.println("[增强功能]:" + method.getName() + "方法于" + new Date() + "结束执行!!!!");
System.out.println("[增强功能]:共耗时" + (endTime - beginTime) + "毫秒!");
return returnVal;
}
}
特点:
通过接口实现,所以目标对象必须要有“接口”。
Cglib代理
Cglib代理代理工厂
基于Cglib的实现 : 需要Enhancer类 + 实现MethodInterceptor接口
public class CglibProxyFactory implements MethodInterceptor{
// 目标对象
private Object target;
// 构造方法
// 传入目标对象
public CglibProxyFactory(Object target) {
this.target = target;
}
// 创建动态代理对象
public Object createProxy() {
Enhancer enhancer = new Enhancer();
// 传入目标对象的(Class类型)=>(父类)
enhancer.setSuperclass(target.getClass());
// 设置回调对象:当通过代理对象调用目标方法时,会执行回调对象的intercept()
enhancer.setCallback(this);
// 创建动态代理对象
Object newProxy = enhancer.create();
return newProxy;
}
// 参数1 proxy:
// 参数2 method: 目标方法
// 参数3 args :目标方法参数
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy arg3) throws Throwable {
System.out.println("***********************************************");
Object returnVal = method.invoke(target, args);
System.out.println("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$");
return returnVal;
}
}
特点:
通过继承目标类,以目标对象子类的方式实现代理,这种方法也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展。
总结
在Spring的AOP编程中:
尽量不要使用静态代理。
如果加入容器的目标对象有实现接口,用JDK代理。
如果目标对象没有实现接口,用Cglib代理。