spring高级篇(十)

1、内嵌tomcat

        boot框架是默认内嵌tomcat的,不需要手动安装和配置外部的 Servlet 容器。

        简单的介绍一下tomcat服务器的构成:

  • Catalina: Catalina 是 Tomcat 的核心组件,负责处理 HTTP 请求、响应以及管理 Servlet 生命周期。它包括一个 Web 容器和一个 Servlet 引擎,用于处理 Servlet 和 JSP 页面。
  • Connector: 连接器是 Tomcat 与外部客户端之间通信的桥梁,负责处理传入的 HTTP 请求,并将其传递给 Catalina 处理。Tomcat 提供了多种类型的连接器,包括 HTTP 连接器(用于处理 HTTP 请求)、AJP 连接器(用于与 Apache HTTP Server 连接)等。
  • Realm: Realm 是 Tomcat 的安全认证和授权机制,用于验证用户身份并控制用户对受保护资源的访问权限。Tomcat 支持多种类型的 Realm,如基于内存的 Realm、基于数据库的 Realm 等。
  • Valves: 阀门是 Tomcat 的拦截器组件,用于在请求处理过程中执行特定的操作,如访问日志记录、安全验证、压缩等。Tomcat 提供了多种类型的阀门,可以通过配置文件进行灵活配置。
  • Host: Host 是 Tomcat 的虚拟主机,用于在同一物理服务器上托管多个域名或应用程序。每个 Host 都有一个唯一的名称和基础目录,可以配置不同的域名和应用程序。
  • Engine: Engine 是 Tomcat 的引擎,用于管理多个虚拟主机(Host)。它负责调度请求到相应的虚拟主机,并协调虚拟主机之间的资源共享和管理。
  • Context: Context 是 Tomcat 的上下文容器,用于管理和配置单个 Web 应用程序的运行环境。每个 Web 应用程序都有一个对应的 Context,包括其配置信息、Servlet 映射、Session 管理等。

        我们来模拟一下tomcat的执行过程:

        其中第四步是将下面自定义的servlet程序放入servletContext上下文中,并且手动指定映射路径(相当于Controller层加入@RequestMapping及派生注解指定路径)

public class A36 {public static void main(String[] args) throws IOException, LifecycleException {//1.创建tomcat对象Tomcat tomcat = new Tomcat();tomcat.setBaseDir("tomcat");//准备docBase,存放项目文件File docBase = Files.createTempDirectory("boot.").toFile();docBase.deleteOnExit();//3.创建tomcat项目 contextContext context = tomcat.addContext("", docBase.getAbsolutePath());//4.编程添加servletcontext.addServletContainerInitializer(new ServletContainerInitializer() {@Overridepublic void onStartup(Set<Class<?>> set, ServletContext servletContext) throws ServletException {servletContext.addServlet("test",new MyServlet()).addMapping("/test");}}}, Collections.emptySet());//5.启动tomcattomcat.start();//6.设置协议,创建连接器Connector connector = new Connector(new Http11Nio2Protocol());connector.setPort(8080);tomcat.setConnector(connector);}
}

        编写一个自定义的servlet程序:

public class MyServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {resp.getWriter().print("abc");}
}

        而内嵌的tomcat如何与Spring进行整合?

        其关键点在于Config配置类中的 public DispatcherServletRegistrationBean registrationBean(DispatcherServlet dispatcherServlet) 方法。这个方法用于注册DispatcherServlet springmvc入口并创建一个 DispatcherServletRegistrationBean Bean,将传入的 DispatcherServlet 注册到 Spring 应用程序中。

       Config配置类又是在refresh容器前注册的:

 public static WebApplicationContext webApplicationContext(){AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();context.register(Config.class);context.refresh();return context;}

       我们只需要在编程添加servlet这一步,获取容器中所有的bean,并且通过.onStartup() 方法完成注册:

     //得到applicationContextWebApplicationContext applicationContext = webApplicationContext();//4.编程添加servletcontext.addServletContainerInitializer(new ServletContainerInitializer() {@Overridepublic void onStartup(Set<Class<?>> set, ServletContext servletContext) throws ServletException {servletContext.addServlet("test",new MyServlet()).addMapping("/test");//得到ServletRegistrationBean中每一个注册的beanfor (ServletRegistrationBean value : applicationContext.getBeansOfType(ServletRegistrationBean.class).values()) {value.onStartup(servletContext);}}}, Collections.emptySet());

        .onStartup() 方法底层调用的依旧是 servletContext.addServlet()  方法

        boot在整合tomcat时,首先是创建了Spring容器,然后在调用onfresh()方法时会将tomcat创建出来,并且执行到添加servlet。

        在finishRefresh(); 方法会启动tomcat服务器并且设置协议,创建连接器。

2、自动装配原理

        现在有如下的场景:在某个包下创建了两个bean,并且将其注册到了两个配置类中:

public class Bean1 {}
public class Bean2 {
}
@Configuration
public class Config1 {@Beanpublic Bean1 bean1(){return new Bean1("第三方");}
}
@Configuration
public class Config2 {@Beanpublic Bean2 bean2(){return new Bean2();}
}

        假设这两个bean都是与数据库连接有关的组件,具有通用性。那么难道是每次在别的地方用到的时候,都去临时注册吗?答案肯定是否定的,就和方法封装一样,我们可以在其他运用到的地方进行导入:

        @Import 注解的作用就是导入其他配置类或组件类,如果在  @Import 注解中将Config1和Config2 的class 写死,这样不太好:

@Configuration
@Import(MyInportSelector.class)
public class MyConfig {@Beanpublic Bean1 bean1(){return new Bean1("本项目");}
}

        我们可以将Config1和Config2注册在自定义的MyInportSelector类中统一管理:

        在Spring中,某个自定义ImportSelector类下需要统一装配的组件,不是写死在自定义ImportSelector类中的,而是放在META-INF下的spring.factories中统一进行管理。

/*** 读取配置文件中的引用*/
public class MyInportSelector implements ImportSelector {/*** 在方法中会读取所有jar包 META-INF下的spring.factories 做自动装配* @param importingClassMetadata* @return*/@Overridepublic String[] selectImports(AnnotationMetadata importingClassMetadata) {//需要自动装配的类不是写死在代码中的,而是放在配置文件中的//从配置文件中读取信息 META-INF下的spring.factories//com.itbaima.a37.MyInportSelector=\//com.itbaima.a37_1.Config1,\//com.itbaima.a37_1.Config2List<String> strings = SpringFactoriesLoader.loadFactoryNames(MyInportSelector.class, null);return strings.toArray(new String[0]);}
}

        完成EnableAutoConfiguration的自动装配:

/*** 读取配置文件中的引用*/
public class MyInportSelector implements ImportSelector {/*** 在方法中会读取所有jar包 META-INF下的spring.factories 做自动装配* @param importingClassMetadata* @return*/@Overridepublic String[] selectImports(AnnotationMetadata importingClassMetadata) {for (String name : SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class, null)) {System.out.println(name);}}
}

         那如果在本项目注册的bean和其他外部引用的bean同名的问题呢?

         生效的是本项目中的。因为bean加载的时机不同,第三方的bean先加载,后加载的bean会覆盖先加载的同名的bean。然而在boot中默认是false不允许覆盖。解决方法:

        自定义的InportSelector实现DeferredImportSelector接口,可以推迟第三方bean的加载。并且需要在注册第三方bean时加上 @ConditionalOnMissingBean 注解,表明当容器中没有该名称的bean时才需要加载。(因为此时本项目中的bean已先于第三方的bean加载)

@Configuration
public class Config1 {@Bean@ConditionalOnMissingBean//当容器中缺少某个bean时才会添加public Bean1 bean1(){return new Bean1("第三方");}
}

3、AopAutoConfiguration

        AopAutoConfiguration是用于负责配置和启用 AspectJ 面向切面编程(AOP)功能。

        我们模拟一下它的自动装配:

@Configuration
@Import(MyImportSelector.class)
public class Config {
}
public class MyImportSelector implements ImportSelector {@Overridepublic String[] selectImports(AnnotationMetadata importingClassMetadata) {return new String[]{AopAutoConfiguration.class.getName()};}
}
public class A38 {public static void main(String[] args) {GenericApplicationContext context = new GenericApplicationContext();//注册各种后处理器AnnotationConfigUtils.registerAnnotationConfigProcessors(context.getDefaultListableBeanFactory());context.registerBean(Config.class);context.refresh();for (String name : context.getBeanDefinitionNames()) {System.out.println(name);}}
}

        下面这四条便是AopAutoConfiguration通过自动装配得到的BeanDefinitionName

org.springframework.boot.autoconfigure.aop.AopAutoConfiguration$AspectJAutoProxyingConfiguration$CglibAutoProxyConfiguration
org.springframework.aop.config.internalAutoProxyCreator
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration$AspectJAutoProxyingConfiguration
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration

        那么AopAutoConfiguration是如何选择装配哪些bean的呢?我们点进AopAutoConfiguration的源码看一下:

        @ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true) 是一个针对properties配置文件内容的判断,此处判断的含义是,如果配置文件中没有spring.aop前缀的键,或者有并且它的值为true时,会进入这个类。显然目前的条件是成立的,我们自定义的配置类中没有spring.aop前缀的键。

        在静态内部类AspectJAutoProxyingConfiguration上也有一个注解:@ConditionalOnClass(Advice.class) 作用是判断是否存在一个名为Advice的类,在boot中是存在的,所以会进入AspectJAutoProxyingConfiguration类:

         

        在JdkDynamicAutoProxyConfiguration和CglibAutoProxyConfiguration静态内部类上,分别有两个注解:

  • @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false") 判断properties配置文件中是否有spring.aop前缀的键,并且值要为false。
  • @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = true) 判断properties配置文件中是否有spring.aop前缀的键,并且值要为ture,或者不存在。

        而两个静态内部类上标注的@EnableAspectJAutoProxy 注解,实际上也是加上了@Import

注解的自动装配配置类:

        自定义的自动装配了类实现了ImportBeanDefinitionRegistrar接口,用于用编程的方式确定装配的内容:

        在AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); 方法中,实际上是注册了AnnotationAwareAspectJAutoProxyCreator:

        复习一下(第三篇):AnnotationAwareAspectJAutoProxyCreator是用于自动创建代理以实现切面功能的Spring后处理器,将高级的Aspect切面分解并转换成低级的Advice切面,并且根据设置去选择JDK或CGLIB代理方式(proxyTargetClass属性),在AnnotationAwareAspectJAutoProxyCreator中,有两个重要的方法:

  • protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName):用于查找符合条件的切面通知器(Advisors)。
  • protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey):内部调用 .findEligibleAdvisors得到存放符合条件切面通知器的集合,如果集合不为空,就创建代理。

         根据条件,应该会自动装配CglibAutoProxyConfiguration:

        可从容器中获取AnnotationAwareAspectJAutoProxyCreator,isProxyTargetClass的取值是true,代表无论是否实现了接口,走的都是CGLIB代理方式。

AnnotationAwareAspectJAutoProxyCreator proxyCreator = context.getBean(AnnotationAwareAspectJAutoProxyCreator.class);
System.out.println(proxyCreator.isProxyTargetClass());

4、DataSource

        在DataSourceAutoConfiguration中,主要有两部分:

  • EmbeddedDatabaseConfiguration:Spring Framework 中用于配置内嵌式数据库(Embedded Database)的自动配置类之一
  • PooledDataSourceConfiguration:Spring Framework 中用于配置连接池数据源(Pooled DataSource)的自动配置类之一。

         EmbeddedDatabaseConfiguration很少用到,我们重点看PooledDataSourceConfiguration:

        DataSourceConfiguration的每个静态内部类上都加入了@ConditionalOnClass 条件判断注解。

        Boot中默认是有HikariDataSource源的:

        所以会将HikariDataSource注册成bean并设置连接信息:

5、MybatisAutoConfiguration

        在MybatisAutoConfiguration类上,有如下的注解:

  • @ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class}) :表明必须要存在SqlSessionFactory和SqlSessionFactoryBean两个类。因为mybatis与boot整合需要数据源连接信息。
  • @ConditionalOnSingleCandidate(DataSource.class) :表明数据源必须是唯一的,不能存在多份不同的数据源
  • @EnableConfigurationProperties({MybatisProperties.class}) : 表明将来会创建一个MybatisProperties对象,用于将环境中的键值信息与对象绑定(要求配置中的键名必须前缀mybatis):
  • @AutoConfigureAfter({ DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class }) : 表明该配置类是在DataSourceAutoConfiguration、MybatisLanguageDriverAutoConfiguration加载完成后再进行初始化。

        上述任何一个条件不满足都不会进入MybatisAutoConfiguration:

         public SqlSessionFactory sqlSessionFactory(DataSource dataSource) 方法用于创建SqlSessionFactory的bean,注意加上了@ConditionalOnMissingBean 代表容器中没有其他第三方的SqlSessionFactory的bean时,才会初始化MybatisAutoConfiguration中的SqlSessionFactory。

         public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) 方法用于创建SqlSession模板:

         SqlSessionTemplate是线程安全的,在同一个线程中,不同方法可以共用一个实例。

        最后还有一个MapperScannerRegistrarNotFoundConfiguration内部类:        

        它只有在没有自定义的MapperFactoryBean和MapperScannerConfigurer时才会生效:

        然后通过@Import(AutoConfiguredMapperScannerRegistrar.class) 注解导入了AutoConfiguredMapperScannerRegistrar,作用是扫描和引导类同包下的被@Mapper注解控制的mapper/dao接口,将这些定义为bean

6、DataSourceTransactionManagerAutoConfiguration

        DataSourceTransactionManagerAutoConfiguration是用于自动配置数据源事务管理器(DataSource Transaction Manager)的类之一。

  • 在类上标注了@ConditionalOnClass({ JdbcTemplate.class, TransactionManager.class }) 注解,要求必须要有事务管理器和JDBC模板方法。
  •  @EnableConfigurationProperties(DataSourceProperties.class) 会将配置文件中以spring.datasource为前缀的key绑定到DataSourceProperties对象中(设置数据库连接信息,username,password...)

         并且导入了EnableConfigurationPropertiesRegistrar自动装配类。

        同样JdbcTransactionManagerConfiguration静态内部类限定容器中只能有一份数据源:

  • DataSourceTransactionManager:创建处理与JDBC 数据源相关的事务的Bean。


        下面介绍一些与整合Spring MVC相关的配置类:

7、TransactionAutoConfiguration

      TransactionAutoConfiguration 是用于自动配置事务管理的类之一。

  • @ConditionalOnClass(PlatformTransactionManager.class) 表明容器中必须要有PlatformTransactionManager类,简单来说,它定义了事务管理器的核心功能。      
  • @AutoConfigureAfter({ JtaAutoConfiguration.class, HibernateJpaAutoConfiguration.class,DataSourceTransactionManagerAutoConfiguration.class, Neo4jDataAutoConfiguration.class }) 表明TransactionAutoConfiguration是在@AutoConfigureAfter 注解value中的类初始化成后再加载。
  • @EnableConfigurationProperties(TransactionProperties.class) 可以将配置文件中以spring.transaction为前缀的key绑定到TransactionProperties对象上。

        并且导入了EnableConfigurationPropertiesRegistrar自动装配类

        TransactionAutoConfiguration类中,提供了声明式和响应式事务的支持:

        以及创建事务管理器:

        还有配置声明式事务的管理:

8、ServletWebServerFactoryAutoConfiguration

        是 Spring Boot 中负责配置 Servlet 容器工厂的自动配置类之一:

  • @ConditionalOnClass(ServletRequest.class):ServletRequest类存在,条件成立。(ServletRequest定义了客户端向服务器发送的 HTTP 请求的主要属性和操作。它是一个核心组件,用于在服务器端处理 HTTP 请求,HttpServletRequest就是它的子类)
  • @ConditionalOnWebApplication(type = Type.SERVLET) :应用程序是一个 Servlet Web 应用程序时,条件成立
  • @EnableConfigurationProperties(ServerProperties.class):用于启用特定类型的配置属性绑定到ServerProperties对象中。

        这个类中主要注册了两个Bean:

  • ServletWebServerFactoryCustomizer:这个方法的主要作用是根据传入的参数定制 Servlet Web 服务器工厂的行为,包括配置服务器属性、注册 Web 监听器以及处理 Cookie 的 SameSite 属性。
  • TomcatServletWebServerFactoryCustomizer:这个方法的主要作用是根据传入的参数定制 Tomcat Servlet Web 服务器的行为,包括配置服务器属性、Session 会话管理、安全性等方面。

9、DispatcherServletAutoConfiguration

        用于配置和启用 DispatcherServlet。DispatcherServlet 是 Spring MVC 中的中央调度器,用于处理传入的 HTTP 请求,并将它们分发到相应的处理程序(Controller)进行处理:

  •  @ConditionalOnWebApplication(type = Type.SERVLET) :应用程序是一个 Servlet Web 应用程序时,条件成立
  • @ConditionalOnClass(DispatcherServlet.class) :容器中必须包含DispatcherServlet类,条件成立
  • @AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class :在ServletWebServerFactoryAutoConfiguration类装配完成后( Servlet 容器工厂创建完成),装配本类。

        在这个类中,较为重要的是DispatcherServletConfiguration和DispatcherServletRegistrationConfiguration两个静态内部类:

  • DispatcherServletConfiguration:主要是将DispatcherServlet注册成bean,以及一个解析客户端发送的包含文件上传的 HTTP 请求,并将上传的文件转换成可操作的对象的bean
  • DispatcherServletRegistrationConfiguration:主要作用是将DispatcherServletRegistrationBean注册成bean,并且设置tomcat容器启动时即进行DispatcherServlet初始化

10、WebMvcAutoConfiguration

        主要用于配置和初始化 Spring MVC 的各种组件:

        RequestMappingHandlerAdapter:

        RequestMappingHandlerMapping:

         ExceptionHandlerExceptionResolver:

11、ErrorMvcAutoConfiguration

        主要作用是在应用程序启动时,自动配置一些默认的错误处理策略和错误页面。

        此前提到的BasicErrorController(处理基本的错误页面和错误信息),ErrorPageRegistrar(转发到自定义的错误页面),在本类中都有体现:

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

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

相关文章

OpenHarmony实战开发-应用侧调用前端页面函数

应用侧可以通过runJavaScript()方法调用前端页面的JavaScript相关函数。 在下面的示例中&#xff0c;点击应用侧的“runJavaScript”按钮时&#xff0c;来触发前端页面的htmlTest()方法。 前端页面代码。 <!-- index.html --> <!DOCTYPE html> <html> <…

图片浏览器-PicView

一、前言 PicView 是一款适用于 Windows 10 或 11 的快速高效的图像查看器&#xff0c;配备了干净简洁的用户界面&#xff0c;可以在不需要时方便地隐藏。 二、支持类型 它支持广泛的图像文件类型&#xff0c;包括&#xff1a;WEBP、GIF、SVG、PNG、JXL、HEIC、PSD 三、软件特…

红日靶场ATTCK 1通关攻略

环境 拓扑图 VM1 web服务器 win7&#xff08;192.168.22.129&#xff0c;10.10.10.140&#xff09; VM2 win2003&#xff08;10.10.10.135&#xff09; VM3 DC win2008&#xff08;10.10.10.138&#xff09; 环境搭建 win7&#xff1a; 设置内网两张网卡&#xff0c;开启…

CNN笔记详解

CNN(卷积神经网络) 计算机视觉&#xff0c;当你们听到这一概念的是否好奇计算机到底是怎样知道这个图片是什么的呢&#xff1f;为此提出了卷积神经网络&#xff0c;通过卷积神经网络&#xff0c;计算机就可以识别出图片中的特征&#xff0c;从而识别出图片中的物体。看到这里充…

Python安装以及环境配置

目录 一、下载安装包二级目录三级目录 一、下载安装包 方式网址Python官网python.org镜像下载地址Download pythonpycharmDownload PyCharm https://blog.csdn.net/sun80760/article/details/135256627 二级目录 三级目录

认识ansible 了解常用模块

ansible是什么&#xff1f; Ansible是一个基于Python开发的配置管理和应用部署工具&#xff0c;现在也在自动化管理领域大放异彩。它融合了众多老牌运维工具的优点&#xff0c;Pubbet和Saltstack能实现的功能&#xff0c;Ansible基本上都可以实现。是自动化运维工具&#xff0…

机器人操作系统ROS2学习 1

随着智能化时代的进程&#xff0c;机器人也在向着高度智能化的方向发展&#xff0c;这对应的机器人操作系统也就相应而生了。机器人操作系统ROS (Robot Operating System)的诞生为机器人系统的开发与应用带来了很大方便&#xff0c;也聚集了全球大量的应用开发人员推动ROS的发展…

hadoop学习---基于Hive的数仓搭建增量信息拉链表的实现

拉链表就是SCD2&#xff0c;它的优点是即满足了反应数据的历史状态&#xff0c;又能在最大程度上节省存储。 拉链表的实现需要在原始字段基础上增加两个新字段&#xff1a; start_time(表示该条记录的生命周期开始时间——周期快照时的状态)end_time(该条记录的生命周期结束时…

Python项目实战,用Python实现2048游戏

目录 写在前言项目介绍项目思路环境搭建项目实现初始化Python类初始化游戏窗口定义游戏棋盘和方块移动和合并游戏主循环 进一步探索 写在前言 hello&#xff0c;大家好&#xff0c;我是一点&#xff0c;专注于Python编程&#xff0c;如果你也对感Python感兴趣&#xff0c;欢迎…

在2G到4g小区重选过程中,4g频点没有优先级信息,最后UE无法重选到4g,是否正常?

这个确实是老问题了&#xff0c;要翻开GSM 的协议找答案。 GSM cell reselection算法分为cell ranking based和priority based两种方式。cell ranking based 只能从GSM重选到UTRAN&#xff1b;而priority based则可以重选到UTRAN和EUTRA。 根据priority based重选算法的描述&am…

Flink窗口理论到实践 | 大数据技术

⭐简单说两句⭐ ✨ 正在努力的小叮当~ &#x1f496; 超级爱分享&#xff0c;分享各种有趣干货&#xff01; &#x1f469;‍&#x1f4bb; 提供&#xff1a;模拟面试 | 简历诊断 | 独家简历模板 &#x1f308; 感谢关注&#xff0c;关注了你就是我的超级粉丝啦&#xff01; &a…

数据库原理与应用实验三 嵌套查询

实验目的和要求 加深和掌握对嵌套查询的理解和应用 实验环境 Windows10 SQLServer 实验内容与过程 图书&#xff08;书号&#xff0c;书名&#xff0c;价格&#xff0c;出版社&#xff09; 读者&#xff08;卡号&#xff0c;姓名&#xff0c;年龄&#xff0c;所属单位&a…

Vue 基础语法

【1】模板语法 &#xff08;1&#xff09;差值表达式 {{}}是 Vue.js 中的文本插值表达式。 它用于在模板中输出数据或表达式的值。当数据或表达式的值发生变化时&#xff0c;插值表达式会自动更新。 补充&#xff1a;三目运算符 它的基本语法是 Condition ? A : B&#xff0…

一起了解开源自定义表单的优势表现

随着社会的进步和科技的发展&#xff0c;越来越多的中小企业希望采用更为先进的软件平台&#xff0c;助力企业实现高效率的流程化管理。低代码技术平台、开源自定义表单已经慢慢走入大众视野&#xff0c;成为一款灵活、高效的数字化转型工具。流辰信息专注于低代码技术平台的研…

鸿蒙内核源码分析(原子操作篇) | 谁在为原子操作保驾护航

基本概念 在支持多任务的操作系统中&#xff0c;修改一块内存区域的数据需要“读取-修改-写入”三个步骤。然而同一内存区域的数据可能同时被多个任务访问&#xff0c;如果在修改数据的过程中被其他任务打断&#xff0c;就会造成该操作的执行结果无法预知。 使用开关中断的方…

更适合宝妈和上班族的兼职,每天2小时收入250+的微头条项目

许多人通过撰写微头条赚取收入&#xff0c;但这通常需要自己寻找素材&#xff0c;然后逐字逐句地进行改编创作&#xff0c;整个过程既繁琐又低效。 然而&#xff0c;如今全球范围内的AI工具正如雨后春笋般涌现。百度推出了文心一言&#xff0c;阿里巴巴推出了AI工具通义千问&a…

JavaSE_抽象类(抽象类概念、语法、、特性、作用)

前言 在上一节中&#xff0c;我们讲解了JAVA中的继承&#xff0c;在本节讲解java中抽象类与接口&#xff0c;这个在程序设计中是非常重要的。 一、什么是抽象类 1.1 抽象类概念 基本概念&#xff1a; 在面向对象的概念中&#xff0c;所有的对象都是通过类来描绘的&#xff0…

动态规划——背包问题(01,完全,多重)

一、01背包问题 1.题目描述 有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。第 i 件物品的体积是 vi&#xff0c;价值是 wi。 求解将哪些物品装入背包&#xff0c;可使这些物品的总体积不超过背包容量&#xff0c;且总价值最大。输出最大价值。 01背包问题特点&…

客户管理软件排行榜:对比18款CRM

本文将对比18个客户管理软件&#xff1a;纷享销客、Zoho CRM、Salesforce、HubSpot CRM、Pipedrive、Freshsales、Microsoft Dynamics 365 CRM、Insightly CRM、Nimble CRM、Apptivo CRM、SugarCRM、白码CRM、简信CRM、销帮帮CRM、Teamface企典CRM、神州云动CRM、悟空CRM、八百…

由于找不到msvcp120.dll,无法继续执行代码的5种解决方法

在操作计算机的过程中&#xff0c;您或许会遇到这样一种情形&#xff1a;当试图启动某个软件应用程序时&#xff0c;系统突然弹出一个错误提示框&#xff0c;明确指出“找不到msvcp120.dll”&#xff0c;它会导致程序无法正常启动或运行。为了解决这个问题&#xff0c;我总结了…