Java动态代理底层机制浅析
在学习spring之初,总会见到动态代理,换句话说不理解动态代理就没法理解spring,诚然可以使用一些“万能模板”,但不理解底层原理和咸鱼有什么区别呢?
什么是动态代理
所谓动态代理,显而易见相对于静态代理
静态代理的好处
可以使得我们的真实角色更加纯粹 . 不再去关注一些公共的事情 .
公共的业务由代理来完成 . 实现了业务的分工 ,
公共业务发生扩展时变得更加集中和方便 .
缺点 :
类多了 , 多了代理类 , 工作量变大了 . 开发效率降低 .
我们想要静态代理的好处,又不想要静态代理的缺点,所以 , 就有了动态代理
动态代理的角色和静态代理的一样 . 动态代理的代理类是动态生成的 .
静态代理的代理类是我们提前写好的
动态代理分为两类 :一类是基于接口动态代理 , 一类是基于类的动态代理
基于接口的动态代理----JDK动态代理
基于类的动态代理–cglib
现在用的比较多的是 javasist 来生成动态代理 . 百度一下javasist
这里使用的JDK原生的动态代理,想要理解,自然离不开官方文档(小弟英文水平有限 找了一篇中文的 文末会附上 希望能帮助大家学习)
实现类和用法
首先打开官方文档搜索proxy 意思就是代理
可以看到代理属于反射的一种,反射可以说是java非常强大的功能之一,后续我也会好好复习
首先我们得明确要使用哪些类来帮助我们实现动态代理,即proxy和InvocationHandler,既然是handler,也就是处理器或者管理者的意思,待会我们将会用他实现代理类的部署。
这里是官方文档对于invocationhandler的一个用法的示例
对于这段代码可以这么理解:
InvocationHandler接口是一个接口,由一个代理类实现。空代理实例是proxy的一个实例。每个代理实例有一个相关的调用处理程序对象,它实现了接口InvocationHandler。方法调用一个代理实例通过其代理接口将被派遣到该实例的调用处理程序的invoke方法,invoke方法就是反射的方法,大家都不陌生应该,通过代理实例,一个java.lang.reflect.Method对象被调用的方法识别和Object型含参数数组。调用处理程序以适当的方式处理编码的方法调用,返回的结果将作为代理实例的方法调用的结果返回。
当然,文字是枯燥的 我将用一个例子来帮助大家理解
我们用 房东-----租客-------中介代理的例子来描述
首先新建一个接口Rent 代表出租这个行为 是一种抽象角色
public interface Rent { public void rent(); }
自然也需要租客和房东
所以我们先新建Host
public class Host implements Rent{ public void rent() { System.out.println("出租房子!"); } }
Client类一会用来输出代理实例的方法调用的结果返回
接下来就是重点,代理类ProxyInvocationHandler
首先新建代理类ProxyInvocationHandler,继承InvocationHandler接口,这一步在刚刚的官方文档里也有体现,不继承接口后面的步骤都是我秀我自己
我们此时可以将这个代理类理解为中介机构,中介机构得知道这房子要租吧
所以得将接口Rent丢进类里 也就是将抽象对象丢进去
private Rent rent;
然后我们得注入,采用Spring里推荐使用的set方法直接注入
public void setRent(Rent rent) { this.rent = rent; }
接下来是关键了
根据官方文档
//生成代理类,重点是第二个参数,获取要代理的抽象角色!之前都是一个角色,现在可以代理一类角色 public Object getProxy(){ return Proxy.newProxyInstance(this.getClass().getClassLoader(), rent.getClass().getInterfaces(),this); }
接着以适当的方式处理编码的方法调用,返回的结果将作为代理实例的方法调用的结果返回,所谓代理实例的方法调用,也就是真实对象中对rent的方法调用,并输出
// proxy : 代理类 method : 代理类的调用处理程序的方法对象. // 处理代理实例上的方法调用并返回结果 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //核心:本质利用反射实现! Object result = method.invoke(rent, args); return result; }
最后创建租客Client类
//租客 public class Client { public static void main(String[] args) { //真实角色 Host host = new Host(); //代理实例的调用处理程序 ProxyInvocationHandler pih = new ProxyInvocationHandler(); pih.setRent(host); //将真实角色放置进去! Rent proxy = (Rent)pih.getProxy(); //动态生成对应的代理类! proxy.rent(); } }
输出结果
总结:
动态代理,就是将一切动态化,而不是自己去创建实现,通过:
抽象角色 : 一般使用接口或者抽象类来实现 Rent
真实角色 : 被代理的角色 Host
代理角色 : 代理真实角色 ; 代理真实角色后 , 一般会做一些附属的操作 . ProxyInvocationHandler
客户 : 使用代理角色来进行一些操作 . Client
这四个角色来实现动态代理的底层机制
- 点赞
- 收藏
- 分享
- 文章举报
- Spring AOP原理和用法
- Spring三种注入方式
- JavaSE多态
- java和.net的对象类型转换浅谈
- SpringMVC工作流程及代码分析
- No qualifying bean of type 'org.springframework.mail.javamail.JavaMailSender' available: expected at...
- 宠物领养网站(一):简 4000 单搭建SpringBoot+JPA+Gradle+Mysql项目
- 解决 https://start.spring.io 访问报错问题
- 宠物领养网站(二):SpringBoot支持JSP开发配置
- JDK,JRE,JVM的区别与联系
- java中 equals 和 hashcode 的关系
- java知识点总结
- java实现九九乘法表-超简单的一目了然
- Java验证码读取
- java界面实现骰子比赛改进
- BES-多模块Springboot项目MyBatis通用Mapper配置(Controller Service Dao在不同子模块中)
- BES-SpringCloud Gateway网关整合多模块项目-Predicates与Filter
- java实现一个删除固定后缀文件的程序
- java编写贪吃蛇小游戏源代码分享给你们
- @蓝桥杯javaB组习题集入门(4)之第二题:序列求和