首页 > 其他分享 >Solon2 开发之容器,八、动态代理的本质

Solon2 开发之容器,八、动态代理的本质

时间:2023-02-12 22:11:33浏览次数:36  
标签:容器 调用 Object 代理 接口 Solon2 UserService public

在 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 增加代理能力,按需添加即可

标签:容器,调用,Object,代理,接口,Solon2,UserService,public
From: https://www.cnblogs.com/noear/p/17114844.html

相关文章

  • WPF学习笔记(窗体和常用容器的使用)
    WPF学习笔记(窗体和常用容器的使用)新手学习之路;望大佬们指点迷津目录WPF学习笔记(窗体和常用容器的使用)窗体(Window)常用属性:圆角无边框窗体设置及效果展示Grid基本属......
  • Solon2 开发之容器,三、注入或手动获取 Bean
    1、如何注入Bean?先了解一下Bean生命周期的简化版:运行构建函数尝试字段注入(有时同步注入,没时订阅注入。不会有相互依赖而卡住的问题)@Init函数(是在容器初始化完成后才......
  • Solon2 开发之容器,四、注入依赖与初始化
    Solon强调有克制的注入+手动控制结合的模式。好处是,代码用料少、启动快。Bean的关键生命节点:节点说明1.Constructor(构造方法)不支持参数注入2.@In......
  • Solon2 开发之容器,一、注入或手动获取配置
    约定resources/app.yml(或app.properties)#为应用配置文件配置样例track:name:xxxurl:http://a.a.adb1:jdbcUrl:"jdbc:mysql://..."username:......
  • Solon2 开发之容器,二、构建一个 Bean 的三种方式
    1、手动简单的构建://生成普通的BeanSolon.context().wrapAndPut(UserService.class,newUserServiceImpl());//生成带注解的Bean(比如:@Controller)Solon.context().be......
  • spring动态代理
    动态代理publicinterfaceUserManager{voidaddUser(Stringusername);voiddelUser(Stringusername);}publicclassUserManagerImplimplementsUserMa......
  • 容器部署分布式zabbix
    之前有写过docker-compose部署zabbix的博客这里再总结下分布式部署zabbix的笔记,这里重点是部署zabbix-proxy同样需要准备数据库配置文件数据库配置文件差不多这里是doc......
  • Docker consul的容器服务更新与发现
    一、Consul概述(1)什么是服务注册与发现服务注册与发现是微服务架构中不可或缺的重要组件。起初服务都是单节点的,不保障高可用性,也不考虑服务的压力承载,服务之间调用单纯的......
  • #yyds干货盘点# LeetCode面试题:盛最多水的容器
    1.简述:给定一个长度为n的整数数组 height 。有 n 条垂线,第i条线的两个端点是 (i,0) 和 (i,height[i]) 。找出其中的两条线,使得它们与 x 轴共同构成的容器可......
  • 【Docker】MySQL容器定时备份
    我们通常使用原生的mysql会比较多,mysql的备份也耳熟能详。假如现在有个mysql数据库username为root,password为123456,且现在要导出schema为db1、db2的数据。在本地导出的时候......