IOC底层实现原理介绍,手动实现IOC容器

news2025/1/13 7:58:49

面试官特别爱问SpringIOC底层实现,Spring源码晦涩难懂怎么办呢? 跟着老师手动实现一个mini ioc容器吧,实现后再回头看Spring源码事半功倍哦,就算直接和面试官讲也完全可以哦,类名完全按照源码设计,话不多说开干~!

手动实现IOC容器的设计

需要实现的IOC功能:

·可以通过xml配置bean信息

·可以通过容器getBean获取对象

·能够根据Bean的依赖属性实现依赖注入

·可以配置Bean的单例多例

实现简易IOC设计的类

类/接口

说明

BeanFactory

IOC容器的基础接口,提供IOC容器的基本功能

DefaultListableBeanFactory

IOC容器的核心实现类,提供多个map集合用来存储bean的定义对象,提供getBean方法的核心实现

XmlBeanFactory

IOC容器的实现类,基于xml构建bean信息

XmlBeanDefinitionReader

用于解析xml信息,并提供解析Document文档的方法,并将解析到的BeanDefinition对象注册到核心容器中

BeanDefinition

封装Bean的定义对象,如: bean的id class,scope ..等等

Property

封装Bean所关联依赖的属性

类之间关系模型

前期准备

创建maven项目引入依赖

<dependencies><!-- 解析xml --><dependency><groupId>dom4j</groupId><artifactId>dom4j</artifactId><version>1.1</version></dependency><!-- BeanUtils    --><dependency><groupId>commons-beanutils</groupId><artifactId>commons-beanutils</artifactId><version>1.9.3</version></dependency></dependencies>

准备3个bean的实体类

/**
 * 学生类  
 * 学生类依赖班级对象
 * 并提供 sayHello() 方法
 * @作者 itcast
 * @创建日期 2020/3/7 19:46
 **/publicclassStudent{privateString name;privateTClass tClass;publicvoidsayHello(){System.out.println("大家好,我是"+this.name+" 我的班级是==>"+tClass.getCname()+" 我的老师是"+tClass.getTeacher().getTname());}publicStringgetName(){return name;}publicvoidsetName(String name){this.name = name;}publicTClassgettClass(){return tClass;}publicvoidsettClass(TClass tClass){this.tClass = tClass;}}
/**
 * 班级类
 * 班级类依赖教师对象
 * @作者 itcast
 * @创建日期 2020/3/7 19:45
 **/publicclassTClass{privateString cname;// 班级名称privateTeacher teacher;// 老师publicStringgetCname(){return cname;}publicvoidsetCname(String cname){this.cname = cname;}public com.itcast.ioc.bean.TeachergetTeacher(){return teacher;}publicvoidsetTeacher(com.itcast.ioc.bean.Teacher teacher){this.teacher = teacher;}}
/**
 * 教师类
 * @作者 itcast
 * @创建日期 2020/3/7 19:44
 **/publicclassTeacher{privateString tname;// 老师名称publicStringgetTname(){return tname;}publicvoidsetTname(String tname){this.tname = tname;}}

xml配置对象

配置学生对象: 小明

依赖班级对象: 3年2班

依赖教师对象: 陈老师

<?xml version="1.0" encoding="UTF-8"?><beans><!-- 配置IOC容器要管理的对象   bean作用域: 单例  原型 --><bean id="student"class="com.itcast.ioc.bean.Student" scope="singleton" lazy-init="true"><!-- 依赖注入:   属性注入    构造器注入   注解注入--><property name="name" value="小明"></property><property name="tClass" ref="tclass"></property></bean><bean id="tclass"class="com.itcast.ioc.bean.TClass"><property name="cname" value="3年2班"></property><property name="teacher" ref="teacher"></property></bean><bean id="teacher"class="com.itcast.ioc.bean.Teacher"><property name="tname" value="陈老师"></property></bean></beans>

mini-IOC容器-定义类

定义BeanFactory

/**
 * 容器的基础接口
 * 提供容器最基本的功能
 */publicinterfaceBeanFactory{// 核心方法 获取对象ObjectgetBean(String beanName);}

定义DefaultListableBeanFactory

packagecom.itcast.ioc.core;importjava.util.Map;importjava.util.concurrent.ConcurrentHashMap;/**
 * 基础容器的核心实现
 * 提供 beanDefinitionMap 存储bean的定义
 * 提供 singletonObjects 存储bean的对象实例
 * @作者 itcast
 * @创建日期 2020/7/8 15:37
 **/publicclassDefaultListableBeanFactoryimplementsBeanFactory{// 提供 beanDefinitionMap 存储bean的定义privateMap<String,BeanDefinition> beanDefinitionMap =newConcurrentHashMap<>();// 提供 singletonObjects 存储bean的对象实例 (scope为singleton的)privateMap<String,Object> singletonObjects =newConcurrentHashMap<>();/**
     * 实现getBean方法
     * @parambeanName
     * @return
     */@OverridepublicObjectgetBean(String beanName){returnnull;}/**
     * 将bean注册到容器中
     * @parambeanDefinition
     */publicvoidregisterBeanDefinition(BeanDefinition beanDefinition){
        beanDefinitionMap.put(beanDefinition.getBeanName(),beanDefinition);}}

定义BeanDefnition

/**
 * 用于描述Bean的定义
 * @作者 itcast
 * @创建日期 2020/7/8 15:41
 **/publicclassBeanDefinition{privateString beanName;// bean标签的ID 作为bean的唯一标识privateString className;// bean的所属classprivateString scope ="singleton";// bean的scope作用域privateList<Property> propertyList =newArrayList<>();publicStringgetBeanName(){return beanName;}publicvoidsetBeanName(String beanName){this.beanName = beanName;}publicStringgetClassName(){return className;}publicvoidsetClassName(String className){this.className = className;}publicStringgetScope(){return scope;}publicvoidsetScope(String scope){this.scope = scope;}publicList<Property>getPropertyList(){return propertyList;}publicvoidsetPropertyList(List<Property> propertyList){this.propertyList = propertyList;}}

定义Property

/**
 * 用于封装一个property标签
 * 属性数据
 * @作者 itcast
 * @创建日期 2020/7/8 15:44
 **/publicclassProperty{privateString name;// 属性名称privateString value;// 属性的值privateString ref;// 属性的引用publicStringgetName(){return name;}publicvoidsetName(String name){this.name = name;}publicStringgetValue(){return value;}publicvoidsetValue(String value){this.value = value;}publicStringgetRef(){return ref;}publicvoidsetRef(String ref){this.ref = ref;}}

定义XmlBeanFactory

/**
 * 继承核心实现类
 * 基于xml配置bean的实现类
 * @作者 itcast
 * @创建日期 2020/7/8 15:47
 **/publicclassXmlBeanFactoryextendsDefaultListableBeanFactory{/**
     * 将解析配置文件 注册bean的所有工作交给reader对象
     */finalXmlBeanDefinitionReader xmlBeanDefinitionReader =newXmlBeanDefinitionReader(this);/**
     * 构造器需要传入xml配置文件
     * @paramconfigPath
     */publicXmlBeanFactory(String configPath){// 使用reader对象 解析配置  注册Beanthis.xmlBeanDefinitionReader.loadBeanDefinitions(configPath);}}

定义XmlBeanDefinitionReader

/**
 * 解析配置
 * 注册到容器中
 * @作者 itcast
 * @创建日期 2020/7/8 15:51
 **/publicclassXmlBeanDefinitionReader{// 核心beanfactory对象 用于将解析后的bean注册到beanfactory中finalDefaultListableBeanFactory beanFactory;publicXmlBeanDefinitionReader(DefaultListableBeanFactory beanFactory){this.beanFactory = beanFactory;}/**
     * 根据传递的配置文件
     * 解析配置
     * 注册bean
     * @paramconfigPath
     */voidloadBeanDefinitions(String configPath){}}

mini-IOC容器--解析注册

实现步骤

1. 通过dom4j解析xml得到Document文档

2. 遍历文档所有Bean标签

3. 解析每一个Bean标签 封装一个BeanDefinition对象

4. 解析每一个Bean标签下的所有Property标签 封装一个Property对象

5. 将BeanDefinition和Property对象注册到容器

实现xml解析及bean注册

/**
 * 解析配置
 * 注册到容器中
 * @作者 itcast
 * @创建日期 2020/7/8 15:51
 **/publicclassXmlBeanDefinitionReader{// 核心beanfactory对象 用于将解析后的bean注册到beanfactory中finalDefaultListableBeanFactory beanFactory;publicXmlBeanDefinitionReader(DefaultListableBeanFactory beanFactory){this.beanFactory = beanFactory;}/**
     * 根据传递的配置文件
     * 解析配置
     * 注册bean
     * @paramconfigPath
     */voidloadBeanDefinitions(String configPath){// 1. 通过dom4j解析xml得到Document文档Document document =doLoadDocument(configPath);// 2. 遍历文档所有Bean标签Element rootElement = document.getRootElement();List<Element> list = rootElement.selectNodes("//bean");for(Element element : list){// 3. 解析每一个Bean标签 封装一个BeanDefinition对象BeanDefinition beanDefinition =parseBeanDefinition(element);// 5. 将BeanDefinition和Property对象注册到容器
            beanFactory.registerBeanDefinition(beanDefinition);}}/**
     * 3. 解析每一个Bean标签 封装一个BeanDefinition对象
     * 4. 解析每一个Bean标签下的所有Property标签 封装一个Property对象
     */BeanDefinitionparseBeanDefinition(Element element){BeanDefinition beanDefinition =newBeanDefinition();String beanName = element.attributeValue("id");String className = element.attributeValue("class");String scope = element.attributeValue("scope");
        beanDefinition.setBeanName(beanName);
        beanDefinition.setClassName(className);if(scope!=null&&!"".equals(scope)){
            beanDefinition.setScope(scope);}List<Element> propertyList = element.elements("property");for(Element propertyEle : propertyList){Property property =newProperty();
            property.setName(propertyEle.attributeValue("name"));
            property.setValue(propertyEle.attributeValue("value"));
            property.setRef(propertyEle.attributeValue("ref"));
            beanDefinition.getPropertyList().add(property);}return beanDefinition;}/**
     * 解析Document文档
     * @paramconfigPath
     * @return
     */DocumentdoLoadDocument(String configPath){InputStream inputStream =this.getClass().getClassLoader().getResourceAsStream(configPath);SAXReader saxReader =newSAXReader();try{return saxReader.read(inputStream);}catch(DocumentException e){
            e.printStackTrace();System.out.println("解析xml出现异常==>"+e.getMessage());thrownewRuntimeException(e.getMessage());}}}

准备测试类

/**
 * 测试类
 * @作者 itcast
 * @创建日期 2020/7/8 16:19
 **/publicclassIocTest{publicstaticvoidmain(String[] args){// 创建IOC容器BeanFactory beanFactory =newXmlBeanFactory("applicationContext.xml");// 通过容器获取对象Student student =(Student)beanFactory.getBean("student");// 调用对象sayHello方法
        student.sayHello();}}

断点查看注册情况

可以看到我们配置的xml内容 已经解析成了BeanDefinition对象,注册到了核心容器的map中

mini-IOC容器-getBean

实现步骤

1. 先从单例的map集合中获取 是否有指定beanName的对象

·有直接返回

·没有下一步

2. 从注册集合中获取bean的定义对象

·有下一步

·没有抛异常NoSuchBeanDefinition

3. 判断bean的scope作用域

singleton单例

· createBean对象

·存入单例集合

·返回对象

prototype多例

·createBean对象

·返回对象

4. createBean方法

获取BeanDefinition中的className

通过反射API得到Class对象

通过反射API得到bean实例

获取BeanDefinition中依赖的属性列表

实现属性的依赖注入

实现getBean及createBean方法

/**
 * 基础容器的核心实现
 * 提供 beanDefinitionMap 存储bean的定义
 * 提供 singletonObjects 存储bean的对象实例
 * @作者 itcast
 * @创建日期 2020/7/8 15:37
 **/publicclassDefaultListableBeanFactoryimplementsBeanFactory{// 提供 beanDefinitionMap 存储bean的定义privateMap<String,BeanDefinition> beanDefinitionMap =newConcurrentHashMap<>();// 提供 singletonObjects 存储bean的对象实例 (scope为singleton的)privateMap<String,Object> singletonObjects =newConcurrentHashMap<>();/**
     * 实现getBean方法
     * @parambeanName
     * @return
     */@OverridepublicObjectgetBean(String beanName){//        1. 先从单例的map集合中获取 是否有指定beanName的对象Object singletonObj = singletonObjects.get(beanName);//                有直接返回if(singletonObj!=null){return singletonObj;}//                没有下一步//        2. 从注册集合中获取bean的定义对象BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);//                有下一步//        没有抛异常NoSuchBeanDefinitionif(beanDefinition==null){thrownewRuntimeException("NoSuchBeanDefinition : 你找的 "+beanName+" 对象 不存在");}//        3. 判断bean的scope作用域String scope = beanDefinition.getScope();//                singleton单例if("singleton".equals(scope)){//        createBean对象Object obj =createBean(beanDefinition);//        存入单例集合
            singletonObjects.put(beanName,obj);//        返回对象return obj;}else{//        prototype多例//        createBean对象returncreateBean(beanDefinition);//        返回对象}}/**
     * //4. createBean方法
     * //获取BeanDefinition中的className
     * //通过反射API得到Class对象
     * //通过反射API得到bean实例
     * //获取BeanDefinition中依赖的属性列表
     * //实现属性的依赖注入
     * 创建对象
     * @parambeanDefinition
     * @return
     */ObjectcreateBean(BeanDefinition beanDefinition){String className = beanDefinition.getClassName();Class<?> aClass;try{
            aClass =Class.forName(className);}catch(ClassNotFoundException e){
            e.printStackTrace();thrownewRuntimeException("类未找到"+e.getMessage());}// 创建对象:Object obj;try{
            obj = aClass.newInstance();}catch(InstantiationException e){
            e.printStackTrace();thrownewRuntimeException("创建对象失败"+e.getMessage());}catch(IllegalAccessException e){
            e.printStackTrace();thrownewRuntimeException("非法访问"+e.getMessage());}// 依赖注入List<Property> propertyList = beanDefinition.getPropertyList();for(Property property : propertyList){String name = property.getName();String value = property.getValue();String ref = property.getRef();// 属性名不为空 进行注入if(name!=null&&!"".equals(name)){// 如果配置的是value值 直接注入if(value!=null&&!"".equals(value)){Map<String,String> params =newHashMap<>();
                    params.put(name,value);try{BeanUtils.populate(obj,params);}catch(IllegalAccessException e){
                        e.printStackTrace();thrownewRuntimeException("非法访问"+e.getMessage());}catch(InvocationTargetException e){
                        e.printStackTrace();thrownewRuntimeException("调用目标对象失败"+e.getMessage());}}// 如果配置的是ref需要获取其它对象注入if(ref!=null&&!"".equals(ref)){try{BeanUtils.setProperty(obj,name,getBean(ref));}catch(IllegalAccessException e){
                        e.printStackTrace();thrownewRuntimeException("非法访问"+e.getMessage());}catch(InvocationTargetException e){
                        e.printStackTrace();thrownewRuntimeException("调用目标对象失败"+e.getMessage());}}}}return obj;}/**
     * 将bean注册到容器中
     * @parambeanDefinition
     */publicvoidregisterBeanDefinition(BeanDefinition beanDefinition){
        beanDefinitionMap.put(beanDefinition.getBeanName(),beanDefinition);}}

mini-IOC容器-单例对象初始化

DefaultListableBeanFactory增加初始化方法

publicvoidpreInstaniceSingletons(){
        beanDefinitionMap.forEach((beanName,beanDefinition)->{String scope = beanDefinition.getScope();// 判断单例  非抽象   不懒加载if("singleton".equals(scope)){this.getBean(beanName);}});}

XmlBeanFactory增加单例对象初始化

publicXmlBeanFactory(String configPath){// 使用reader对象 解析配置  注册Beanthis.xmlBeanDefinitionReader.loadBeanDefinitions(configPath);// 初始化单例对象this.preInstaniceSingletons();}

mini-IOC容器-测试和小结

测试对象能否获取

查看bean的注册及单例集合信息

可以通过变更scope的值查看对应的变化

IOC容器源码及其它面试细节

扩展: 容器如何创建对象

IOC容器在准备创建对象时, 会判断是否有配置 factory-method方法

如果有配置 会调用factory-method所指向的方法构建对象.

如果没配置,会检查是否有配置构造参数

无构造参数: 调用默认构造器创建对象

有构造参数: 根据参数情况匹配对应的构造器

扩展: bean的生命周期

spring 容器中的bean的完整生命周期一共分为十一步完成。

1.bean对象的实例化

2.封装属性,也就是设置properties中的属性值

3.如果bean实现了BeanNameAware,则执行setBeanName方法,也就是bean中的id值

4.如果实现BeanFactoryAware或者ApplicationContextAware ,需要设置setBeanFactory或者上下文对象setApplicationContext

5.如果存在类实现BeanPostProcessor后处理bean,执行postProcessBeforeInitialization,可以在初始化之前执行一些方法

6.如果bean实现了InitializingBean,则执行afterPropertiesSet,执行属性设置之后的操作

7.调用执行指定的初始化方法

8.如果存在类实现BeanPostProcessor则执行postProcessAfterInitialization,执行初始化之后的操作

9.执行自身的业务方法

10.如果bean实现了DisposableBean,则执行spring的的销毁方法

11.调用执行自定义的销毁方法。

扩展: bean的循环依赖问题

A 依赖 B B 依赖 A 产生闭环,称为循环依赖

·Spring 默认允许单例对象的属性注入 所产生的循环依赖

单例对象的循环依赖 Spring通过3级缓存来解决

比如一个类A中有一个属性是B类,B类中有一个属性是A类,这时看Spring是怎么解决他们的相互依赖的。Spring注入一个类的大体步骤分为两部分,一是先完成对类的构造工作,二是会对类的属性进行设置和填充。首先Spring构造A类,通过AbstractAutowireCapableBeanFactory的doCreateBean方法中调用addSingletonFactory方法将A类曝光到singletonFactories中。这时完成A的构造后,需要填充B属性,继续第二步,发现B还没有构造,于是开始B流程的构造过程,构造的时候发现需要填充A,从第三层缓存singletonFactories中找到A(此时的A还没有完全构造完成,但是可以拿到A的一个引用),B拿到A的引用后,完成B自己的填充属性工作,完成初始化工作,把自己放到第一层缓存singletonObjects中。这时回到A的这边,在拿到B对象后,完成自己的填充属性工作。

源码

级别

描述

singletonObjects

一级缓存

用于存放完全初始化好的 bean,从该缓存中取出的 bean 可以直接使用

earlySingletonObjects

二级缓存

存放原始的 bean 对象(尚未填充属性),用于解决循环依赖

singletonFactories

三级缓存

存放 bean 工厂对象,用于解决循环依赖

·如果是构造器依赖属性 会报循环依赖异常

·如果对象都是多例对象 会报循环依赖异常

·如果设置allowCircularReferences为false 会报循环依赖异常

protectedvoidcustomizeBeanFactory(DefaultListableBeanFactory beanFactory){if(this.allowBeanDefinitionOverriding !=null){
      beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);}if(this.allowCircularReferences !=null){
      beanFactory.setAllowCircularReferences(this.allowCircularReferences);}}

扩展: bean的覆盖问题

默认情况:

同一个配置文件中出现id相同的bean会报错,不同的配置文件出现id相同的bean后加,载的bean会将先加载的bean覆盖掉称为bean的覆盖,bean的覆盖不会报错,但可能影响我们的项目,可以通过属性设置不允许bean的覆盖,allowBeanDefinitionOverriding设置为false。

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

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

相关文章

葡聚糖-叶酸;Dextran-FA;Dextran-Folicacid 结构式;科研试剂简介

名称&#xff1a;Dextran-Folicacid 中文名&#xff1a;叶酸修饰的葡聚糖 别称&#xff1a;葡聚糖-FA,葡聚糖-叶酸 存储条件&#xff1a;-20C&#xff0c;避光&#xff0c;避湿 外观: 固体或类白色絮状&#xff0c;取决于分子量 溶剂&#xff1a;溶于大部分有机溶剂&#…

HTAP 能够取代 OLAP 吗?

HTAP是什么 HTAP(Hybrid Transaction and Analytical Processing)数据库&#xff0c;也称混合型关系数据库&#xff0c;是能同时提供OLTP和OLAP的混合关系型数据库。在互联网浪潮出现之前&#xff0c;企业的数据量普遍不大&#xff0c;特别是核心的业务数据&#xff0c;通常一个…

【深入理解JVM】垃圾收集器内存分配策略

目录 gc root对象有哪些 oopMap 安全点&#xff08;safe point&#xff09; 安全区域 卡表 伪共享问题 三色标记法 垃圾收集器 CMS G1 gc root对象有哪些 虚拟机栈中引用的对象&#xff08;虚拟机栈中的引用的对象可以作为GC Root。我们程序在虚拟机的栈中执行&…

Redis安装及常用配置详解

一般redis安装于linux服务器&#xff0c;故本例介绍的是Linux下的安装一. Redis下载1. 官网下载tar包可以到​​ ​redis的官网​​​找到各个Redis版本的下载地址,如: https://redis.io/download/#redis-downloads&#xff0c;最新稳定版是7.0版2. 使用wget 下载redis在官网中…

无桥PFC的家族推演

1. 组合法构建无桥PFC PFC是一种AC-DC变换器&#xff0c;将交流输入电压分成正负半周&#xff0c;输出电压是直流&#xff0c;因此AC-DC变换器可以当做是两个DC-DC变换器的组合。在PFC的拓扑推演中&#xff0c;就是设计两个DC-DC变换器的工作模式。以下内容是基于对陈正格博士发…

流程编辑器bpmnjs的改造3:加一个审批人的设置

默认的设计器有代理人、候选用户和候选组&#xff0c;但是并不能满足实际的业务需求&#xff0c;我们需要对它进行改造&#xff0c;使得我们能够按照自定义的规则来生成用户任务节点的审批人。1、在bpmnjs里面加一个审批人的输入部件打开resources/properties-panel/provider/a…

MD5算法全解析

前言 这段时间刚好正在做软件安全的实验和课设&#xff0c;学习了各种加密算法&#xff0c;比如对称加密算法的DES,AES&#xff1b;非对称加密算法的RSA&#xff1b;再如今天要讲的主角-单向加密算法的MD5。为什么这么多算法&#xff0c;MD5成为了今天的猪脚呢&#xff1f;&am…

nexus raw 仓库代理(node-sass 内网下载问题)

问题背景 内网环境中使用 node 构建项目&#xff0c;项目中依赖了 node-sass&#xff0c;环境自动下载 node-saas 失败&#xff08;内网&#xff09;。 下面是构建 node-sass 的错误代码&#xff1a; [5/5] Building fresh packages... error /workspace/node_modules/node-…

FreeRTOS-消息队列详解

✅作者简介&#xff1a;嵌入式入坑者&#xff0c;与大家一起加油&#xff0c;希望文章能够帮助各位&#xff01;&#xff01;&#xff01;&#xff01; &#x1f4c3;个人主页&#xff1a;rivencode的个人主页 &#x1f525;系列专栏&#xff1a;玩转FreeRTOS &#x1f4ac;保持…

burpsuite安装HTTPS证书

burpsuite安装HTTPS证书1.Burpsuite介绍1.1.Burpsuite安装2.https证书介绍2.1.证书下载步骤2.1.1.打开burp软件2.1.2.开启代理2.1.3.下载证书2.1.4.证书2.2.证书安装步骤2.2.1.打开证书页2.2.2.导入证书2.2.3.确认安装2.3.抓包测试1.Burpsuite介绍 Burp Suite 是用于攻击web 应…

OpenStack 扩容cpu、内存

创建要扩容的实例类型&#xff0c;也就是flavor获取要扩容的server id根据命令 nova list获取刚才创建好的实例类型id根据命令 nova flavor-list执行扩容的命令nova resize <server-id> <flavor-id>举例&#xff1a;nova resize 06be1c3d-bcfb-4038-ae28-f8e7ac0a2…

【AI奇技淫巧】使用Optuna进行机器学习模型调参

使用Optuna进行机器学习模型调参Optuna简介框架特点安装方式举个例子高级配置搜索方式分支&#xff08;Branches&#xff09;与循环&#xff08;Loops&#xff09;分布式优化命令行界面用户定义属性将用户定义属性添加到Study将用户属性添加到Trial中对无望的Trial进行剪枝&…

大前端—回顾2022年明星项目,展望2023发展前沿

导读 | 2022年是艰难的一年&#xff0c;不仅有互联网的寒冬、还有新冠疫情的洗礼。但是似乎这一切都阻挡不了JavaScript的内卷&#xff0c;一年不长不短的时间中&#xff0c;JavaScript从创新、性能、功能等多维度深度进化&#xff0c;给前端带来了诸多惊喜。本文基于github上流…

(十三)并发集合——ConcurrentSkipListMap/Set

ConcurrentSkipListMapConcurrentSkipListMap与TreeMap对应&#xff0c;相当于线程安全的TreeMap&#xff0c;key有序&#xff0c;TreeMap基于红黑树&#xff0c;ConcurrentSkipListMap基于跳表。无锁链表的问题用跳表而不用红黑树是因为目前计算机领域还未找到一种高效的、作用…

LabVIEW测试和调试Web服务

LabVIEW测试和调试Web服务发布Web服务至终端前&#xff0c;需要测试HTTP方法VI是否按照预期与客户端进行通信。可直接从LabVIEW项目将Web服务置于调试服务器上&#xff0c;从而允许客户端发送请求至HTTP方法VI。调试服务器提供类似沙盒的环境。1. (Windows) 右键单击我的电脑下…

JVM- 第二章-类加载子系统

类加载子系统 2. 类加载子系统 2.1. 内存结构概述2.2. 类加载器与类的加载过程 加载阶段链接阶段初始化阶段 2.3. 类加载器分类 2.3.1. 虚拟机自带的加载器2.3.2. 用户自定义类加载器 2.4. ClassLoader的使用说明2.5. 双亲委派机制2.6. 其他 2. 类加载子系统 2.1. 内存结构…

nacos

文章目录1、认识和安装nacos&#xff08;单机安装&#xff09;1.1、下载安装包1.2、解压1.3、端口配置1.4、启动1.5、访问2、nacos快速入门2.1、在父工程中添加依赖2.2、注释掉服务中原有的eureka依赖2.3、添加nacos的客户端依赖2.4、修改配置文件2.5、启动并测试2.6、总结3、n…

19、Java并发 Java wait() 和 notify() 方法

大家有没有发现&#xff0c;其实 「 一文秒懂 」 系列讲述的都是多线程并发开发的问题。这个话题太大了&#xff0c;估计没有上百篇文章都解释不清楚。 本文&#xff0c;我们来讲解下 Java 并发中的基础的基础&#xff0c;核心的核心&#xff0c;Java 并发编程中的最基本的机制…

为什么 APISIX Ingress 是比 Ingress NGINX 更好的选择?

作者容鑫&#xff0c;API7.ai 云原生技术工程师&#xff0c;Apache APISIX Committer。 本文将会对比两个比较流行的 Ingress controller 实现&#xff0c;希望能对读者进行 Ingress controller 选型中有所帮助。 Ingress NGINX 是 Kubernetes 社区实现的 Ingress controller&a…

高通量代谢组学四路筛选法,揭秘“神药”二甲双胍延长寿命的机制

百趣代谢组学分享—研究背景 目前据统计中国糖尿病患者人数达9700万以上&#xff0c;数量达到世界第一。这其中2型糖尿病占到了90%以上。二甲双胍是目前治疗2型糖尿病的一线“明星”药物&#xff0c;因其较少出现低血糖和体重增加副作用而受到广大患者和医生的青睐。代谢组学文…