Proxy代理模式
代理模式基本概念:为其他对象提供一个代理来控制这个的访问。
主要解决的问题:直接访问对象时所带来的问题。
代理类: 负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。
举个栗子(=.=)
开始接触spring框架的时候,必然的要去了解 IOC 和 AOP,其中AOP的底层实现原理就是动态代理。以此为切入点,通过对AOP底层实现的理解,初识代理模式。
1、静态代理实现AOP,首先来一波简单代码①
//目标对象的接口
public interface IWorkDao {
void work();
}
//实现类
public class WorkDaoImpl implements IWorkDao {
@Override
public void work() {
System.out.println("这里是目标对象WorkDao的实现类");
}
}
//增强类:一般给类方法添加事务控制或者性能检测
public class TransactionManager {
public void beginTransation(){
System.out.println("start...");
}
//切割线------
//...业务逻辑代码
//切割线------
public void endTransation(){
System.out.println("over...");
}
}
目标对象增加的过程产生代理类
//代理对象持有被代理对象的一个接口public class WorkDaoProxy implements IWorkDao { //主角:目标对象 IWorkDao workDao; //配角:增强对象 TransactionManager tx; //来一个构造器 public WorkDaoProxy(IWorkDao workDao, TransactionManager tx) { this.workDao = workDao; this.tx = tx; } //将增强添加到目标对象(织入) @Override public void work() { tx.beginTransation();//非业务代码 workDao.work(); //业务代码 tx.endTransation();//非业务代码,横向切割体现出来了有木有 }}
//测试类
public class Test {
public static void main(String[] args) {
//目标对象
IWorkDao workDao = new WorkDaoImpl();
//增强
TransactionManager tx = new TransactionManager();
//代理对象
WorkDaoProxy workDaoProxy = new WorkDaoProxy(workDao,tx);
//代理对象调用目标方法
workDaoProxy.work();
}
}
这里存在一个问题,要是我创建其他的目标对象接口比如ISleepDao或者修改当前类方法名,这不又得重新创建一个代理类或者修改?好麻烦有木有,所以就有以下方案:
2、基于jdk动态代理实现AOP(基于InvocationHandler接口模式),代码①省略
//代理类
public class ProxyHandle implements InvocationHandler {
//目标对象(不用知道具体的目标对象是谁,好神秘)
Object target;
//增强
TransactionManager tx;
//构造器(用于实例化handle)
public ProxyHandle(Object target, TransactionManager tx) {
this.target = target;
this.tx = tx;
}
/**
* 织入
* @param proxy
* @param method
* @param args 参数列表
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
tx.beginTransation();
Object obj = method.invoke(target, args);
tx.endTransation();
return obj;
}
}
//测试类
public class Test {
public static void main(String[] args) {
//目标对象
IWorkDao workDao = new WorkDaoImpl();
//增强
TransactionManager tx = new TransactionManager();
//获得handle(构造器开辟内存空间用于存放目标对象和增强对象)
ProxyHandle handle = new ProxyHandle(workDao,tx);
//生成代理对象(传入handle,利用反射获得目标对象和增强)
IWorkDao workDaoProxy = (IWorkDao) Proxy.newProxyInstance(workDao.getClass().getClassLoader(), workDao.getClass().getInterfaces(), handle);
//代理对象调用目标方法
workDaoProxy.work();
}
}
解决了每创建一个目标对象必须创建一个代理类的问题,JDK中的动态代理是通过反射类Proxy以及InvocationHandler回调接口实现的,但是,JDK中所要进行动态代理的类必须要实现一个接口(如上面的:Object target 的接口),也就是说只能对该类所实现接口中定义的方法进行代理,这在实际编程中具有一定的局限性,而且使用反射的效率也并不是很高。
3、基于cglib动态代理实现AOP,首先要导入cglib的jar包,继续代码①省略
//代理类
public class CglibDynInterceptor implements MethodInterceptor{
//要代理的原始对象(抛弃你了)
//private Object object;
private Enhancer enhancer = new Enhancer();
private TransactionManager tx;
public CglibDynInterceptor(TransactionManager tx) {
this.tx = tx;
}
//创建子类
public Object getProxy(Class cls){
enhancer.setSuperclass(cls); //设置代理对象
enhancer.setCallback(this); //回调MethodInterceptor接口方法拦截(类似于JDK中的 InvocationHandler接口)
//通过字节码技术动态创建子类
return enhancer.create();
}
/**
* object:由CGLib动态生成的代理类实例
* method:增强方法引用
* args:参数值列表
* methodProxy:生成的代理类对方法的代理引用
*/
@Override
public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy)
throws Throwable {
tx.beginTransation();
//拦截父类方法(调用代理类实例上的proxy方法的父类方法)
Object result = methodProxy.invokeSuper(object, args);
tx.endTransation();
return result;
}
}
//测试类
public class Test {
public static void main(String[] args) {
//增强
TransactionManager tx = new TransactionManager();
//创建代理类
CglibDynInterceptor proxy = new CglibDynInterceptor(tx);
//通过反射创建代理对象(子类)
IWorkDao workDaoProxy = (IWorkDao) proxy.getProxy(IWorkDao.class);
workDaoProxy.work();
}
}
使用CGLib实现动态代理,完全不受代理类必须实现接口的限制,而且CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,比使用Java反射效率要高。唯一需要注意的是,CGLib不能对声明为final的方法进行代理,因为CGLib原理是动态生成被代理类的子类。
Enhancer允许为非接口类型创建一个Java代理。Enhancer动态创建了给定类型的子类但是拦截了所有的方法。和Proxy不一样的是,不管是接口还是类他都能正常工作(解决jdk动态代理中每创建一个代理类必须要实现接口)
另外:Callback接口是一个空接口,没有任何契约方法,它只表示这是一个回调。
以上是个人结合SpringAop底层实现原理去理解代理模式,不足之处还请谅解~