实战:SpringBoot 15个功能强大Bean

news2024/11/24 16:33:22

下面这15+个bean,可以很方便的帮我们获取当前环境信息,运行信息,参数信息等等

1. 应用程序参数Environment和ApplicationArguments

SpringBoot程序在启动时,可以通过如下方式设置启动参数:

java -jar app.jar --pack.title=xxx --pack.version=1.0.0

一般访问上面的参数可以通过如下方式:

@Resourceprivate Environment env ;public void getArgs() {  String title = env.getProperty("pack.title") ;  String version = env.getProperty("pack.version") ;}

其实SpringBoot为我们注册了一个Bean对象ApplicationArguments,在代码中可以直接注入该对象

@Resourceprivate ApplicationArguments applicationArguments ;public void getArgs() {  List<String> titles = applicationArguments.getOptionValues("pack.title") ;  List<String> version = applicationArguments.getOptionValues("pack.version") ;}

我们还可以拿到原始配置的参数信息

String[] args = applicationArguments.getSourceArgs() ;

输出结果

[--pack.title=xxx, --pack.version=1.0.0]

可以根据自己的需要进行解析处理。

2. Banner

如果你想在项目中获取Banner信息,那么你可以直接在代码中注入Banner对象。

@Resourceprivate Banner banner ;@Resourceprivate Environment env ;public void printBanner() {  banner.printBanner(env, PackApplication.class, System.out) ;}

注意:确保你没有关闭Banner,也就是说你没有进行如下的配置。

spring:  main:    banner-mode: off #关闭Banner

编程方式

SpringApplication app = new SpringApplication(PackApplication.class);app.setBannerMode(Mode.OFF) ;

如果你关闭了Banner,那么上面的注入将会报错。

3. 类型转换器ConversionService

ConversionService是个非常重要及强大的类,该类在SpringBoot启动过程中将配置文件中的配置数据转换为对应的数据类型。Controller请求参数数据类型进行转换。在代码中我们可以直接注入该类,如下示例:

@Resourceprivate ConversionService conversionService ;Integer ret = conversionService.convert("6666",   TypeDescriptor.valueOf(String.class),   TypeDescriptor.valueOf(Integer.class)) ;

你也可以注册自定义的类型转换

@Configurationpublic class WebConfig implements WebMvcConfigurer {  @Override  public void addFormatters(FormatterRegistry registry) {    registry.addConverterFactory(new ConverterFactory<String, User>() {      @Override      public <T extends User> Converter<String, T> getConverter(Class<T> targetType) {        return new Converter<String, T>() {          @Override          public T convert(String source) {            String[] s = source.split(",") ;            return (T) new User(Integer.valueOf(s[0]), s[1]) ;          }        } ;      }    }) ;  }}

添加自定义类型转换后,我们可以在代码中自己通过ConversionService进行类型转换。

4. Servlet相关对象:ServletRequest、ServletResponse、HttpSession、WebRequest

SpringBoot启动过程中会注册以下4个与Web相关的Bean对象。

  • ServletRequest

  • ServletResponse

  • HttpSession

  • WebRequest

这4个对象,我们可以在代码中任意的注入,而不必担心线程安全问题。因为这些对象实际对应的是ObjectFactory。而对应的内部实现是从ThreadLocal中获取。如下示例:

@Resourceprivate HttpServletRequest request ;@Resourceprivate HttpServletResponse response ;
public void getParam() {  String value = request.getParameter("name") ;}

每个请求到来时都会将当前对应的Request存入到ThreadLocal中。

5. 国际化MessageSource

我们可以在代码中直接注入MessageSource对象,进行国际化资源的访问,如下示例:

@Resourceprivate MessageSource messageSource ;public void getMsg() {  String message = this.messageSource.getMessage("pack.info.message",     new Object[] {"张三"}, "我是默认消息", Locale.CHINA) ;}

上面代码如果你没有设置默认消息,那么会报错,在默认情况下Spring实例化的MessageSource对象是DelegatingMessageSource这是一个空的实现。要能使的我们的国际化资源生效,你还需要在配置文件中进行如下配置:

spring:  messages:    basename: i18n/message #这里根据自己实际情况自定义basename

这样配置后,SpringBoot会自动注册ResourceBundleMessageSource对象。

其实我们也可以不使用MessageSource,而直接注入ApplicationContext对象,如下示例:

@Resourceprivate ConfigurableApplicationContext context ;
String message = context.getMessage("pack.info.message",   new Object[] {"张三"}, "我是默认消息", Locale.CHINA) ;

通过ApplicationContext对象获取资源消息,起内部还是使用的上面的MessageSource。

6. 事件发布对象ApplicationEventMulticaster

在项目中你要发布事件你可以通过ApplicationContext对象来发布,如下示例:

@Resourceprivate ConfigurableApplicationContext context ;// 发布事件context.publishEvent(new TxApplicationEvent(context)) ;

一般在项目中通过上面的方式发布一个事件。而实际Spring为我们还注册了一个ApplicationEventMulticaster对象,该对象专门用来广播事件。

@Resourceprivate ApplicationEventMulticaster eventMulticast ;eventMulticast.multicastEvent(new TxApplicationEvent(context)) ;

我们也可以自定义beanName为applicationEventMulticaster的Bean对象实现自定义。

7. 优雅关闭服务WebServerGracefulShutdownLifecycle

如果你是内嵌Tomcat启动(以Jar包形式)SpringBoot项目,那么会向容器中注册一个WebServerGracefulShutdownLifecycle对象,通过该对象你可以优雅的关闭服务。

备注:当然,你也可以通过actuator来进行优雅的关闭webserver。

@Resourceprivate WebServerGracefulShutdownLifecycle webServerGracefullShutdown ;public void shutdownWebServer() {  webServerGracefullShutdown.stop(() -> {    System.out.println("优雅关闭Web Server");    context.close() ;  }) ;}

注意:你还需要开启如下配置

server:  shutdown: graceful

8. ApplicationPid获取进程ID

如果你想在程序中获取当前SpringBoot运行的进程号,那么你可以使用ApplicationPid,该类非常方便的获取当前进程ID。

ApplicationPid pid = new ApplicationPid() ;System.out.printf("进程ID: %s%n", pid.toString()) ;

输出结果

进程ID: 24416

当然你还可以通过如下方式,获取当前的进程号

#在META-INF/spring.factories中注册监听器org.springframework.context.ApplicationListener=\org.springframework.boot.context.ApplicationPidFileWriter

该监听器会将当前的进程ID写入文件中,通过如下配置文件路径

spring:  pid:    file: d:/app.pid

文件内容:当前进程id

如果你觉得无聊,那么你还可以通过如下方式

String pid = ManagementFactory.getRuntimeMXBean().getName().split("@")[0]

这样也可以获取进程ID。

9. 应用运行主目录ApplicationHome

ApplicationHome提供访问应用程序主目录的途径。尝试为Jar文件、解压缩文件和直接运行的应用程序选择一个合理的主目录。

ApplicationHome home = new ApplicationHome() ;System.out.printf("dir: %s, source: %s%n", home.getDir(), home.getSource()) ;

在IDE中运行输出结果

dir: D:\java\workspace\test-app, source: null

打成Jar后运行输出结果

dir: D:\java\workspace\test-app\target,   source: D:\java\workspace\test-app\target\test-app-1.0.0.jar

通过jar运行后,source输出的是当前运行的jar包路径。

10. 获取Java版本JavaVersion

要想知道当前SpringBoot运行时的java版本可以通过JavaVersion获取

System.out.printf("Java Version: %s%n", JavaVersion.getJavaVersion()) ;

输出结果

Java Version: 17

JavaVersion是个枚举类,定义了17~22枚举值,你还可以调用isEqualOrNewerThanisOlderThan进行java版本的比较。

11. 应用临时目录ApplicationTemp

ApplicationTemp类提供了访问应用程序特定的临时目录的功能。一般来说,不同的Spring Boot应用程序将得到不同的位置,但是,只需重新启动应用程序即可获得相同的位置。

ApplicationTemp temp = new ApplicationTemp() ;System.out.printf("临时目录: %s%n", temp.getDir()) ;

输出结果

临时目录: C:\Users\MSI-NB\AppData\Local\Temp\561929B2C764E67BCDA2DF9DAE26EF121F7E5365

不论你在IDE下还是Jar方式运行,windows平台下临时目录都在这里的Temp下

12. SystemProperties系统属性/环境变量访问

当你需要访问系统属性时可以通过SystemProperties类非常方便的获取。如果你访问的属性不存在时(null),那么它会再从环境变量中获取(System#getenv)

System.out.printf("java.home=%s%n", SystemProperties.get("java.home")) ;

输出结果

java.home=D:\software\jre

注:这里的get方法参数是可变长参数,你可以传递多个key,获取时遍历遇到不为null的直接返回。

13. Instantiator实例化对象

Instantiator通过注入可用参数来实例化对象的简单工厂。

public interface DAO {}public class A implements DAO {}  public class B implements DAO {}

注备上面几个类,接下通过Instantiator一次性实例化多个对象。

Instantiator<DAO> instant = new Instantiator<>(DAO.class, p -> {}) ;List<DAO> ret = instant.instantiate(List.of("com.pack.A", "com.pack.B")) ;System.out.printf("%s%n", ret) ;

输出结果

[com.pack.A@3127cb44, com.pack.B@3234474]

非常方便的一次性帮助你实例化多个同类型的类

14. 资源加载PropertiesPropertySourceLoaderYamlPropertySourceLoader

如果你想将后缀为.properties,.xml,.yaml资源文件加载,那么你可以使用PropertiesPropertySourceLoaderYamlPropertySourceLoader

// 加载properties文件PropertiesPropertySourceLoader propertyLoader = new PropertiesPropertySourceLoader() ;List<PropertySource<?>> list = propertyLoader.load("pack", new ClassPathResource("pack.properties")) ;System.out.printf("pack.*: %s%n", list.get(0).getSource()) ;// 加载yaml文件YamlPropertySourceLoader yamlLoader = new YamlPropertySourceLoader() ;List<PropertySource<?>> yamls = yamlLoader.load("pack", new ClassPathResource("pack.yml")) ;System.out.printf("pack.*: %s%n", yamls.get(0).getSource()) ;

通过上面2个Loader非常方便的将资源文件加载,加载后的List<PropertySource>还可以注册到Environment中,在系统中直接访问。

在SpringBoot兴起之前,Spring项目通常需要手动配置PropertySourcesPlaceholderConfigurer来解析配置文件中的占位符,以及PropertyOverrideConfigurer来允许属性覆盖(该类可能用的也是表少的)。这2个类使用也相对比较简单,它能帮助我们加载配置文件及处理${xxx}占位符。然而,SpringBoot出现后,似乎在项目中基本不会去定义这2个类,SpringBoot已经帮我们自动的配置(PropertyOverrideConfigurer并没有需要我们自己配置)。接下来我们就再来介绍这2个类在SpringBoot中如何覆盖系统默认的配置及使用方式。

 实战案例

1 PropertySourcesPlaceholderConfigurer

属性不存在问题

在默认下,当使用${xxx}配置的属性环境中不存在时,将会报错。如下示例:

@Value("pack.title")private String title ;

当你的环境中没有配置pack.title属性时,容器启动将会报错。

图片

不过我们可以通过下面的方式来规避该错误

@Value("${pack.title:xx}")private String title ;

通过上面的方式设置默认值,这里你也直接使用冒号":"后面不设置值${pack.title:}。

通过自定义PropertySourcesPlaceholderConfigurer修改属性,使其支持不存在属性情况,如下:

@BeanPropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {  PropertySourcesPlaceholderConfigurer placeholderConfigurer = new PropertySourcesPlaceholderConfigurer() ;  // 设置为true,忽略不能解析的占位符  placeholderConfigurer.setIgnoreUnresolvablePlaceholders(true) ;  return placeholderConfigurer ;}

上面设置后服务能正确启动。

修改占位符

我们还可以修改占位符的定义方式(不推荐

@BeanPropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {  PropertySourcesPlaceholderConfigurer placeholderConfigurer = new PropertySourcesPlaceholderConfigurer() ;  // 设置占位符前缀&后缀,@[xxx]  placeholderConfigurer.setPlaceholderPrefix("@[") ;  placeholderConfigurer.setPlaceholderSuffix("]") ;  return placeholderConfigurer ;}

如上配置后,使用时就只能通过@[xxx]

自定义配置文件

在自定义时,你还可以指定自己的配置文件,初始化该bean时会加载对应的配置文件

@BeanPropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {  PropertySourcesPlaceholderConfigurer placeholderConfigurer = new PropertySourcesPlaceholderConfigurer() ;  // 指定配置文件  placeholderConfigurer.setLocations(new ClassPathResource("pack.properties")) ;  return placeholderConfigurer ;}

你也可以指定多个配置文件。

2 PropertyOverrideConfigurer

该配置文件相比较用的比较少了。该类同样是个BeanFactoryPostProcessor处理器。通过类名也能猜到是用来覆盖属性值的处理器类。直接上代码

@Componentpublic class PropertyOverrideBean {
  @Value("${pack.title}")  private String title ;  @Value("${pack.os}")  private String os ;  // getters, setters}
@Resourceprivate PropertyOverrideBean pob ;System.out.println(pob) ;

输出结果

PropertyOverrideBean [title=xxxooo, os=window]

接下来配置PropertyOverrideConfigurer

@BeanPropertyOverrideConfigurer propertyOverrideConfigurer() {  PropertyOverrideConfigurer propertyOverrideConfigurer = new PropertyOverrideConfigurer() ;  propertyOverrideConfigurer.setLocation(new ClassPathResource("pack.properties")) ;  return propertyOverrideConfigurer ;}

同样这里我们指定一个自定义配置文件;但是这里的pack.properties文件中的内容就要主要属性key的格式了,[beanName].[key]=xxxx这里的属性key的前缀必须是你要覆盖bean的名称。如下示例:

propertyOverrideBean.title=my titlepropertyOverrideBean.os=linux

上面的propertyOverrideBean就是PropertyOverrideBean的beanName。

输出结果:

PropertyOverrideBean [title=my title, os=linux]

覆盖了系统默认的属性值。

嵌套属性

@Componentpublic class PropertyOverrideBean {  // other property  private User user = new User() ;}public class User {  @Value("pack.age")  private Integer age ;  // getters, setters}

在配置文件中添加配置

propertyOverrideBean.user.age=88

输出结果

PropertyOverrideBean [title=my title, os=linux, user=User [age=88]]

注意:这里的嵌套属性User必须事先创建好否则将会抛出NPE异常。

15. 获取basePackages

如果你需要在代码中获取当前应用启动类所在的基包basePackages,那么你可以通过如下方式

private ConfigurableApplicationContext context ;System.out.printf("basepPckages: %s%n", AutoConfigurationPackages.get(context)) ;

输出结果

basepPckages: [com.pack]

内部注册的是一个BasePackages Bean,该类是静态私有的所以你没法直接访问,只能通过上面的方式。

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

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

相关文章

单链表算法 - 链表分割

链表分割_牛客题霸_牛客网现有一链表的头指针 ListNode* pHead&#xff0c;给一定值x&#xff0c;编写一段代码将所有小于x的。题目来自【牛客题霸】https://www.nowcoder.com/practice/0e27e0b064de4eacac178676ef9c9d70思路: 代码: /* struct ListNode {int val;struct List…

iterator(迭代器模式)

引入 在想显示数组当中所有元素时&#xff0c;我们往往会使用下面的for循环语句来遍历数组 #include <iostream> #include <vector>int main() {std::vector<int> v({ 1, 2, 3 });for (int i 0; i < v.size(); i){std::cout << v[i] << &q…

正则表达式(Ⅲ)——分组匹配

简介 为了给表达式分组&#xff0c;我们需要将文本包裹在 () 中 有点类似于匹配子串&#xff0c;只不过是找出所有的子串&#xff0c;并且拼成一组 分组之间需要有分割符&#xff0c;,或者-或者_都可以 直接分组 引用分组 这个比较难以理解 \1和\2的作用有两个&#xff1a…

Ubuntu系统修改SSH默认端口号

1.查看系统和系统版本号 rootecs-c0fe:~# lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 16.04.7 LTS Release: 16.04 Codename: xenial rootecs-c0fe:~# uname -a Linux ecs-c0fe 4.4.0-210-generic #242-Ubunt…

Python入门------多个版本--虚拟环境的创建(非anaconda方式)

说明介绍&#xff1a; 1. 什么是虚拟环境 在Python中&#xff0c;虚拟环境&#xff08;Virtual Environment&#xff09;是一个独立的、隔离的Python运行环境&#xff0c;它拥有自己的Python解释器、第三方库和应用程序。通过创建虚拟环境&#xff0c;可以确保项目之间的依赖关…

Python 实验五 高级数据结构

一、实验目的 &#xff08;1&#xff09;掌握序列的基本操作 &#xff08;2&#xff09;掌握集合、字典的基本操作 二、实验环境 联网计算机一台/每人&#xff0c;内装Windows 7以上操作系统和安装Python 3.7集成开发环境IDLE。 三、实验内容 Sy5-1 列表实现。编写一个…

数据库的约束条件和用户管理

约束条件&#xff1a; 主键&#xff1a;主键约束 primary key 用于标识表中的主键列的值&#xff0c;而且这个值是全表当中唯一的&#xff0c;而且只不能为null 一个表只能有一个主键。 外键&#xff1a;用来建立表与表之间的关系。确保外键中的值于另一个表的主键值匹配&a…

camtasia怎么剪掉不用的部分 屏幕录制的视频怎么裁剪上下不要的部分 camtasia studio怎么裁剪视频时长 camtasia怎么剪辑视频教程

有时我们录制的屏幕内容&#xff0c;并不一定全部需要。那么&#xff0c;屏幕录制的视频怎么裁剪上下不要的部分&#xff1f;可以使用视频剪辑软件&#xff0c;或者微课制作工具来进行裁剪。屏幕录制的视频怎么旋转&#xff1f;录制视频的旋转也是一样的&#xff0c;均在编辑步…

可视化工具选择指南:助力企业数字化转型和新质生产力发展

随着信息技术的快速发展和新质生产力概念的兴起&#xff0c;可视化工具在各个行业中的作用日益凸显。这些工具不仅能够帮助用户更直观地理解和分析数据&#xff0c;还能提升团队的协作效率和决策质量。 在当今数字化转型迅速发展的背景下&#xff0c;新质生产力的概念正在成为…

Spring Boot项目的404是如何发生的

问题 在日常开发中&#xff0c;假如我们访问一个Sping容器中并不存在的路径&#xff0c;通常会返回404的报错&#xff0c;具体原因是什么呢&#xff1f; 结论 错误的访问会调用两次DispatcherServlet&#xff1a;第一次调用无法找到对应路径时&#xff0c;会给Response设置一个…

【React笔记初学总结一】React新手的学习流程笔记总结,掰开了揉碎了,下载安装基础结构学习

REACT学习记录 一、React是什么&#xff1a;二、尝试安装下载&#xff1a;三、理解都有什么四、基础网页学习&#xff1a;1.几个比较重要的资源包例子2.第一个react示例&#xff1a;&#xff08;掰开了揉碎了&#xff0c;咱们先看懂它最简单的结构&#xff09;3.第二个react示例…

Vue--Router(路由)

目录 一 Router(路由) 1.作用 2.实现步骤 3.注意 一 Router(路由) 1.作用 Router又叫做路由&#xff0c;简单来说&#xff0c;就是用来实现vue的页面之间跳转的。 我们都知道&#xff0c;使用vue必然会涉及到很多个组件&#xff0c;也就是页面&#xff0c;而页面之间肯定需…

mars3d实现GraphicLayer获取当前相机视角内的可视点位(矢量数据

效果&#xff1a; mars3d实现GraphicLayer获取当前相机视角内的可视点位&#xff08;矢量数据 相关依赖api&#xff1a; 1. map.getExtent(); 提取地球当前视域边界,示例&#xff1a;{ xmin: 70, xmax: 140, ymin: 0, ymax: 55, height: 0, } 2.graphicLayer.eachGraphic遍…

Android12 MultiMedia框架之NuPlayer Surface

在学习NuPlayer创建Decoder和Renderer之前&#xff0c;得先看下video数据最终生产到什么地方去&#xff1f;答案是Surface&#xff0c;而且Surface是NuPlayer创建Decoder的条件。 APP会创建一层SurfaceView来显示视频层&#xff0c;同时内部会创建一个BLASTBufferQueue&#x…

睡前故事—绿色科技的未来:可持续发展的梦幻故事

欢迎来到《Bedtime Stories Time》。这是一个我们倾听、放松、并逐渐入睡的播客。感谢你收听并支持我们&#xff0c;希望你能将这个播客作为你睡前例行活动的一部分。今晚我们将讲述绿色科技的未来&#xff1a;可持续发展的梦幻故事的故事。一个宁静的夜晚&#xff0c;希望你现…

自适应简约大气科技数码产品公司网站源码系统 模版一键搭建 可自定义带源代码包以及搭建部署教程

系统概述 在当今这个数字化、信息化的时代&#xff0c;科技数码产品行业正处于高速发展的黄金时期。为了在这个竞争激烈的市场中脱颖而出&#xff0c;科技数码产品公司不仅需要拥有卓越的产品和技术&#xff0c;还需要一个能够完美展现其品牌形象和产品特色的网站。为此&#…

【PyTorch快速入门教程】02 Jupyter notebook安装及配置

文章目录 1 安装 Jupyter notebook2 安装 ipykernel3 更改 jupyter 默认配置3.1 生成配置文件3.2 关键配置信息 4 扩展插件推荐参考 1 安装 Jupyter notebook 一行命令搞定 python -m pip install jupyter 现在就可以打开Jupyter notebook来运行python啦。 jupyter notebook…

印尼语翻译通:AI驱动的智能翻译与语言学习助手

在这个多元文化交织的世界中&#xff0c;语言是连接我们的桥梁。印尼语翻译通&#xff0c;一款专为打破语言障碍而生的智能翻译软件&#xff0c;让您与印尼语的世界轻松接轨。无论是商务出差、学术研究&#xff0c;还是探索印尼丰富的文化遗产&#xff0c;印尼语翻译通都是您的…

自动驾驶系列—智能巡航辅助功能中的车道中央保持功能介绍

文章目录 1. 背景介绍2. 功能定义3. 功能原理4. 传感器架构5. 实际应用案例5.1 典型场景1&#xff1a;直道内行驶5.1.1 直道内居中行驶5.1.2 直道内跟车行驶 5.2 典型场景2&#xff1a;弯道内行驶5.2.1 弯道内居中行驶5.2.2 弯道内跟车行驶 5.3 典型场景3&#xff1a;道路边缘5…

【Godot4.2】MLTag类:HTML、XML通用标签类

概述 HTML和XML采用类似的标签形式。 之前在Godot中以函数库形式实现了网页标签和内容生成。能用&#xff0c;但是缺点也很明显。函数之间没有从属关系&#xff0c;但是多有依赖&#xff0c;而且没有划分出各种对象和类型。 如果以完全的面向对象形式来设计标签类或者元素类…