动态代理,区别与代理模式的静态代理,静态代理往往通过构造函数并返回一个真实的被代理对象,然后执行被代理对象的方法,因此不能额外执行更多的操作。静态代理最主要的是引入明确的被代理对象,程序在编译阶段就需要知道要代理的对象,因此有很多局限性。而动态代理则是在实现阶段并不关心要代理谁,在程序运行阶段才指定代理的对象。现在有一个非常流行的技术叫面向切面编程,其核心就是采用了动态代理机制。对于日志,事务,权限都可以在设计阶段不用考虑,而在设计后通过AOP的方式切入。
抽象主题,主要是定义需要干的事情
public interface Subject {
//业务操作s
public void doSomething(String strs);
}
真实主题
public class RealSubject implements Subject {
@Override
public void doSomething(String strs) {
System.out.println("do something--------------->"+strs);
}
}
//动态代理的handler类
public class MyInvocationHander implements InvocationHandler {
private Object target=null;
public MyInvocationHander(Object obj) {
super();
this.target = obj;
}
/**
* 代理方法
* 所有通过代理的方法都通过invoke方法调用
* **/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// TODO Auto-generated method stub
return method.invoke(this.target, args);
}
}
//动态代理类
public class DynamicProxy<T> {
@SuppressWarnings("unchecked")
public static <T> T newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler handler ){
if(true) {
//执行前置通知
(new BeforeAdvice()).exec();
}
return (T) Proxy.newProxyInstance(loader, interfaces, handler);
}
}
//通知接口以及实现
public interface IAdvice {
public void exec();
}
public class BeforeAdvice implements IAdvice {
@Override
public void exec() {
System.out.println("我是前置通知,我给执行了");
}
}
//动态代理场景测试
public class Client {
public static void main(String[] args) {
//定义一个主题
Subject subject=new RealSubject();
//定义一个handler,处理工作
InvocationHandler handler=new MyInvocationHander(subject);
//定义主题的代理、
Subject proxy=DynamicProxy.newProxyInstance(subject.getClass().getClassLoader(), subject.getClass().getInterfaces(), handler);
proxy.doSomething("finished");
}
}
执行结果
我是前置通知,我给执行了
do something--------------->finished
刚才的动态代理只是通用的一个代理类,没有业务意义,我们可以继承这个从而产生一个实现类来处理业务
public class SubjectDynamicProxy extends DynamicProxy{
public static <T> T newProxyInstance(Subject subject) {
ClassLoader loader=subject.getClass().getClassLoader();
Class<?>[] classes=subject.getClass().getInterfaces();
InvocationHandler handler=new MyInvocationHander(subject);
return newProxyInstance(loader, classes, handler);
}
}
具体的代理就更加简单
public class Client {
public static void main(String[] args) {
//定义一个主题
Subject subject=new RealSubject();
//定义一个handler,处理工作
InvocationHandler handler=new MyInvocationHander(subject);
//定义主题的代理、
Subject proxy=DynamicProxy.newProxyInstance(subject.getClass().getClassLoader(), subject.getClass().getInterfaces(), handler);
//第二种代理业务
Subject proxy2=SubjectDynamicProxy.newProxyInstance(subject);
proxy.doSomething("finished");
proxy2.doSomething("second business finished");
}
}
在不改变原有代码的基础上增强或者控制对象的行为。要实现动态代理的首要条件是被代理类必须实现一个接口。现在有一些代理技术比如,CGLIB不用实现接口也可以实现对象的动态代理。
jdk自带的反射代理类java.lang.reflect.Proxy的newProxyInstance 可以为我们动态生成代理对象,其原理是通过动态生成并装载代理类的字节码。cglib与jdk的动态代理不同,下一篇将会介绍cglib和JDK动态代理的不同之处和优缺点。