代理模式
什么是代理模式:
由于某些原因需要给某对象提供一个代理以控制对该对象的访问,这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。
结构
代理类(Proxy)
目标类(Target)
静态代理
代理类和目标类需要实现同一个接口,在目标类中实现方法的主要逻辑(核心代码)
public class DemoDAOImpl implements IDemoDAO{
@Override
public void executeInsert() {
System.out.println("[数据访问操作]:1.连接数据库");
System.out.println("[数据访问操作]:2.执行SQL");
System.out.println("[数据访问操作]:3.处理结果");
}
}
在代理类中实现增强逻辑(公共代码)在创建目标类对象,调用目标类方法。从而实现不改变核心代码的前提下改变代码的输入内容。
public class DemoDAOpoxy implements IDemoDAO {
private DemoDAOImpl demoDaoImpl = new DemoDAOImpl();
@Override
public void executeInsert() {
long beginTime = System.currentTimeMillis();
System.out.println("[增强操作]:executeInsert方法于"+new Date()+"开始执行...");
demoDaoImpl.executeInsert();
long endTime = System.currentTimeMillis();
System.out.println("[增强操作]:executeInsert方法于"+new Date()+"结束执行!!!");
long time = endTime-beginTime;
System.out.println("[增强操作]:共耗时:"+time+"毫秒");
}
}
动态代理
为了应对大规模的代理需求,则需要有一种可针对不同的目标类创建不同的代理对象的代理工厂(利用反射)。动态代理的出现实现了这一需求。
动态代理有两种,一种是基于JDK的动态代理工厂,一种是基于Cglib的动态代理工厂。下面介绍这两种代理工厂的结构。
基于JDK的动态代理工厂
前提:目标类必须实现接口。工厂类则需实现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 resultVal = method.invoke(target, args);
long endTime = System.currentTimeMillis();
System.out.println("[增强操作]:"+method.getName()+"方法于"+new Date()+"结束执行!!!");
System.out.println("[增强操作]:共耗时:"+(endTime-beginTime)+"毫秒");
return resultVal;
}
}
基于Cglib的动态代理工厂
通过继承实现,实际上就是工厂类成为目标类的父类
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 result = method.invoke(target, args);
System.out.println("$$$$$$$$$$$$$$$$$$$$");
return result;
}
}
区别
如果目标类可实现接口,则优先选择JDK的代理工厂,如果目标类因为某些业务不能实现接口,可选择使用Cglib代理工厂。