先看再点赞,给自己一点思考的时间,如果对自己有帮助,微信搜索【程序职场】关注这个执着的职场程序员。
价值:Java技能,面试经验指导,简历优化,职场规划指导,技能提升方法,讲不完的职场故事,个人成长经验。
01
概念
动态代理是设计模式当中代理模式的一种。
主要用来做方法的增强,让你可以在不修改源码的情况下,增强一些方法,在方法执行前后做任何你想做的事情,因为在InvocationHandler的invoke方法中,你可以直接获取正在调用方法对应的Method对象,具体应用的话。
比如可以添加调用日志,做事务控制等。
随让上面说了很多的有点,但是也是存在不足的。
诚然,Proxy已经设计得非常优美,但是还是有一点点小小的遗憾之处,那就是它始终无法摆脱仅支持interface代理的桎梏,因为它的设计注定了这个遗憾。
回想一下那些动态生成的代理类的继承关系图,它们已经注定有一个共同的父类叫Proxy。
Java的继承机制注定了这些动态代理类们无法实现对class的动态代理,原因是多继承在Java中本质上就行不通。
有很多条理由,人们可以否定对 class代理的必要性,但是同样有一些理由,相信支持class动态代理会更美好。
接口和类的划分,本就不是很明显,只是到了Java中才变得如此的细化。
如果只从方法的声明及是否被定义来考量,有一种两者的混合体,它的名字叫抽象类。实现对抽象类的动态代理,相信也有其内在的价值。此外,还有一些历史遗留的类,它们将因为没有实现任何接口而从此与动态代理永世无缘。
如此种种,不得不说是一个小小的遗憾。但是,不完美并不等于不伟大,伟大是一种本质,Java动态代理就是佐例。
Jdk动态代理之所以只能代理接口是因为代理类本身已经extends了Proxy,而java是不允许多重继承的,但是允许实现多个接口,因此才有这样的需要。
终于知道为什么说“Jdk动态代理局限于接口是因为Java只支持单继承”。
02
总结
1,JDK动态代理是基于接口的代理,其将代理接口中包括default方法在内的所有方法;
2,InvocationHandler是一个函数式接口(类似Runnable接口),其invoke方法指定方法的代理逻辑;
3,代理类的Method属性是接口中的方法对象,不是实现类的,注解加在接口方法上才能拿到;
03
使用步骤
1.通过实现InvocationHandler接口定义自己的InvocationHandler。
2.通过Proxy.getProxyClass0方法获得动态代理类。
3.通过反射机制获取动态代理类的构造方法,getConstructor(InvocationHandler.class)。
4.通过构造函数获得代理对象,并将第一步时自定义的InvocationHandler实例对象作为入参,newInstance(new Object[]{InvocationHandler})。
5.通过代理对象调用方法。
04
实战详解
1.定义需要被动态代理的接口
public interface Subject {
void subjectRun(String param);
}
2.被真正代理的类,用来处理实际业务
public class RealSubject implements Subject {
public void subjectRun(String param) {
System.out.println("代理对象的方法被执行了!"+param);
}
}
3.定义代理类需实现InvocationHandler
public class ProxySubject implements InvocationHandler {
//真正被代理的对象
private Object subject;
//通过构造方法为代理对象赋值
public ProxySubject(Object subject){
this.subject = subject;
}
/**
* @param proxy 动态生成的代理类
* @param method 被代理的类的方法
* @param args 调用被代理类的入参
* @return
* @throws Throwable
*/@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result = null;
System.out.println("目标对象方法执行之前对方法加强!");
method.invoke(subject,args);
//subject:被代理的对象 args:调用方法的入参
System.out.println("目标对象方法执行之前对方法加强!");
return result;
}
}
4.测试类
public class ProxyRun {
public static void main(String[] args){
//被真实代理的类,处理实际业务
Subject subject = new RealSubject();
//实现InvocationHandler的代理类
InvocationHandler h = new ProxySubject(subject);
//动态生成代理类对象
Subject subjectProxy = (Subject)Proxy.newProxyInstance
(h.getClass().getClassLoader(),
subject.getClass().getInterfaces(),h);
//调用动态生成代理类的方法
subjectProxy.subjectRun("execute");
}
}
5.程序运行结果
目标对象方法执行之前对方法加强!
代理对象的方法被执行了!execute
目标对象方法执行之后对方法加强!
05
我是【尔东双月】一枚执着的职场程序员,微信搜索【程序职场】关注我。别忘了三连啊,点赞、收藏、留言,随意给,我不挑。
知乎号: 程序职场
CSDN:程序职场
注:如果文章有任何问题,欢迎毫不留情地指正。