在 Java 里动态代理,主要分:接口动态代理 和 类动态代理。因为它的代理类都是动态创建的,所以名字里会带上“动态”。

官网的有些地方叫“代理”,也有些地方叫“动态代理”。都是一个意思。

1、接口动态代理

这是 jdk 直接支持的能力。内在的原理是:框架会动态生成目标接口的一个代理类(即接口的实现类)并返回,使用者在调用接口的函数时,实际上调用的是这个代理类的函数,而代理类又把数据转给了调用处理器接口。

而整个过程的感受是调用目标接口,最终到了 InvocationHandler 的实现类上:

//1. 定义目标接口
public interface UserService{
void addUser(int userId, String userName);
} //=> //2. 通过JDK接口,获得一个代理实例
UserService userService = Proxy.getProxy(UserService.class, new InvocationHandlerImpl()); //生成的 UserService 代理类,差不多是这个样子:
public class UserService$Proxy implements UserService{
final InvocationHandler handler;
final Method addUser2; //示意一下,别太计较它哪来的 public UserService$Proxy(InvocationHandler handler){
this.handler = handler;
} @Override
public void void addUser(int userId, String userName){
handler.invoke(this, addUser2, new Object[](userId, userName));
}
} //在调用 userService 时,本质是调用 UserService$Proxy 的函数,最终又是转发到 InvocationHandler 的实现类上。 //=> //3. 实现调用处理器接口 public class InvocationHandlerImpl implements InvocationHandler{
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
//...
}
}

一般,接口动态代理是为了:转发处理。

2、类动态代理

类的动态代理,略麻烦些,且要借助字符码工具框架(Solon 用的是 ASM)。内在的原理倒是相差不大:框架会动态生成目标类的一个代理类(一个重写了所有函数的子类)并返回,使用者在调用目标类的函数时,实际上调用的是这个代理类的函数,而代理类又把数据转给了调用处理器接口。调用处理器在处理时,会附加上别的处理。

而整个过程的感受是调用目标类,可以附加上很多拦截处理:

//1. 定义目标类
public class UserService{
public void addUser(int userId, String userName){
//..
}
} //=> //2. 通过框架接口,获得一个代理实例(::注意这里的区别!)
UserService userService = new UserService();
userService = AsmProxy.getProxy(UserService.class, new AsmInvocationHandlerImpl(userService)); //生成的 UserService 代理类,差不多是这个样子:
public class UserService$AsmProxy extends UserService{
final AsmInvocationHandler handler;
final Method addUser2; //示意一下,别太计较它哪来的 public UserService$Proxy(AsmInvocationHandler handler){
this.handler = handler;
} @Override
public void void addUser(int userId, String userName){
handler.invoke(this, addUser2, new Object[](userId, userName));
}
} //本质还是调用 UserService$AsmProxy 的函数,最终也是转发到 AsmInvocationHandler 的实现类上。 //=> //3. 实现调用处理器接口 public class AsmInvocationHandlerImpl implements AsmInvocationHandler{
//::注意这里的区别
final Object target;
public AsmInvocationHandlerImpl(Object target){
this.target = target;
} public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
//::注意这里的区别
MethodWrap methodWrap = MethodWrap.get(method); //MethodWrap 内部对各种拦截器做了封装处理
methodWrap.invoke(target, args);
}
}

一般,类动态代理是为了:拦截并附加处理。

3、关于 Solon 的类代理情况与“函数环绕拦截”

对 Solon 来讲,只有一个函数反射后再经 MethodWrap 执行的,就是被代理了。所有的“函数环绕拦截”处理就封装在 MethodWrap 里面。

  • @Controller、@Remoting 注解的类

这两个注解类,没有 ASM 的类代码,但是它们的 Method 会转为 MethodWrap ,并包装成 Action 注册到路由器。即它们是经 MethodWrap 再调用的。所以它们有代理能力,支持“函数环绕拦截”。

  • @Service、@Dao、@Repository 注解的类

这三个注解,来自 solon.aspect 插件包,它们注解的类,都会被 ASM 代理。跟上面原理分析的一样,也支持“函数环绕拦截”。

  • 有克制的拦截

Solon 不支持表达式的随意拦截,必须以注解为“切点”进行显示拦截。所以 Solon 不用为所有的 Bean 增加代理能力,按需添加即可。

Solon2 开发之容器,八、动态代理的本质的更多相关文章

  1. mybatis开发Dao的Mapper动态代理方式

    1. 开发规范Mapper接口开发方法只需要程序员编写Mapper接口(相当于Dao接口),由Mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体跟Dao原始方法中接口实现类的方法相 ...

  2. java开发必学知识:动态代理

    目录 1. 引言 2. 代理模式及静态代理 2.1 代理模式说明 2.2 静态代理 2.3 静态代理局限性 3. 动态代理 3.1 JAVA反射机制 3.2 JDK动态代理 3.2.1 JDK动态代理 ...

  3. 02.MyBatis在DAO层开发使用的Mapper动态代理方式

    在实际开发中,Mybatis作用于DAO层,那么Service层该如何调用Mybatis Mybatis鼓励使用Mapper动态代理的方式 Mapper接口开发方法只需要程序员编写Mapper接口(相 ...

  4. 【Mybtais】Mybatis 插件 Plugin开发(一)动态代理步步解析

    需求: 对原有系统中的方法进行'拦截',在方法执行的前后添加新的处理逻辑. 分析: 不是办法的办法就是,对原有的每个方法进行修改,添加上新的逻辑:如果需要拦截的方法比较少,选择此方法到是会节省成本.但 ...

  5. 深入理解Spring IoC容器和动态代理机制

    Deployment期间验证 实现一: <bean id="theTargetBean" class="..."/> <bean id=&qu ...

  6. MyBatis开发Dao的原始Dao开发和Mapper动态代理开发

    目录 咳咳...初学者看文字(Mapper接口开发四个规范)属实有点费劲,博主我就废了点劲做了如下图,方便理解: 原始Dao开发方式 1. 编写映射文件 3.编写Dao实现类 4.编写Dao测试 Ma ...

  7. 【Java EE 学习 50】【Spring学习第二天】【使用注解的DI实现】【spring中的继承】【动态代理伪hibernate实现】

    一.使用注解的DI实现 1.@Resource 使用该注解能够实现引用型属性的DI实现,该注解能够根据属性名和属性类型自动给属性赋值.一般使用@Resource(name="student& ...

  8. spring5——Aop的实现原理(动态代理)

    spring框架的核心之一AOP,面向切面编程是一种编程思想.我对于面向切面编程的理解是:可以让我们动态的控制程序的执行流程及执行结果.spring框架对AOP的实现是为了使业务逻辑之间实现分离,分离 ...

  9. .NET:动态代理的 “5 + 1” 模式

    背景 什么叫“动态代理”,代理模式我们都知道,动态代理就是动态生成的代理(采用Emit). 重量级的ORM和IOC产品离不开动态代理,作为开发人员,多数情况不用关注动态代理的内部实现机制,但是了解其一 ...

  10. java:Spring框架2(bean的作用域,静态工厂和实例工厂,自动装配,动态代理)

    1.bean的作用域,静态工厂和实例工厂: bean.xml: <?xml version="1.0" encoding="UTF-8"?> < ...

随机推荐

  1. CH58X/CH57X/V208 Observer(观察者)例程讨论讲解

    使用的是沁恒的CH582M的Observer例程与官方的demo板. 本例程的功能是主机扫描到从机的MAC地址并打印出来. 先对宏定义进行理解讨论. 最大响应扫描数为8,在串口调试助手那里可以看到打印 ...

  2. 嵌入式学习-c语言篇01:搭建C语言环境

    使用NotePad++和gcc编译器来搭建c语言环境 NotePad++:C语言编码器 gcc:C语言编译器 这两个软甲可以去官网下载 下载好进入该文件夹,如图: 添加环境变量:直接cmd,运行gcc ...

  3. 高精度加法(Java)

    题目描述 高精度加法,相当于 a+b problem,不用考虑负数. 输入格式 分两行输入. a , b ≤ 10^500 输出格式 输出只有一行,代表 a + b  的值. 思路 使用数组进行模拟, ...

  4. vue 中使用 this 更新数据的一次大坑

    情景说明: 之前用 vue 做数据绑定更新时,发现一个莫名奇妙的问题. 我在 vue 实例中声明了一个数组属性如 books: [],在异步请求的回调函数中使用 this.books = res.da ...

  5. requests模块和openpyxl模块

    第三方模块的下载和使用 1,第三方模块就是别人大神们已经写好的模块,功能特别强大.我们如果像使用第三方模块就先要进行下载.下载完成后 才可以在python中直接调用 2.下载方式一:pip工具 pip ...

  6. 如何搭建自己的CICD流水线,实现自动编译部署功能?

    之前使用过GitLab的CICD流水线,有多种环境,点击即可编译部署,十分的方便. 如何在个人项目中搭建自己的CICD流水线,实现push代码后自动编译并部署呢?这里使用到阿里云 云效DevOps,阿 ...

  7. C/C++标准输入输出函数终极最全解析(不全捶我)

    C/C++的一众输入输出函数的区别常常搞得人晕头转向,二者之中又以输入函数更加令人头疼.本文尝试整理C/C++的各种输入输出函数. 由于输入涉及空格.换行符的读取.忽略等问题,因此输入比输出更麻烦.所 ...

  8. 教你几个 Java 编程中的奇技淫巧

    枯燥的编程中总得有些乐趣,今天我们不谈论那些高深的技能,教你几个在编程中的奇技淫巧,说不定在某些时候还能炫耀一番呢. 1.找到最大值和最小值 不使用 if else switch 和三元运算符,在给定 ...

  9. 现代 CSS 高阶技巧,像 Canvas 一样自由绘图构建样式!

    在上一篇文章中 -- 现代 CSS 之高阶图片渐隐消失术,我们借助了 CSS @Property 及 CSS Mask 属性,成功的实现了这样一种图片渐变消失的效果: CodePen Demo -- ...

  10. IE浏览器卸载

    1.打开此电脑,点击上箭头,打开控制面板: 2.选择卸载程序: 3.点击启用或关闭Windows功能: 4.弹出Windows功能对话框,找到Inetrnet Explorer 11,取消勾选: 5. ...