【Springboot 入门培训 】#19 Spring Boot 组件扫描与bean生命周期
目录
- 1 什么是组件扫描
- 2 何时使用组件扫描
- 3 扫描整个包`basePackages`与 includeFilters
- 4 Spring boot 的 Bean 生命周期
- 4.1 生命周期
- 4.2 Bean 生命周期
- 4.3 周期各个阶段
首先,我想先为你介绍一下“Spring”,这是一个开放源代码的设计模式解决方案和轻量级的反转控制(IoC)和面向切面(AOP)的容器框架。在这个框架中,有一个重要的概念叫做“组件扫描”。
1 什么是组件扫描
为了进行依赖注入,Spring 创建了一个所谓的应用程序上下文。在启动期间,Spring 实例化对象并将它们添加到应用程序上下文中。应用程序上下文中的对象称为“Spring beans”或“组件”。Spring 解决了 Spring bean 之间的依赖关系,并将 Spring bean 注入到其他 Spring bean 的字段或构造函数中。
那么,什么是组件扫描呢?组件扫描就是Spring框架用来发现并自动注册你的应用程序中的bean的方式。这些bean可以是任何用@Component,@Controller,@Service,@Repository或者其他注解标记的类。Spring框架会扫描这些标记,并在应用程序的上下文中创建和管理这些bean。
1. 启动 Spring 应用|
2. 查找所有的 `@Configuration` 类|
3. 找到 `ExplicitScan` 类|
4. 发现 `@ComponentScan` 注解,读取 `basePackages` 属性|
5. 从 `io.reflectoring.vehicles` 包开始,扫描这个包和它的所有子包|
6. 对每个找到的类,检查是否存在 `@Component`、`@Service`、`@Repository`、`@Controller`等 Spring 注解|
7. 对于带有这些注解的类,将它们注册为 Spring Beans
在类路径中搜索应该对应用程序上下文有贡献的类的过程称为组件扫描。
@Component
这是一个通用的构造型注释,用于指示该类是 Spring 管理的组件。其他刻板印象是@Component.
@Controller
这表明带注释的类是一个 Spring 管理的控制器,它提供带注释的方法@RequestMapping来响应 Web 请求。
Spring 4.0 引入了@RestController结合了@Controller和 的注释@ResponseBody,使得创建返回 JSON 对象-的 RESTful 服务变得容易。
@Service
我们可以将@Service构造型用于包含业务逻辑的类或来自服务层的类。
@Repository
我们可以使用@Repository负责提供对数据库实体的访问的 DAO 类的构造型。
如果我们使用 Spring Data 来管理数据库操作,那么我们应该使用 Spring Data Repository 接口而不是构建我们自己的@Repository-annotated 类。
2 何时使用组件扫描
组件扫描的实现是通过@ComponentScan注解来实现的。如果你的应用是一个Spring Boot应用,那么,包含Spring Boot应用类的包以及其下的所有包都会被一个隐式的组件扫描所覆盖。这是因为Spring Boot的@SpringBootApplication注解包含了@Configuration, @ComponentScan, 和@EnableAutoConfiguration三个注解。
默认情况下,@ComponentScan注解会扫描当前包以及其所有子包的组件。所以,如果你的应用程序的包结构没有变化,你不需要显式地进行组件扫描。注意,如果你在默认的包中指定了带有@Configuration注解的类,Spring会扫描类路径中所有JAR文件的所有类。这种情况不是很推荐的,如果项目jar包的数量很巨大那么注解会扫描的时间会很长,导致启动的时间会很慢。
我们利用@ComponentScan和@Configuration注解引导 Spring 扫描带有各种构造型注解的类。注解@ComponentScan有多个属性,这些属性可以根据我们的需求进行调整以获得预期的扫描行为。
我们将使用 的ApplicationContext方法getBeanDefinitionNames()来检查已成功扫描并添加到应用程序上下文的 beans 列表。
@Component
class BeanViewer {private final Logger LOG = LoggerFactory.getLogger(getClass());@EventListenerpublic void showBeansRegistered(ApplicationReadyEvent event) {String[] beanNames = event.getApplicationContext().getBeanDefinitionNames();for(String beanName: beanNames) {LOG.info("{}", beanName);}}
}
以上BeanViewer将打印在应用程序上下文中注册的所有 beans。这将帮助我们检查我们的组件是否正确加载。
例子1 同一个包下:
让我们用一个实例来解释这个过程。假设我们有一个应用程序,其结构如下:
|- com.example.demo (main package)|- DemoApplication.java (Spring Boot Application class)|- UserService.java (@Service annotated class)|- BeanViewer.java
当我们启动这个 Spring Boot 应用时,UserService 类会被自动扫描并作为一个 Spring bean 注册到应用程序上下文中,因为它位于 DemoApplication.java 同一个包或其子包下。
例子2 不在同包下:
现在,假设我们有另一个包,它并不在 DemoApplication.java 的包或子包下:
|- com.example.demo|- DemoApplication.java|- UserService.java
|- com.example.utils|- UtilityService.java (@Service annotated class)
在这种情况下,UtilityService 类不会被默认的组件扫描机制捕捉到。
为了让 Spring 扫描并注册这个类,我们需要在 DemoApplication.java 类或任何其他的配置类上添加 @ComponentScan 注解,并指定 com.example.utils 作为需要扫描的包。
@SpringBootApplication
@ComponentScan(basePackages = "com.example.utils")
public class DemoApplication {// ...
}
当然,@ComponentScan 注解也支持更多的定制,@ComponentScan注解提供了更多的定制化选项让我们看一下它可以用来修改其行为的注释的属性:
basePackages:获取应扫描组件的包名称列表。basePackageClasses:获取应扫描其包的类的列表。includeFilters:使我们能够指定应扫描哪些类型的组件。excludeFilters: 这是相反的includeFilters。我们可以在扫描时根据条件指定条件来忽略某些组件。useDefaultFilters:如果为真,它会启用自动检测带有任何构造型注释的类。如果为 false,则将包含属于includeFilters和定义的过滤条件的组件。excludeFilters
在控制组件扫描时,需要对此类配置项有深入的理解,这样可以帮助我们创建出优雅和高效的 Spring 应用。
3 扫描整个包basePackages与 includeFilters
在了解了如何使用Spring的@ComponentScan注解,我们可以开始深入探索其高级选项,例如定制包扫描以及包含和排除过滤器。
首先,我们创建一个ExplicitScan类,并将其放在主应用程序包io.reflectoring.componentscan中。这样,该类就会被Spring的默认组件扫描捕获。然后,我们在该类中使用@ComponentScan注解,并通过basePackages属性指定另一个包io.reflectoring.vehicles作为扫描目标:
package io.reflectoring.componentscan;
@Configuration
@ComponentScan(basePackages= "io.reflectoring.vehicles")
public class ExplicitScan {
}
运行这个应用程序,我们可以看到vehicles包中的所有组件都被成功地注册到了应用程序的上下文中。其中,BeanViewer类的日志输出就是这个结果的直接证明。
includeFilters
那么,如果我们只希望包含某个特定类型的组件呢?比如,我们只希望包含扩展了Zht类的组件。这时,我们就可以使用includeFilters属性并配合FilterType.ASSIGNABLE_TYPE过滤器来实现这个需求:
@Configuration
@ComponentScan(basePackages= "io.reflectoring.vehicles",includeFilters=@ComponentScan.Filter(type=FilterType.ASSIGNABLE_TYPE,classes=Zht.class),useDefaultFilters=false)
public class ExplicitScan {
}
在这个例子中,我们修改了ExplicitScan类以包含扩展了Zht类的组件,同时设置useDefaultFilters为false以禁用默认的过滤器。运行这个应用程序,只有继承Zht类的组件会被扫描到,因为它们都扩展了Zht类。
其他可用的过滤器类型是:
ANNOTATION:仅匹配具有特定构造型注释的类。ASPECTJ: 使用 AspectJ 类型模式表达式匹配类ASSIGNABLE_TYPE:匹配扩展或实现此类或接口的类。REGEX:使用包名称的正则表达式匹配类。
在上面的例子中,我们修改了我们的ExplicitScan类以includeFilters包含扩展的组件Car.class,我们正在改变useDefaultFilters = false以便只应用我们的特定过滤器。
excludeFilters
另一方面,我们也可以使用excludeFilters属性来排除一些我们不希望被组件扫描捕获的类。同样,我们需要配合FilterType.ASSIGNABLE_TYPE过滤器来实现这个需求:
@Configuration
@ComponentScan(basePackages= "io.reflectoring.vehicles",excludeFilters=@ComponentScan.Filter(type=FilterType.ASSIGNABLE_TYPE,classes=Car.class))
public class ExplicitScan {
}
在这个例子中,我们没有设置useDefaultFilters为false,所以默认的过滤器仍然会被应用。运行这个应用程序,继承Zht类的组件会被排除在了组件扫描之外。
最后,我想强调一下,@ComponentScan注解是一个强大的工具,但也需要谨慎使用。否则,它可能会让你的应用程序的组成规则变得混乱。为了保持清晰和明确的规则,一个好的做法是在一个显式导入的@Configuration类中使用@ComponentScan注解,并且仅仅自动扫描这个类所在的包。这样,我们就可以更好地管理和控制我们的应用程序上下文了
4 Spring boot 的 Bean 生命周期
现在开始我们称,在创建、编排和销毁ApplicationContext方面受 Spring 控制的每个对象都称为 Spring Bean。
通过上面的介绍我们知道定义 Spring bean 的最常见方法是使用注解@Component:
@Component
class MySpringBean {...
}
如果启用了 Spring boot的组件扫描,则会将一个对象MySpringBean添加到应用程序上下文中。
另一种方法创建Spring bean的方法式在@Configuration注解类中创建一个@Bean注解方法来返回MySpringBean类的对象,让这个类对象变为spring bean。
@Configuration
class MySpringConfiguration {@Beanpublic MySpringBean mySpringBean() {return new MySpringBean();}
}
4.1 生命周期
当我们看到 Spring bean 的生命周期时,生命周期时分为对象实例化到销毁的许多阶段。为了方便大家理解,我们将它们分为创建和销毁阶段。
Bean 创建阶段
- **实例化:**这是 bean 的一切开始的地方。Spring 实例化 bean 对象就像我们手动创建 Java 对象实例一样。
- **填充属性:**实例化对象后,Spring 扫描实现接口的 bean
Aware并开始设置相关属性。 - 预初始化: Spring
BeanPostProcessor在此阶段开始运行。这些postProcessBeforeInitialization()方法完成了他们的工作。此外,@PostConstruct带注释的方法会在它们之后运行。 - AfterPropertiesSet: Spring 执行
afterPropertiesSet()实现InitializingBean. - 自定义初始化:
initMethodSpring 触发我们在注释属性中定义的初始化方法@Bean。 - 初始化后: Spring 的
BeanPostProcessors 第二次起作用。此阶段触发postProcessAfterInitialization()方法。
Bean 销毁阶段
- Pre-Destroy: Spring
@PreDestroy在这个阶段触发带注解的方法。 - 销毁: Spring 执行实现
destroy()的方法DisposableBean。 - 自定义销毁:
destroyMethod我们可以使用注释中的属性定义自定义销毁挂钩@Bean,Spring 在最后阶段运行它们。
Spring Bean生命周期
1. 实例化 Bean|
2. 填充属性|
3. 预初始化 - `postProcessBeforeInitialization()` 方法|
4. 执行 `@PostConstruct` 注解的方法|
5. 调用 `afterPropertiesSet()` 方法(如果Bean实现了`InitializingBean`接口)|
6. 执行自定义初始化方法(如果在 `@Bean` 注解中定义了 `initMethod` 属性)|
7. 初始化后 - `postProcessAfterInitialization()` 方法|V
(在这里, Bean处于完全初始化和可用的状态, 直到它被销毁)|
8. 调用 `@PreDestroy` 注解的方法|
9. 执行 `destroy()` 方法(如果Bean实现了`DisposableBean`接口)|
10. 执行自定义销毁方法(如果在 `@Bean` 注解中定义了 `destroyMethod` 属性)|V
(在这里, Bean被完全销毁, 并从Spring应用上下文中移除)
1 启动接口
我们可以实现 Spring 的InitializingBean接口中的afterPropertiesSet()方法启动Spring bean 生命周期。
@Component
class MySpringBean implements InitializingBean {@Overridepublic void afterPropertiesSet() {}
}
2 销毁接口
同样的,我们可以实现DisposableBean接口的destroy()方法销毁阶段的方法。
@Component
class MySpringBean implements DisposableBean {@Overridepublic void destroy() {//...}
}
3 JSR-250 注释启动与销毁
我们可以使用Spring JSR-250标准中的@PostConstruct和@PreDestroy方法,将它们挂钩到预初始化和销毁阶段。
@Component
class MySpringBean {@PostConstructpublic void postConstruct() {}@PreDestroypublic void preDestroy() {}
}
4 使用@Bean注释的属性
此外,我们在创建 Spring bean 时,可以在 @Bean 配置中设置注解的initMethod属性和destroyMethod属性来设置初始化启动和销毁。
@Configuration
class MySpringConfiguration {@Bean(initMethod = "onInitialize", destroyMethod = "onDestroy")public MySpringBean mySpringBean() {return new MySpringBean();}
}
我们应该注意,如果我们的 bean 中有一个名为close()or的公共方法shutdown(),那么默认情况下它会自动触发销毁回调。
@Component
class MySpringBean {public void close() {}
}
如果我们不希望这种默认销毁行为,我们可以通过设置禁用destroyMethod=""来关闭它。
@Configuration
class MySpringConfiguration {@Bean(destroyMethod = "")public MySpringBean mySpringBean() {return new MySpringBean();}
}
5 BeanPostProcessor 设置
我们可以利用该BeanPostProcessor接口在 Spring bean 初始化之前或之后运行任何自定义操作,来实现启动和销毁bean。
class MyBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName)throws BeansException {return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName)throws BeansException {return bean;}
}
6 使用Aware接口
进入生命周期的另一种方法是使用接口Aware来实现启动与销毁。
@Component
class MySpringBean implements BeanNameAware, ApplicationContextAware {@Overridepublic void setBeanName(String name) {//...}@Overridepublic void setApplicationContext(ApplicationContext applicationContext)throws BeansException {//...}}
4.2 Bean 生命周期
当我们需要调整我们的软件以满足新的需求时,寻找最佳实践以维持我们代码库的长期可维护性是至关重要的。在 Spring 框架中,大多数情况下,挂钩到 bean 生命周期是扩展我们应用程序的好方法。让我们深入了解一下这个过程。
1 BeanNameAware 接口
一种常见的情况是在运行时获取 bean 的属性,如 bean 的名称。例如,当我们需要在日志中记录 bean 的创建:
@Component
class NamedSpringBean implements BeanNameAware {Logger logger = LoggerFactory.getLogger(NamedSpringBean.class);public void setBeanName(String name) {System.out.println(name + "获得bean名字");}
}
在这个例子中,我们通过实现 BeanNameAware 接口,能够在 Spring 创建 bean 时获取其名称,从而可以在日志中记录它。
2 动态改变bean实例
我们可能需要以编程方式定义 Spring bean。这在我们需要动态地创建和更改 bean 实例的情况下特别有用。例如,我们可以创建一个 IpToLocationService,这个服务可以动态地更新 IpDatabaseRepository 以便它始终使用最新版本的数据库:
@Service
class IpToLocationService implements BeanFactoryAware {DefaultListableBeanFactory listableBeanFactory;IpDatabaseRepository ipDatabaseRepository;@Overridepublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {listableBeanFactory = (DefaultListableBeanFactory) beanFactory;updateIpDatabase();}public void updateIpDatabase(){}}
在这个例子中,我们通过实现 BeanFactoryAware 接口来获取 BeanFactory 实例,此外我们在方法中updateIpDatabase()获取实例后立即调用我们的方法。因此,我们可以在 Spring 上下文启动时创建 bean 的第一个实例。BeanFactory``setBeanFactory()``IpDatabaseRepository
另一种情况是从 Spring 上下文之外访问ApplicationContextor实例。BeanFactory
例如,我们可能希望将 注入BeanFactory到非 Spring 类中,以便能够访问该类中的 Spring bean 或配置。
class AutowireCapableJobFactoryextends SpringBeanJobFactory implements ApplicationContextAware {private AutowireCapableBeanFactory beanFactory;@Overridepublic void setApplicationContext(final ApplicationContext context) {beanFactory = context.getAutowireCapableBeanFactory();}@Overrideprotected Object createJobInstance(final TriggerFiredBundle bundle)throws Exception {final Object job = super.createJobInstance(bundle);beanFactory.autowireBean(job);return job;}
}
在此示例中,我们使用ApplicationContextAware接口来访问 bean 工厂,并使用 bean 工厂自动装配Job最初不受 Spring 管理的 bean 中的依赖项。
此外,也可以用 Spring - Jersey集成,Jersey也是常用的一种方法。
@Configuration
class JerseyConfig extends ResourceConfig {@Autowiredprivate ApplicationContext applicationContext;@PostConstructpublic void registerResources() {applicationContext.getBeansWithAnnotation(Path.class).values().forEach(this::register);}
}
通过将 Jersey 标记ResourceConfig为 Spring @Configuration,我们注入ApplicationContext并查找所有由 Jersey 注释的 bean @Path,以便在应用程序启动时轻松注册它们。
4.3 周期各个阶段
下面大家可以看到Spring bean生命周期中各个阶段的执行顺序。
class MySpringBean implements BeanNameAware, ApplicationContextAware,InitializingBean, DisposableBean {private String message;public void sendMessage(String message) {this.message = message;}public String getMessage() {return this.message;}@Overridepublic void setBeanName(String name) {System.out.println("--- setBeanName executed ---");}@Overridepublic void setApplicationContext(ApplicationContext applicationContext)throws BeansException {System.out.println("--- setApplicationContext executed ---");}@PostConstructpublic void postConstruct() {System.out.println("--- @PostConstruct executed ---");}@Overridepublic void afterPropertiesSet() {System.out.println("--- afterPropertiesSet executed ---");}public void initMethod() {System.out.println("--- init-method executed ---");}@PreDestroypublic void preDestroy() {System.out.println("--- @PreDestroy executed ---");}@Overridepublic void destroy() throws Exception {System.out.println("--- destroy executed ---");}public void destroyMethod() {System.out.println("--- destroy-method executed ---");}}
此外,我们创建了一个BeanPostProcessor挂钩到初始化之前和之后的阶段:
class MyBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName)throws BeansException {if (bean instanceof MySpringBean) {System.out.println("--- postProcessBeforeInitialization executed ---");}return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName)throws BeansException {if (bean instanceof MySpringBean) {System.out.println("--- postProcessAfterInitialization executed ---");}return bean;}}
接下来,我们编写一个 Spring 配置来定义我们的 bean:
@Configuration
class MySpringConfiguration {@Beanpublic MyBeanPostProcessor myBeanPostProcessor(){return new MyBeanPostProcessor();}@Bean(initMethod = "initMethod", destroyMethod = "destroyMethod")public MySpringBean mySpringBean(){return new MySpringBean();}}
最后,我们编写一个@SpringBootTest来运行我们的 Spring 上下文:
@SpringBootTest
class BeanLifecycleApplicationTests {@Autowiredpublic MySpringBean mySpringBean;@Testpublic void testMySpringBeanLifecycle() {String message = "Hello World";mySpringBean.sendMessage(message);assertThat(mySpringBean.getMessage()).isEqualTo(message);}}
因此,我们的测试方法记录了生命周期阶段之间的执行顺序:
--- setBeanName executed ---
--- setApplicationContext executed ---
--- postProcessBeforeInitialization executed ---
--- @PostConstruct executed ---
--- afterPropertiesSet executed ---
--- init-method executed ---
--- postProcessAfterInitialization executed ---
...
--- @PreDestroy executed ---
--- destroy executed ---
--- destroy-method executed ---
在本文中,我们了解了 bean 生命周期阶段是什么、为什么以及我们如何挂接到 Spring 中的生命周期阶段。Spring 在 bean 生命周期中有许多阶段以及许多接收回调的方法。我们可以像在BeanPostProcessor。尽管每个方法都有其用途,但我们应该注意使用 Spring 接口将我们的代码耦合到 Spring Framework。
另一方面,@PostConstruct注释@PreDestroy是 Java API 的一部分。因此,我们认为它们是接收生命周期回调的更好替代方案,因为它们甚至可以将我们的组件与 Spring 分离。
系列文章目录
【Springboot 入门培训 】#1 MyBatis项目运行环境配置
【Springboot 入门培训 】#2 MyBatis 增改删除与查询 in like foreach操作
【Springboot 入门培训 】#3 MyBatis 多数据源与缓存和数据连接池设置
【Springboot 入门培训 】#4 WEB+JSP MVC项目搭建
【Springboot 入门培训 】#5 WEB+Thymeleaf MVC项目搭建与测试
【Springboot 入门培训 】#6 (Framework7 移动 webapp) WEB APP 项目搭建
【Springboot 入门培训 】#7 (Framework7 移动webapp) 页面路由跳转
【Springboot 入门培训 】#8 (Framework7 移动webapp) Component 模板MVVM与AJAX
【Springboot 入门培训 】# 9 Security(一) 登录验证初始化
【Springboot 入门培训 】#10 Security(二) 数据库DB 登录验证
【Springboot 入门培训 】#11 Security(三) json 前后端分离跨域登录
【Springboot 入门培训 】#12 Security(四) Jwt 前后端分离跨域登录
【Springboot 入门培训 】#13 Security(五) oauth2 基础应用
【Springboot 入门培训 】#14 WebJars 样式包BootStrap 5架构
【Springboot 入门培训 】#15 MyBatis-Thymeleaf 插件在项目中的应用
【Springboot 入门培训 】#16 Spring boot 日志 Slf4j + Logback
【Springboot 入门培训 】#17 WebJars + BootStrap5 常用JS组件应用
【Springboot 入门培训 】#18 SpringBoot Cache 缓存实现
Spring boot 中Thymeleaf 模板 html 标签使用
相关文章:
【Springboot 入门培训 】#19 Spring Boot 组件扫描与bean生命周期
目录 1 什么是组件扫描2 何时使用组件扫描3 扫描整个包basePackages与 includeFilters4 Spring boot 的 Bean 生命周期4.1 生命周期4.2 Bean 生命周期4.3 周期各个阶段 首先,我想先为你介绍一下“Spring”,这是一个开放源代码的设计模式解决方案和轻量级…...
Linux printf 函数输出问题
printf 函数并不会直接将数据输出到屏幕,而是先放到缓冲区中,只有一下三种情况满足,才会输出到屏幕。 1) 缓冲区满 2) 强制刷新缓冲区 fflush 3) 程序结束时 1 #include<stdio.h>2 #include<st…...
皮卡丘Unsafe Fileupload
1.不安全的文件上传漏洞概述 文件上传功能在web应用系统很常见,比如很多网站注册的时候需要上传头像、上传附件等等。当用户点击上传按钮后,后台会对上传的文件进行判断 比如是否是指定的类型、后缀名、大小等等,然后将其按照设计的格式进行…...
最优化简明版(上)
引言 本文简单地介绍一些凸优化(Convex Optimization)的基础知识,可能不会有很多证明推导,目的是能快速应用到机器学习问题上。 凸集 直线与线段 设 x 1 ≠ x 2 x_1 \neq x_2 x1x2为 R n \Bbb R^n Rn空间中的两个点,那么具有下列形…...
MySQL的一些介绍
1. SQL的select语句完整的执行顺序 SQL Select语句完整的执行顺序: 1、from子句组装来自不同数据源的数据; 2、where子句基于指定的条件对记录行进行筛选; 3、group by子句将数据划分为多个分组; 4、使用聚集函数进行计算&am…...
unity发布webGL后无法预览解决
众所周知,unity发布成webgl后是无法直接预览的。因为一般来说浏览器默认都是禁止webgl运行的。 直接说我最后的解决方法:去vscode里下载一个live server ,安装好。 下载vscode地址Visual Studio Code - Code Editing. Redefined 期间试过几种方法都不管…...
Flume和Kafka的组合使用
一.安装Kafka 1.1下载安装包 通过百度网盘分享的文件:复制链接打开「百度网盘APP 即可获取」 链接:https://pan.baidu.com/s/1vC6Di3Pml6k1KMbnK0OE1Q?pwdhuan 提取码:huan 也可以访问官网,下载kafka2.4.0的安装文件 1.2解…...
JSONSQL:使用SQL过滤JSON类型数据(支持多种数据库常用查询、统计、平均值、最大值、最小值、求和语法)...
1. 简介 在开发中,经常需要根据条件过滤大批量的JSON类型数据。如果仅需要过滤这一种类型,将JSON转为List后过滤即可;如果相同的条件既想过滤数据库表中的数据、也想过滤内存中JSON数据,甚至想过滤Elasticsearch中的数据ÿ…...
Linux输入输出重定向
目录 Linux输入输出重定向 Linux中的默认设备 输入输出重定向定义 输入输出重定向操作符 实用形式 标准输入、标准输出、标准错误 输出重定向案例 案例1 --- 输出重定向(覆盖) 案例2 --- 输出重定向(追加) 案例3 --- 错误…...
使用kettle进行数据统计
1.使用kettle设计一个能生成100个取值范围为0到100随机整数的转换。 为了完成该转换,需要使用生成记录控件、生成随机数控件、计算器控件及字段选择控件。控件布局如下图所示 生成记录控件可以在限制框内指定生成记录的个数,具体配置如图所示 生成随机数…...
线程的取消和清理
一、线程的取消 意义:随时杀掉一个线程 int pthread_cancel(pthread_t thread); 注意:线程的取消要有取消点才可以,不是说取消就取消,线程的取消点主要是阻塞的系统调用 二、运行段错误调试 可以使用gdb调试 使用gdb 运行代…...
day8 -- 全文本搜索
brief InnoDB存储引擎从MySQL 5.6开始支持全文本搜索。具体来说,MySQL使用InnoDB存储引擎的全文本搜索功能称为InnoDB全文本搜索(InnoDB Full-Text Search)。InnoDB全文本搜索支持标准的全文本搜索查询语法和多语言分词器,因此可…...
C语言:if-else语句
嗨,今天咱们讲讲C语言控制语句里的条件选择,主要总结下if else语句。 咱们生活里经常会有这样的场景,明天该怎么穿呢,得考虑下具体的天气。如果是晴天,温度还不错,可以穿T恤;如果是阴天…...
C语言---函数
1、函数是什么 学习库函数网站: https://cplusplus.com/reference/http://en.cppreference.comhttp://zh.cppreference.com 我们参考文档,学习几个库函数 2、库函数 3、自定义函数 自定义函数和库函数一样,有函数名,返回值类…...
【JVM】什么是双亲委派机制?
一、为什么会有这种机制? 类加载器将.class类加载到内存中时,为了避免重复加载(确保Class对象的唯一性)以及JVM的安全性,需要使用某一种方式来实现只加载一次,加载过就不能被修改或再次加载。 二、什么是双…...
Vulkan Tutorial 7 纹理贴图
目录 23 图像 图片库 暂存缓冲区 纹理图像 布局转换 将缓冲区复制到图像上 准备纹理图像 传输屏障掩码 清除 24 图像视图和采样器 纹理图像视图 采样器 Anisotropy 设备特征 25 组合图像采样器 更新描述符 纹理坐标系 着色器 23 图像 添加纹理将涉及以下步骤&am…...
LinkedBlockingQueue阻塞队列
➢ LinkedBlockingQueue阻塞队列 LinkedBlockingQueue类图 LinkedBlockingQueue 中也有两个 Node 分别用来存放首尾节点,并且里面有个初始值为 0 的原子变量 count 用来记录队列元素个数,另外里面有两个ReentrantLock的独占锁,分别用来控制…...
面试-Redis 常见问题,后续面试遇到新的在补充
面试-Redis 1.谈谈Redis 缓存穿透,击穿,雪崩及如何避免 缓存穿透:是指大量访问请求在访问一个不存在的key,由于key 不存在,就会去查询数据库,数据库中也不存在该数据,无法将数据存储到redis 中…...
2023年上半年数据库系统工程师上午真题及答案解析
1.计算机中, 系统总线用于( )连接。 A.接口和外设 B.运算器、控制器和寄存器 C.主存及外设部件 D.DMA控制器和中断控制器 2.在由高速缓存、主存和硬盘构成的三级存储体系中,CPU执行指令时需要读取数据,那么DMA控制器和中断CPU发出的数据地…...
设计模式概念
设计模式是软件工程领域中常用的解决问题的经验总结和最佳实践。它们提供了一套被广泛接受的解决方案,用于处理常见的设计问题,并促进可重用、可扩展和易于维护的代码。 设计模式的主要目标是提高软件的可重用性、可扩展性和灵活性,同时降低…...
springboot 百货中心供应链管理系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,百货中心供应链管理系统被用户普遍使用,为方…...
【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器
一.自适应梯度算法Adagrad概述 Adagrad(Adaptive Gradient Algorithm)是一种自适应学习率的优化算法,由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率,适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...
Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件
今天呢,博主的学习进度也是步入了Java Mybatis 框架,目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学,希望能对大家有所帮助,也特别欢迎大家指点不足之处,小生很乐意接受正确的建议&…...
376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...
vue3 定时器-定义全局方法 vue+ts
1.创建ts文件 路径:src/utils/timer.ts 完整代码: import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...
c#开发AI模型对话
AI模型 前面已经介绍了一般AI模型本地部署,直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型,但是目前国内可能使用不多,至少实践例子很少看见。开发训练模型就不介绍了&am…...
UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)
UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中,UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化…...
企业如何增强终端安全?
在数字化转型加速的今天,企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机,到工厂里的物联网设备、智能传感器,这些终端构成了企业与外部世界连接的 “神经末梢”。然而,随着远程办公的常态化和设备接入的爆炸式…...
代理篇12|深入理解 Vite中的Proxy接口代理配置
在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...
快刀集(1): 一刀斩断视频片头广告
一刀流:用一个简单脚本,秒杀视频片头广告,还你清爽观影体验。 1. 引子 作为一个爱生活、爱学习、爱收藏高清资源的老码农,平时写代码之余看看电影、补补片,是再正常不过的事。 电影嘛,要沉浸,…...
