一、定义
动态代理是在实现阶段不用关心代理的是谁,而在运行阶段才指定代理哪个对象。面向切面编程(AOP)其核心就是采用的动态代理机制。
二、代码演示
2.1 类图
上面类图,是两条独立的发展线路。动态代理实现代理的职责,业务逻辑Subject实现先关业务逻辑,两者没有必然的相互耦合的关系。通知Advices从另外一个切面切入,最终高层通过Client进行耦合,完成业务的逻辑封装。
2.2 业务逻辑抽象主题
public interface Subject {
//业务操作
public void doSomething(String str);
}
2.3 业务逻辑真实主题
public class RealSubject implements Subject {
public void doSomething(String str){
System.out.println("do something!---------->"+str);
}
}
2.4 动态代理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);
}
}
备注:所有通过动态代理实现的方法全部通过invoke方法调用。
2.5 动态代理类
public class DymamicProxy<T> {
public static <T> T newProxyInstance(ClassLoader loader, Class<?> []interfaces, InvocationHandler h){
//寻找JoinPiont连接点,AOP框架使用元数据定义
if (true){
(new BeforeAdvice()).exec();
}
return (T)Proxy.newProxyInstance(loader,interfaces,h);
}
}
2.6 通知接口及实现类
public interface IAdvice {
//通知只有一个方法
public void exec();
}
public class BeforeAdvice implements IAdvice {
public void exec(){
System.out.println("我是前置通知,我被执行了!");
}
}
2.7 动态代理场景类
public class Client {
public static void main(String args[]){
//定义个主题
Subject subject = new RealSubject();
//定义一个Handler
InvocationHandler handler = new MyInvocationHandler(subject);
//定义一个主题的代理
Subject subjectProxy = DymamicProxy.newProxyInstance(subject.getClass().getClassLoader(),subject.getClass().getInterfaces(),handler);
//代理的行为
subjectProxy.doSomething("Finish");
}
}
运行结果:
我是前置通知,我被执行了!
do something!---------->Finish
三、优点
3.1 动态代理能有效的从切面实现业务逻辑, 降低与业务代码的耦合度。
四、缺点
五、应用场景
动态代理是一个通用的代理框架,Spirng AOP 和 AspectJ 都是用动态代理实现, 在企业应用动态代理实现权限, 日志,事务处理等业务逻辑。
六、注意事项
6.1 (T)Object object = (T)Proxy.newProxyInstance(c.getClassLoader(), c.getInterfaces(), new MyInvocationHandler(_obj) )
该方法是动态代理的核心由jdk维护,为什么哟啊重新生成对象呢 ? 注意 c.getInterfaces()会查找该类的所有接口,然后new MyInvocationHandler(_obj) 实现接口的所有方法,方法都是空,由其invoke方法接管所有方法的实现,其动态调用过程如图:
6.2 动态代理必选满足如下逻辑
- A、业务代理类必须要实现一个接口,因为“subject.getClass().getInterfaces()”需要取接口信息
- B、必须要有一个代理处理类。如:MyInvocationHandler 该类必须实现InvocationHandler接口invoke方法
- C、必须生成代理对象。如:Subject subjectProxy = DymamicProxy.newProxyInstance(subject.getClass().getClassLoader(),subject.getClass().getInterfaces(),handler); C、必须生成代理对象。如:Subject subjectProxy = DymamicProxy.newProxyInstance(subject.getClass().getClassLoader(),subject.getClass().getInterfaces(),handler);