Spring

Spring 重新加载 Properties 属性

1、概览 本文将带你了解如何在 Spring 中重新加载 Properties 配置属性。 2、Spring 读取 Properties Spring 有几种不同的方式来访问 Properties: Environment - 可以注入 Environment,然后使用 Environment#getProperty 来读取给定的属性。Environment 包含不同的属性源,如系统属性(System Properties)、-D 参数和 application.properties(或者 .yml) 等。还可以使用 @PropertySource 将额外的属性源添加到 Environment 中。 Properties - 可以将 properties 文件加载到 Properties 实例中,然后在 Bean 中通过调用 properties.get("property") 使用它。 @Value - 可以使用 @Value(${'property'}) 注解在 Bean 中注入特定属性。 @ConfigurationProperties - 可以使用 @ConfigurationProperties 在 Bean 中加载层次化的属性。。 3、重新加载外部属性文件 要在运行时更改文件中的属性(Properties),应该将该文件放在 Jar 之外的某个地方。然后使用命令行参数 -spring.config.location=file://{文件路径} 告诉 Spring 文件的位置。或者,也可以将其放在 application.properties 中。 对于基于磁盘文件的 Properties,可以开发一个端点或定时任务来读取文件并更新 Properties。 Apache 的 commons-configuration 是一个用于重新加载属性文件的库。可以使用 PropertiesConfiguration 和不同的 ReloadingStrategy 。

Spring Bean 注解

1、概览 本文将带你了解最常见的 Spring Bean 注解,用于定义不同类型的 Bean。 在 Spring 容器中配置 Bean 有几种方法。可以使用 XML 配置声明,也可以在配置类中使用 @Bean 注解声明 Bean。 最后,还可以使用 org.springframework.stereotype 包中的注解来标记类,然后由组件扫描来处理。 2、组件扫描 如果启用了组件扫描,Spring 就可以自动扫描包中的 Bean。 通过 @ComponentScan 注解配置要扫描的包,以查找带有注解配置的类。可以使用 basePackages 或 value 参数(value 是 basePackages 的别名)指定 base package: @Configuration @ComponentScan(basePackages = "com.baeldung.annotations") class VehicleFactoryConfig {} 还可以使用 basePackageClasses 参数指定 base package 中的类: @Configuration @ComponentScan(basePackageClasses = VehicleFactoryConfig.class) class VehicleFactoryConfig {} 这两个参数都是数组,因此可以为每个参数指定多个 package。 如果没有指定参数,将从 @ComponentScan 注解类所在的同一个包中开始扫描。 @ComponentScan 利用了 Java 8 的重复注解功能,这意味着可以多次使用它来标记一个类: @Configuration @ComponentScan(basePackages = "com.baeldung.annotations") @ComponentScan(basePackageClasses = VehicleFactoryConfig.

Spring Data 注解

1、简介 Spring Data 提供了对数据存储技术的抽象。因此,我们的业务逻辑代码可以更加独立于底层持久化实现。而且,Spring 还简化了处理与数据存储相关的实现细节的过程。 本文将带你了解 Spring Data、Spring Data JPA 和 Spring Data MongoDB 项目中最常见的注解。 2、常见的 Spring Data 注解 2.1、@Transactional @Transactional 用于定义事务方法: @Transactional void pay() {} 如果在类上应用此注解,那么它就会对类中的所有方法起作用。也可以在方法上定义此注解来进行覆盖。 2.2、@NoRepositoryBean 有时我们会通过一个基本的 Repository 接口,定义一些通用的方法。然后,所有的 Repository 来继承这个基本的 Repository 接口。 基本的 Repository 接口不应该被实例化为 Bean,所以可以使用 @NoRepositoryBean 注解进行标注。 例如,如果想在所有 Repository 中使用 Optional<T> findById(ID id) 方法,那么可以创建一个基础 Repository 接口: @NoRepositoryBean interface MyUtilityRepository<T, ID extends Serializable> extends CrudRepository<T, ID> { Optional<T> findById(ID id); } 此注解不会影响子接口,因此 Spring 将会把下面 Repository 接口创建为 Bean:

Spring 定时任务注解

1、概览 本文将带你了解 org.springframework.scheduling.annotation 包中和调度相关的注解。 2、@EnableAsync 注解用于在 Spring 中启用异步功能。 必须与 @Configuration 一起使用: @Configuration @EnableAsync class VehicleFactoryConfig {} 启用了异步调用后,可以使用 @Async 来定义支持异步调用的方法。 3、@EnableScheduling @EnableScheduling 用于启用定时任务调度。同样,必须与 @Configuration 结合使用: @Configuration @EnableScheduling class VehicleFactoryConfig {} 启用了定时调度后,就可以可以使用 @Scheduled 注解来定期运行方法。 4、@Async @Async 用于注解需要异步执行的方法。 @Async void repairCar() { // ... } 如果将此注解应用于一个类,那么所有方法都将被异步调用。 注意,需要通过 @EnableAsync 或 XML 配置来启用异步调用,此注解才会生效。 5、@Scheduled 如果需要定期执行一个方法,可以使用此注解: @Scheduled(fixedRate = 10000) void checkVehicle() { // ... } 可以使用它来按固定间隔执行方法,或者可以使用类似 cron 的表达式进行微调。 @Scheduled 利用了 Java 8 的重复注解功能,这意味着可以多次使用它来标记一个方法: @Scheduled(fixedRate = 10000) @Scheduled(cron = "0 * * * * MON-FRI") void checkVehicle() { // .

Spring Web 注解

1、概览 本文将带你了解 org.springframework.web.bind.annotation 包中的 Spring Web 注解。 2、@RequestMapping 简单地说,@RequestMapping 注解用于标记 @Controller 类中的请求处理方法(Handler),可配置的属性如下: path 或其别名 name 和 value:方法映射到的 URL method:支持的 HTTP 方法 params:内容协商,根据 HTTP 参数的有无或值匹配请求 headers:内容协商,根据 HTTP Header 的存在、缺失或值匹配请求 consumes:支持的请求媒体类型(Content-Type) produces:响应的媒体类型 示例如下: @Controller class VehicleController { @RequestMapping(value = "/vehicles/home", method = RequestMethod.GET) String home() { return "home"; } } 在 @Controller 类的类级应用此注解,就能为类中的所有 Handler 方法提供默认设置。唯一的例外是 URL,Spring 不会在方法级设置覆盖 URL,而是将两个 path 部分拼接在一起。 例如,以下配置与上述配置效果相同: @Controller @RequestMapping(value = "/vehicles", method = RequestMethod.GET) class VehicleController { @RequestMapping("/home") String home() { return "home"; } } 此外,@GetMapping、@PostMapping、@PutMapping、@DeleteMapping 和 @PatchMapping 是 @RequestMapping 的不同变体,其 HTTP 方法已分别设置为 GET、POST、PUT、DELETE 和 PATCH。

Spring 核心注解

1、概览 我们可以通过 org.springframework.beans.factory.annotation 和 org.springframework.context.annotation 包中的注解来使用 Spring DI 引擎的功能。 通常把这些注解称为 “Spring 核心注解”。 2、和 DI 相关的注解 2.1、@Autowired 可以在构造函数、Setter 方法或字段注入中使用 @Autowired 注解,Spring 会解析并注入依赖。 构造函数注入: class Car { Engine engine; @Autowired Car(Engine engine) { this.engine = engine; } } Setter 注入: class Car { Engine engine; @Autowired void setEngine(Engine engine) { this.engine = engine; } } 字段注入: class Car { @Autowired Engine engine; } @Autowired 有一个名为 required 的 boolean 参数,默认值为 true。当 Spring 找不到合适的 Bean 进行注入时,它会控制 Spring 的行为。当值为 true 时,会抛出异常,反之则不会。

Spring Kafka 的 “Trusted Packages” 特性

1、概览 本文将带你了解 Spring Kafka 中的 “Trusted Packages” 功能,了解其背后的动机以及用法。 2、先决条件 一般来说,Spring Kafka 模块允许我们指定一些关于发送的 POJO 的元数据。它通常采用 Kafka Message Header 的形式。 例如,可以这样配置 ProducerFactory: @Bean public ProducerFactory<Object, SomeData> producerFactory() { JsonSerializer<SomeData> jsonSerializer = new JsonSerializer<>(); jsonSerializer.setAddTypeInfo(true); return new DefaultKafkaProducerFactory<>( producerFactoryConfig(), new StringOrBytesSerializer(), jsonSerializer ); } @Data @AllArgsConstructor static class SomeData { private String id; private String type; private String status; private Instant timestamp; } 然后,使用上面用 producerFactory 配置的 KafkaTemplate 在一个 Topic 中生产一条新消息: public void sendDataIntoKafka() { SomeData someData = new SomeData("1", "active", "sent", Instant.

Spring 中的 ApplicationContext

1、概览 本文将带你详细了解 Spring 中的 ApplicationContext 接口。 2、ApplicationContext 接口 Spring 框架的主要功能之一是 IoC(控制反转)容器。Spring IoC 容器负责管理应用的对象。它使用依赖注入来实现控制反转。 BeanFactory 和 ApplicationContext 接口,代表 Spring IoC 容器。其中,BeanFactory 是访问 Spring 容器的根接口。它提供了管理 Bean 的基本功能。 而 ApplicationContext 是 BeanFactory 的子接口。因此,它具备 BeanFactory 的所有功能。 此外,它还提供了更多面向企业的特定功能。ApplicationContext 的重要功能包括解析消息、支持国际化、发布事件以及应用层特定的上下文。这就是为什么我们将其作为默认的 Spring 容器使用的原因。 3、Spring Bean 是什么? 在深入了解 ApplicationContext 容器之前,有必要了解一下 Spring Bean。在 Spring 中,Bean 是 Spring 容器实例化、组装和管理的对象。 那么,是否应该将应用的所有对象都配置为 Spring Bean 呢?作为最佳实践,不应该这样做。 一般来说,根据 Spring 文档 所述,应该为服务层对象、数据访问对象 (DAO)、表现对象、基础架构对象(如 Hibernate SessionFactory、JMS Queue 等)定义 Bean。 此外,通常情况下,不应该在容器中配置细粒度的 Domain 对象。创建和加载 Domain 对象通常是 DAO 和业务逻辑的职责。

Linux 与 Spring 中 Cron 的区别

1、概览 通过 Cron 表达式,我们可以安排任务在特定日期和时间定期运行。Cron 表达式在 Unix 中推出后,其他基于 Unix 的操作系统和软件库(包括 Spring)都采用了它的任务调度方法。 本文将带你了解基于 Unix 操作系统的 Cron 表达式与 Spring Cron 之间的区别。 2、Unix Cron 在大多数基于 Unix 的系统中,Cron 有五个字段:分钟(0-59)、小时(0-23)、月日(1-31)、月份(1-12 或名称)和星期(0-7 或名称)。 可以在每个字段中添加一些特殊值,如星号(*): 5 0 * * * 任务将在每天午夜后 5 分钟执行。也可以使用数值范围: 5 0-5 * * * 如上,调度器将在午夜 12 点后 5 分钟执行任务,并在每天 1 点、2 点、3 点、4 点和 5 点后 5 分钟执行任务。 或者,可以使用一个值列表: 5 0,3 * * * 现在,调度器会在每天午夜 12 点后 5 分钟和下午 3 点后 5 分钟执行作业。原始 Cron 表达式提供的功能远不止这些。

如果 @PathVariable 包含点(.),会被截断

1、概览 使用 Spring 的 @PathVariable 和 @RequestMapping 来映射包含点的请求时,最后一个 URI 路径变量的值被会截断。 2、原因 具体来说,Spring 认为最后一个点后面的任何内容都是文件扩展名,如 .json 或 .xml,因此,它会截断值以检索路径变量。 来看一个使用路径变量的例子: @RestController public class CustomController { @GetMapping("/example/{firstValue}/{secondValue}") public void example(@PathVariable("firstValue") String firstValue, @PathVariable("secondValue") String secondValue) { // ... } } 如上,考虑以下请求 URL 以及 firstValue 和 secondValue 变量的值: example/gallery/link:firstValue = "gallery",secondValue = "link"。 example/gallery.df/link.ar URL:firstValue = "gallery.df ",secondValue = "link" example/gallery.df/link.com.ar:firstValue = "gallery.df",secondValue = "link.com" 可以看到,第一个变量不受影响,但第二个带点(.)的变量总是被截断。 3、解决办法 解决这种不便的方法之一是修改 @PathVariable 定义,添加一个 regex(正则)映射。这样,任何点(包括最后一个点)都将被视为参数的一部分: @GetMapping("/example/{firstValue}/{secondValue:.+}") public void example( @PathVariable("firstValue") String firstValue, @PathVariable("secondValue") String secondValue) { //.