Dubbo源码(十) 与Spring一起学习Dubbo里的Aware

news2024/11/15 19:55:05

目录

一、Spring

1.BeanNameAware

2. BeanClassLoaderAware

3. ApplicationContextAware

4. EnvironmentAware

5. ApplicationEventPublisherAware

6. aware注入时机

二、Dubbo

1. ExtensionAccessorAware

三、小结


        现在很多同行做java开发几年了,被迫停留在curd的层面上"拧螺丝",对SpringAware可能只停留在怎么用的层面上,那我们用Spring时可以通过Aware能获取到容器工厂、应用上下文、Bean的类加载器等。

        那Spring 开发者为什么要设计这些Aware呢?那跟着这篇文章去一探究竟吧!      

        Spring 常见的一些Aware有 BeanNameAware、BeanClassLoaderAware、ApplicationContextAware、EnvironmentAware、ApplicationEventPublisherAware等。

        我在前文里写到Dubbo里的一些设计思想借鉴了Spring , 同样Dubbo 3.0里使用到了ScopeModelAware、ExtensionAccessorAware等,在初始化Extension Bean时设置了ExtensionAccessorAware, 让我们一起来看下aware的作用吧。

一、Spring

1.BeanNameAware

        获取到该Bean的name

@DubboService
public class DemoServiceImpl implements DemoService, BeanNameAware {

    @Override
    public String sayHello(String name) {
        System.out.println("Hello " + name + ", request from consumer: " + RpcContext.getContext().getRemoteAddress());
        return "Hello " + name;
    }


    @Override
    public void setBeanName(String beanName) {
        System.out.println("获取到BeanName=" + beanName);
    }
}

         在启动的时候获取到beanName: 

2. BeanClassLoaderAware

        获取到加载Bean的类加载器,可用该加载器写业务代码。

package org.apache.dubbo.springboot.demo.provider;


import org.apache.dubbo.config.annotation.DubboService;
import org.apache.dubbo.rpc.RpcContext;
import org.apache.dubbo.springboot.demo.DemoService;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanNameAware;

@DubboService
public class DemoServiceImpl implements DemoService, BeanNameAware, BeanClassLoaderAware {

    private ClassLoader classLoader;

    @Override
    public String sayHello(String name) {
        System.out.println("Hello " + name + ", request from consumer: " + RpcContext.getContext().getRemoteAddress());

        try {
            Class<?> clazz = classLoader.loadClass("org.apache.dubbo.springboot.demo.provider.Test01");
            Test01 test01 = (Test01) clazz.newInstance();
            test01.say();
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }
        return "Hello " + name;
    }


    @Override
    public void setBeanName(String beanName) {
        System.out.println("获取到BeanName=" + beanName);
    }

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        this.classLoader = classLoader;
    }
}

        获取到ClassLoader, 加载到Test01类后获取到指定对象:

3. ApplicationContextAware

        获取到Spring应用的上下文applicationContext, 可以根据applicationContext去拿到某个bean。

        比如我新建一个Test02, 用@Component注解标记,表示交给spring 管理。


package org.apache.dubbo.springboot.demo.provider;


import org.apache.dubbo.config.annotation.DubboService;
import org.apache.dubbo.rpc.RpcContext;
import org.apache.dubbo.springboot.demo.DemoService;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

@DubboService
public class DemoServiceImpl implements DemoService, BeanNameAware, BeanClassLoaderAware, ApplicationContextAware {

    private ClassLoader classLoader;


    private ApplicationContext applicationContext;

    @Override
    public String sayHello(String name) {
        System.out.println("Hello " + name + ", request from consumer: " + RpcContext.getContext().getRemoteAddress());

        try {
            Class<?> clazz = classLoader.loadClass("org.apache.dubbo.springboot.demo.provider.Test01");
            Test01 test01 = (Test01) clazz.newInstance();
            test01.say();
            Test02 test02 = applicationContext.getBean(Test02.class);
            test02.say();
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }
        return "Hello " + name;
    }


    @Override
    public void setBeanName(String beanName) {
        System.out.println("获取到BeanName=" + beanName);
    }

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        this.classLoader = classLoader;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

打印结果:

4. EnvironmentAware

        新建一个EnvironmentAwareConfig类实现EnvironmentAware接口, 实现类需要是Bean, 即被Spring 容器管理的类。

        添加一个参数: -Dtest=testEnvironmentAware:

        我们可以在业务代码里根据environment对象获取到配置的参数。 

package org.apache.dubbo.springboot.demo.provider;

import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;


@Component
public class EnvironmentConfig implements EnvironmentAware {
    @Override
    public void setEnvironment(Environment environment) {
        System.out.println("获取到属性: " + environment.getProperty("test", "nothing"));
    }
}

        实际开发中,可以使用environment获取到启动入参。 

5. ApplicationEventPublisherAware

        这个Aware是用来获取事件发布订阅的类ApplicationEventPublisher,利用applicationEventPublisher发布Spring 事件。

package org.apache.dubbo.springboot.demo.provider.publish;

import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;


@Component
public class EventPublisher implements ApplicationEventPublisherAware {
    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        applicationEventPublisher.publishEvent(new EventTest("test"));
    }

    public static class EventTest extends ApplicationEvent {
        public EventTest(Object source) {
            super(source);
        }
    }

    @Component
    public static class EventListener implements ApplicationListener {
        @Override
        public void onApplicationEvent(ApplicationEvent applicationEvent) {
            if (applicationEvent instanceof EventTest) {
                System.out.println("接收到事件====" + applicationEvent.getSource());
            }
        }
    }


}

打印结果: 

6. aware注入时机

        以上的所有Aware都是Spring 提供给开发者使用的工具类,那他们是在Spring 什么时候注入的呢?

        看一下Spring 5.2+的代码, 他们其实是在postProccessBeforeInitialization()方法里注入的。

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.springframework.context.support;

import java.security.AccessControlContext;
import java.security.AccessController;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.EmbeddedValueResolver;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.MessageSourceAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.lang.Nullable;
import org.springframework.util.StringValueResolver;

class ApplicationContextAwareProcessor implements BeanPostProcessor {
    private final ConfigurableApplicationContext applicationContext;
    private final StringValueResolver embeddedValueResolver;

    public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
        this.embeddedValueResolver = new EmbeddedValueResolver(applicationContext.getBeanFactory());
    }

    @Nullable
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (!(bean instanceof EnvironmentAware) && !(bean instanceof EmbeddedValueResolverAware) && !(bean instanceof ResourceLoaderAware) && !(bean instanceof ApplicationEventPublisherAware) && !(bean instanceof MessageSourceAware) && !(bean instanceof ApplicationContextAware)) {
            return bean;
        } else {
            AccessControlContext acc = null;
            if (System.getSecurityManager() != null) {
                acc = this.applicationContext.getBeanFactory().getAccessControlContext();
            }

            if (acc != null) {
                AccessController.doPrivileged(() -> {
                    this.invokeAwareInterfaces(bean);
                    return null;
                }, acc);
            } else {
                this.invokeAwareInterfaces(bean);
            }

            return bean;
        }
    }

// 注入Aware
    private void invokeAwareInterfaces(Object bean) {
        if (bean instanceof EnvironmentAware) {
            ((EnvironmentAware)bean).setEnvironment(this.applicationContext.getEnvironment());
        }

        if (bean instanceof EmbeddedValueResolverAware) {
            ((EmbeddedValueResolverAware)bean).setEmbeddedValueResolver(this.embeddedValueResolver);
        }

        if (bean instanceof ResourceLoaderAware) {
            ((ResourceLoaderAware)bean).setResourceLoader(this.applicationContext);
        }

        if (bean instanceof ApplicationEventPublisherAware) {
            ((ApplicationEventPublisherAware)bean).setApplicationEventPublisher(this.applicationContext);
        }

        if (bean instanceof MessageSourceAware) {
            ((MessageSourceAware)bean).setMessageSource(this.applicationContext);
        }

        if (bean instanceof ApplicationContextAware) {
            ((ApplicationContextAware)bean).setApplicationContext(this.applicationContext);
        }

    }
}

 从invokeAwareInterfaces方法里得知aware的加载顺序:

EnvironmentAware>ResourceLoaderAware>ApplicationEvenetPublisherAware>ApplicationContextAware 

二、Dubbo

        ExtensionAccessorAware是为了SPI 扩展而设计的一个类,该了的作用提供方法实现类的ExtensionAccessor, 通过ExtensionAccessor可以获取到指定的SPI实现类。

1. ExtensionAccessorAware

/**
 * SPI extension can implement this aware interface to obtain appropriate {@link ExtensionAccessor} instance.
 */
public interface ExtensionAccessorAware {

    void setExtensionAccessor(final ExtensionAccessor extensionAccessor);

}

        该方法的调用时机是在Extension实例注入完成后执行。 

        方式一: 在ScopeBeanFactory注册Bean实例注入完成后,会执行PostProcessAfterInitialization()方法来初始化实例。 


    private void initializeBean(String name, Object bean) {
        checkDestroyed();
        try {
            // 设置一系列的aware
            if (bean instanceof ExtensionAccessorAware) {
                ((ExtensionAccessorAware) bean).setExtensionAccessor(extensionAccessor);
            }
            // 执行postProcessAfterInitialization(bean,name);
            for (ExtensionPostProcessor processor : extensionPostProcessors) {
                processor.postProcessAfterInitialization(bean, name);
            }
        } catch (Exception e) {
            throw new ScopeBeanException("register bean failed! name=" + name + ", type=" + bean.getClass().getName(), e);
        }
    }

        方式二: 在ExtensionLoader里执行InjectExtension(instance)方法后执行。

   @SuppressWarnings("unchecked")
    private T createExtension(String name, boolean wrap) {
        // 根据实现类名去加载所有的Spi,然后将实现类放入到内存里,然后返回实现类的Class
        Class<?> clazz = getExtensionClasses().get(name);
        if (clazz == null || unacceptableExceptions.contains(name)) {
            throw findException(name);
        }
        try {
            T instance = (T) extensionInstances.get(clazz);
            if (instance == null) {
                extensionInstances.putIfAbsent(clazz, createExtensionInstance(clazz));
                instance = (T) extensionInstances.get(clazz);
                // 初始化之前
                instance = postProcessBeforeInitialization(instance, name);
                // 注入extension
                injectExtension(instance);
                // 初始化之后
                instance = postProcessAfterInitialization(instance, name);
            }
        }
// ...
}

        如果是ExensionAccessorAware那么就设置ExtensionAccessor。 

    @SuppressWarnings("unchecked")
    private T postProcessAfterInitialization(T instance, String name) throws Exception {
        //设置Aware
        if (instance instanceof ExtensionAccessorAware) {
            ((ExtensionAccessorAware) instance).setExtensionAccessor(extensionDirector);
        }
        if (extensionPostProcessors != null) {
            for (ExtensionPostProcessor processor : extensionPostProcessors) {
                instance = (T) processor.postProcessAfterInitialization(instance, name);
            }
        }
        return instance;
    }

       从代码里发现,Dubbo的ExtensionAccessorAware接口的设置在postProccessAfterInitialization方法之前,可以理解为Bean的初始化之前,我感觉此处的aware 初始化的时机设计类似于 Spring的aware。

三、小结

        Aware的设计的初衷在于将应用的底层设计与业务剥离,开发者可以根据需求使用Aware来获取到指定对象,通过注入的对象添加一些需要的业务代码。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/12404.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[附源码]java毕业设计竞价拍卖系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

灵雀云ACP 斩获“2022金边奖-最佳云原生边缘云平台”

近日&#xff0c;由边缘计算社区主办的全球边缘计算大会上海站成功召开&#xff0c;灵雀云凭借出色的全栈云原生技术实力、专业的高品质服务以及在边缘云场景的丰富落地实践&#xff0c;斩获“2022金边奖-最佳云原生边缘云平台”奖项。 “十四五”规划中明确指出要“协同发展云…

使用kubeadm部署kubernetes集群

文章目录环境环境初始化配置hosts配置时钟同步禁用firewalld、selinux、postfix禁用swap分区开启IP转发、修改内核信息配置IPVS安装Docker配置yum源安装docker-ce配置镜像加速器安装kubernetes组件配置yum源安装kubeadm、kubelet、kubectl工具配置containerd部署master安装pod网…

UTF-8、Unicode编码与汉字的相关内容

介绍 UTF-8是Unicode的一种实现方式&#xff0c;比如一个汉字用Unicode编码表示是两个字节&#xff0c;而用UTF8编码表示则为3个字节。 之所以写这篇文章&#xff0c;是因为我的webserver程序中&#xff0c;浏览器发送资源请求且该资源名为中文时出现了编码问题。 UTF8编码 U…

【SQL 中级语法 2】自连接的用法

SQL的连接运算根据其特征的不同&#xff0c;有着不同的名称&#xff0c;如内连接、外连接、交叉连接等。一般来说&#xff0c;这些连接大都是以不同的表或视图为对象进行的&#xff0c;但针对相同的表或相同的视图的连接也并没有被禁止。针对相同的表进行的连接被称为“自连接”…

python之排序

目录1. 对一维array中的数值进行从大到小排序2. 将DataFrame的列逆序排列3. 根据字符串中的数字进行排序3.2 啊4. 列表参考资料1. 对一维array中的数值进行从大到小排序 import numpy as np a np.array([5,6,8,2,1,7,5,3,90,78,62,5,4,2,9,4]) # b a.sort(axis0,kindquickso…

抑制剂拮抗剂等小分子化合物

小分子化合物主要通过调节其蛋白靶点的活性发挥作用。目前小分子化合物的蛋白靶点主要包括酶、离子通道和受体三大类。根据靶点种类的不同&#xff0c;小分子化合物发挥着不同的作用。 1. 酶的抑制剂&#xff08;enzyme inhibitor&#xff09; 在所有的小分子化合物中&#xff…

【虹科案例】虹科脉冲发生器在半导体行业中的应用

非易失性存储单元特点 存储器研究的趋势是开发一种称为非易失性 RAM 的新型存储器&#xff0c;它将 RAM 的速度与大容量存储器的数据存储相结合。几年来有许多新单元类型的提议&#xff0c;例如 FeRAM&#xff08;铁电存储器&#xff09;、ReRAM&#xff08;电阻式存储器&…

C++string类的模拟实现以及经验分享

文章目录1. 为什么学习string类&#xff1f;1.1 C语言中的字符串1.2 两个面试题2. string类的实现构造函数&#xff1a;拷贝构造函数赋值运算符重载&#xff1a;析构函数流提取运算符重载1. 为什么学习string类&#xff1f; 1.1 C语言中的字符串 C语言中&#xff0c;字符串是…

5款十分小众,却又非常好用的良心软件

今天推荐5款十分小众的软件&#xff0c;知道的人不多&#xff0c;但是每个都是非常非常好用的&#xff0c;有兴趣的小伙伴可以自行搜索下载。 1.杀毒软件——火绒安全软件 首先说一下国产杀软之光&#xff0c;这是一款电脑安全软件&#xff0c;病毒库更新及时&#xff0c;界面…

【文档+视频】Verdi基础教程

目录 前言 1.Verdi 环境配置 2.VCS 产生Verdi 波形 1、tb中加入相应的系统函数 2、makefile中加入相应的选项 3.nTrace 1、如何调用Verdi&#xff1f; 【重点】 2、如何查看包含的设计架构&#xff1f; 3、如何查寻模块实例化的位置&#xff1f;【重点】 4、在nTrace…

Linux网络编程11——简单的web服务器

学习视频链接 02-web大练习的概述_bilibili_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1iJ411S7UA/?p132&spm_id_frompageDriver&vd_source0471cde1c644648fafd07b54e303c905 目录 一、项目展示 二、HTTP 协议基础 2.1 HTTP协议基础。 2.2 请求消息(R…

个人博客系统

目录一、项目简介二、项目开发流程2.1 准备工作2.2 实现Vue层2.2 实现Model层2.4 实现Controller层一、项目简介 基于servlet&#xff0c;采用前后端分离的方式&#xff0c;实现个人博客系统&#xff0c;功能包括&#xff1a;登录、注销、编辑、删除博客、发布博客等. 二、项…

用了10年开源工具,换了Smartbi后,3分钟搞定一份报表

大约在20年前&#xff0c;中国企业开始应用国外BI软件&#xff0c;报表工具可以说是BI 1.0时代的代表产物。在BI软件盛行之初&#xff0c;大部分软件都有开源的&#xff0c;从系统到数据库到各类工具、应用&#xff0c;当时大部分企业使用的BI软件包括报表工具&#xff0c;也都…

外汇天眼:外汇占款是什么意思? 与外汇储备之间的差额是由哪些原因造成的?

外汇占款就是指受资国中央银行回收外汇财产而相对投放的本币。 因为人民币是是非非随意换取代币&#xff0c;外资企业导入后需换取成人民币才可以进到商品流通应用&#xff0c;国家以便外资企业兑换外币要投入很多的资产提升了贷币的需要量&#xff0c;产生了外汇占款。 外汇占…

线程池源码解析 3.excute() 方法

线程池源码解析—excute()方法 execute() execute 方法是线程池的核心方法&#xff0c;所有的方法&#xff0c;包括包装的 FutureTask&#xff0c;都是调用这个方法。 大致流程 这里只是总结了一遍大致的流程&#xff0c;一些细节问题见下面的流程图或者参考源码。 当提交任…

【毕业设计】大数据电商销售预测分析 - python 数据分析

文章目录1 前言2 开始分析2.1 数据特征2.2 各项投入与销售额之间的关系2.3 建立销售额的预测模型3 最后1 前言 &#x1f525; Hi&#xff0c;大家好&#xff0c;这里是丹成学长的毕设系列文章&#xff01; &#x1f525; 对毕设有任何疑问都可以问学长哦! 这两年开始&#x…

Java8新特性 CompletableFuture

Java8新特性 CompletableFuture 什么是CompletableFuture&#xff1f; CompletableFuture类的设计灵感来自于 Google Guava 的 ListenableFuture 类&#xff0c;它实现了 Future 和 CompletionStage 接口并且新增了许多方法&#xff0c;它支持 lambda表达式&#xff0c;通过回…

【IDEA插件】这5款IDEA插件,堪称代码BUG检查神器!

随着业务的发展&#xff0c;系统会越来越庞大&#xff0c;原本简单稳定的功能&#xff0c;可能在不断迭代后复杂度上升&#xff0c;潜在的风险也随之暴露&#xff0c;导致最终服务不稳定&#xff0c;造成业务价值的损失。而为了减少这种情况&#xff0c;其中一种比较好的方式就…

5.盒子阴影(重点)

提示&#xff1a;css3中新增了盒子阴影&#xff0c;我们可以使用box-shadow属性为盒子添加阴影。 1、语法&#xff1a; div{ box-shadow:"h-shadow"或者“v-shadow” } 解释&#xff1a; h-shadow 必须&#xff0c;水平阴影位置&#xff0c;允许负值。 v-shado…