什么是动态代理?
动态代理就是在实现阶段不用关心代理谁,而在运行阶段才指定代理哪个对象。具体说明动态代理是根据被代理的接口生成所有的方法,也就是说给定一个接口,动态代理会宣称“我已经实现该接口的所有方法了”。
面向切面变成(AOP),其核心就是采用了动态代理机制。AOP编程没有使用什么新的技术,但是它对我们的设计、编码有非常大的影响,对于日志、事务、权限等都可以在系统设计阶段不用考虑,而在设计后通过AOP的方式切过去。
代理思路:
动态代理实现代理的职责,业务逻辑Subject实现相关的逻辑功能,两者之间没有必然的相互耦合的关系。通知Advice从另一个切面切入,最终在高层模块也就是Client进行耦合,完成逻辑的封装任务。
抽象主题
public interface Subject {
// 业务操作
public void doSomething(String str);
}
其中的doSomething是一种标识方法,可以有多个逻辑处理方法。
真实主题
public class RealSubject implements Subject {
// 业务操作
public void doSomething(String str) {
System.out.println("do something!--->" + str);
}
}
动态代理的Handler类
public class MyInvocationHandler implements InvocationHandler {
// 被代理的对象
private Object target = null;
// 通过构造函数传递一个对象
public MyInvocationHandler(Object _obj) {
this.target = _obj;
}
// 代理方法
public Object invoke(Object proxy , Method method , Object[] args) throws Throwable {
// 执行被代理的方法
return method.invoke(this.target , args);
}
}
动态代理类
public class DynamicProxy<T> {
public static <T> T newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandle h) {
// 寻找JoinPoint连接点,AOP框架使用元数据定义
if(true) {
// 执行一个前置通知
(new BeforeAdvice()).exec();
}
// 执行目标,并返回结果
return (T)Proxy.newProxyInstance(loader, interface , h);
}
}
该方法时重新生成了一个对象,为什么要重新生成?你要使用代理,注意c.getInterfaces()这句话,这是非常有意思的一句话,是说查找到该类的所有接口,然后实现接口的所有方法。当然了,方法都是空的,由谁具体负责接管呢?是new MyInvocationHandler(_Obj)这个对象。于是 我们知道一个类的动态代理类时这样的一个类,由InvocationHandler的实现类实现所有的方法,由其invoke方法接管所有方法的实现。
通知接口及实现
public interface IAdvice {
// 通知只有一个方法,执行即可
}
public class BeforeAdvice implements IAdivce {
public void exec() {
System.out.println("我是前置通知,我被执行了!");
}
}
具体业务的动态代理
public class SubjectDynamicProxy extends DynamicProxy {
public static <T> newProxyInstance(Subject subject) {
// 获得ClassLoader
ClassLoader loader = subject.getClass().getClassLoader();
// 获得接口数组
Class<?> classes = subject.getClass().getInterfaces();
// 获得handler
InvocationHandler handler = new MyInvocationHandler(subject);
return newProxyInstance(loader, classes , handler);
}
}
场景类
public class Client {
public static void main(Stirng[] args) {
// 定义一个主题
Subject subject = new RealSubject();
// 定义主题的代理
Subject proxy = SubjectDynamicProxy.newProxyInstance(subject);
// 代理的行为
proxy.doSomething("Finish");
}
}
动态代理的主要意图就是解决我们常说的“审计”问题,也就是横切面编程,在不改变我们已有的代码结构的情况下增强或控制对象的行为。
注意:要实现动态代理的首要条件是:被代理类必须实现一个接口,回想一下前面的分析吧,当然了,现在也有很多技术如CGLIB可以实现不需要接口也可以实现动态代理的方式。