技术笔记:Spring生态研习【五】:Springboot中bean的条件注入

简介: 技术笔记:Spring生态研习【五】:Springboot中bean的条件注入

在springboot中,开发的确变的简单了很多,但是,开发者现在希望开发傻瓜式的方便搞定项目中的各种奇怪的需求最好了,不用烧脑,本来程序猿的生活就是枯燥的,不要再给自己添加更多的烦恼。


今天,就为了方便这点,介绍下,如何解决在开发过程中,一些场景下,为了实现一个配置模块中,基于开关量或者选择配置项,实现不同功能,例如,在一个session共享模块当中,解决session是基于header传递还是基于cookie传递这两种应用场景,有些应用中希望基于header传递sessionId,但是有些应用中希望基于cookie传递sessionId,然后,session共享模块,是一个非常基础的组件,差不多是一个开箱即用的功能块。所以呢,最好能配置好,然后只需要基于配置文件中的某个选项,就能实现运行在不同的工作模式下。这个能否做到呢?真的只需要改一下配置中的开关量就能实现吗?


能否实现,这里卖个关子,先不说,介绍完了本篇博文后,细心的读者一定知道答案,或者说一定能明白能否做,怎么做!


第一大点:先介绍一下springboot中能够支持的或者说封装好的常用的条件注入的注解


1 @ConditionalOnBean


1.1 基本使用案例


@Component


@ConditionalOnBean(name="aBean")


public class BBean {


private final ABean aBean;


public BBean(ABean aBean) {


// ...


}


}


1.2 使用说明


只有当beang的名称为aBean存在的时候,才会注入BBean。


2 @ConditionalOnMissingBean


2.1 基本案例


@Bean


@ConditionalOnMissingBean(name = "notExistsBean")


public BeanToCreate createOneBean() {


return new BeanToCreate("notExistsBean");


}


2.2 使用说明


只有当bean名称为notExistsBean不存在的时候,BeanToCreate类型的bean才会被创建,和@ConditionalOnBean的使用方式相反


3 @ConditionalOnClass


3.1 基本使用案例


@Bean


@ConditionalOnClass(DependedClz.class)


public InjectIfClzExists injectIfClzExists() {


return new InjectIfClzExists("dependedClz");


}


3.2 使用说明


只有当Class为DependedClz.class存在的时候,才会注入类型为InjectIfClzExists的bean,使用上和@ConditionalOnBean有些类似。


4 @ConditionalOnMissingClass


4.1 使用案例


@Bean


@ConditionalOnMissingClass("com.shihuc.bean.clz.DependedClz")


public InjectIfClzNotExists injectIfClzNotExists() {


return new InjectIfClzNotExists("com.shihuc.bean.clz.DependedClz");


}


4.2 使用说明


只有当类com.shihuc.bean.clz.DependedClz不存在的时候,才会注入类型为InjectIfClzNotExists的bean。


5 @ConditionalOnProperty


5.1 基本使用案例


springboot的项目中配置文件application.properties文件中有如下配置:


#.....


section.condition_field=noti


section.condition_property=test


#...


@Bean


@ConditionalOnProperty("section.condition_field")


public PropertyExistBean propertyExistBean() {


return new PropertyExistBean("section.condition_field");


}


5.2 使用说明


主要是根据配置文件中的参数,来决定是否需要创建这个bean,这样就给了我们一个根据配置来控制Bean的选择的手段了,这个非常的好用。因为application.properties文件中存在section.condition_field这个属性,所以,PropertyExistBean这个bean会被创建出来。


5.3 扩展用法


5.3.1 注解定义


@Retention(RetentionPolicy.RUNTIME)


@Target({ ElementType.TYPE, ElementType.METHOD })


@Documented


@Conditional(OnPropertyCondition.class)


public @interface ConditionalOnProperty {


/


Alias for {@link #name()}.


@return the names


注意,这个value和name不能同时使用


/


String【】 value() default {};


/


A prefix that should be applied to each property. The prefix automatically ends


with a dot if not specified.


@return the prefix


/


String prefix() default "";


/


The name of the properties to test. If a prefix has been defined, it is applied to


compute the full key of each property. For instance if the prefix is


{@code app.config} and one value is {@code my-value}, the full key would be


{@code app.config.my-value}



Use the dashed notation to specify each property, that is all lower case with a "-"


to separate words (e.g. {@code my-long-property}).


@return the names


*/


String【】 name() default {};


/


The string representation of the expected value for the properties. If not


specified, the property must not be equal to {@code false}.


@return the expected value


/


String havingValue() default "";


/


Specify if the condition should match if the property is not set. Defaults to


{@code false}.


@return if should match if the property is missing


/


boolean matchIfMissing() default false;


}


当我想实现配置文件中存在属性aaa.bbb且其属性的值为ccc时,才注入bean实例DDDD(名为dddd)。


@Bean("dddd")


@ConditionalOnProperty(value="aaa.bbbb", havingValue="ccc")


public DDDD propertyExistBean() {


return new DDDD("aaa.bbb");


}


6 @ConditionalOnExpression


6.1 使用案例


配置文件application.properties中存在下面的配置内容:


conditional.flag=true


java对应代码:


@Bean


@ConditionalOnExpression("#{'true'.equals(environment【'conditional.flag'】)}")


public ExpressTrueBean expressTrueBean() {


return new ExpressTrueBean("express true");


}


6.2 使用说明


相比较前面的Bean,Class是否存在,配置参数property是否存在或者有某个值而言,这个依赖SPEL表达式的,使用起来就功能显得更加强大了;其主要就是执行Spel表达式,根据返回的true/false来判断是否满足条件。


第二大点: spring基于Condition接口和@Conditional注解进行注入bean


这个相当于是条件注入bean的根源解决方案,上述其他几个ConditionalOnXXXX的注解,都是这个Conditional注解的具体场景的定制版,假如没有能够满足自己的应用场景的,或者说要自己实现一个比较特殊的条件注入呢,例如多个条件同时成立之类,怎么办呢,那就需要通过实现Condition接口然后基于@Conditional注解进行使用了。


1 @Conditional注解定义


//此注解可以标注在类和方法上


@Target({ElementType.TYPE, ElementType.METHOD})


@Retention(RetentionPolicy.RUNTIME)


@Documented


public @interface Conditional {


/


All {@link Condition}s that must {@linkplain Condition#matches match}


in order for the component to be registered.


/


Class【】 value();


}


注意,这个注解就一个参数value,且入参是一个Condition的Class的数组。


2 Condition是什么?


@FunctionalInterface


public interface Condition {


/**


Determine if the condition matches.


@param context the condition context


@param metadata metadata of the {@link org.springframework.core.type.AnnotationMetadata class}


or {@link org.springframework.core.type.MethodMetadata method} being checked


@return {@code true} if the condition matches and the component can be registered,


or {@code false} to veto the annotated component's registration


/


boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);


}


3. 使用案例


假设属性配置文件中,有两个环境参数,一个是温度temp,一个是湿度humi,只有当温度高于30度,且湿度大于50个点时,启用Linux,当温度小于30度且湿度小于50个点时,启用Windows,这个只是为了说明在一个@Conditional里面将多个条件满足该如何实现,还有其他的业务场景,可以参照这个案例。


3.1 配置文件参数


#温度数据,摄氏温度


conditional.prop.temp=29


#湿度数据,百分比,这里不带百分号,相当于扩大100倍,使用的时候除以100


conditional.prop.humi=51


3.2 定义bean


有一个HeWoBean的接口,以及两个实现类HelloBean和WorldBean。


/


@Author: chengsh05


@Date: 2019/8/29 16:17


*/


public interface HeWoBean {


public String toString();


}


/


@Author: chengsh05


@Date: 2019/8/29 15:52


/


public class HelloBean implements HeWoBean {


public String getHhh() {


return hhh;


}


public void setHhh(String hhh) {


this.hhh = hhh;


}


public String getEee() {


return eee;


}


public void setEee(String eee) {


this.eee = eee;


}


String hhh;


String eee;


public HelloBean(String hh, String ee) {


this.hhh = hh;


this.eee = ee;


}


@Override


public String toString() {


return this.hhh + ", " + this.eee;


}


}


/**


@Author: chengsh05


@Date: 2019/8/29 15:54


/


public class WorldBean implements HeWoBean {


public String //代码效果参考:http://www.jhylw.com.cn/415925261.html

getWww() {

return www;


}


public void setWww(String www) {


this.www = www;


}


public String getOoo() {


return ooo;


}


public void setOoo(String ooo) {


this.ooo = ooo;


}


String www;


String ooo;


public WorldBean(String ww, String oo) {


this.www = ww;


this.ooo = oo;


}


@Override


public String toString() {


return this.www + ", " + this.ooo;


}


}


3. condition接口实现类及@Conditional应用


/


@Author: chengsh05


@Date: 2019/8/29 9:08


@Description: 配置信息中,温度和湿度条件满足的时候,即当温度temp大于30度,湿度大于50%,启用Linux


/


public class LinuxTime implements Condition {


@Override


public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {


String tempStr = context.getEnvironment().getProperty("conditional.prop.temp");


float temp = Float.valueOf(tempStr);


String humiStr = context.getEnvironment().getProperty("conditional.prop.humi");


float humi = Float.valueOf(humiStr);


if(temp > 30 && humi > 60){


return true;


}


return false;


}


}


/


@Author: chengsh05


@Date: 2019/8/29 9:07


@Description: 配置信息中,温度和湿度条件满足的时候,即当温度temp小于30度,湿度小于50%,启用windows


/


public class WindowsTime implements Condition {


@Override


public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {


String tempStr = context.getEnvironment().getProperty("conditional.prop.temp");


float temp = Float.valueOf(tempStr);


String humiStr = context.getEnvironment().getProperty("conditional.prop.humi");


float humi = Float.valueOf(humiStr);


if(temp < 30 && humi < 60){


return true;


}


return false;


}


}


/


@Author: chengsh05


@Date: 2019/8/29 15:50


*/


@Configuration


public class MyConditional {


@Bean("mybean")


@Conditional(LinuxTime.class)


public HelloBean createHello() {


return new HelloBean("hello", "Linux");


}


@Bean("mybean")


@Conditional(WindowsTime.class)


public WorldBean createWorld() {


return new WorldBean("world", "Windows");


}


}


4.应用验证


/


@Author: chengsh05


@Date: 2019/8/29 16:03


*/


@Controller


@RequestMapping("/condition")


public class ConditionalController {


@Autowired


@Qualifier("mybean")


private HeWoBean myBean;


@RequestMapping("/check")


@ResponseBody


public void check() {


System.out

相关文章
|
3月前
|
Java Spring
在使用Spring的`@Value`注解注入属性值时,有一些特殊字符需要注意
【10月更文挑战第9天】在使用Spring的`@Value`注解注入属性值时,需注意一些特殊字符的正确处理方法,包括空格、引号、反斜杠、新行、制表符、逗号、大括号、$、百分号及其他特殊字符。通过适当包裹或转义,确保这些字符能被正确解析和注入。
244 3
|
7天前
|
缓存 安全 Java
Spring Boot 3 集成 Spring Security + JWT
本文详细介绍了如何使用Spring Boot 3和Spring Security集成JWT,实现前后端分离的安全认证概述了从入门到引入数据库,再到使用JWT的完整流程。列举了项目中用到的关键依赖,如MyBatis-Plus、Hutool等。简要提及了系统配置表、部门表、字典表等表结构。使用Hutool-jwt工具类进行JWT校验。配置忽略路径、禁用CSRF、添加JWT校验过滤器等。实现登录接口,返回token等信息。
134 12
|
13天前
|
监控 JavaScript 数据可视化
建筑施工一体化信息管理平台源码,支持微服务架构,采用Java、Spring Cloud、Vue等技术开发。
智慧工地云平台是专为建筑施工领域打造的一体化信息管理平台,利用大数据、云计算、物联网等技术,实现施工区域各系统数据汇总与可视化管理。平台涵盖人员、设备、物料、环境等关键因素的实时监控与数据分析,提供远程指挥、决策支持等功能,提升工作效率,促进产业信息化发展。系统由PC端、APP移动端及项目、监管、数据屏三大平台组成,支持微服务架构,采用Java、Spring Cloud、Vue等技术开发。
|
13天前
|
存储 安全 Java
Spring Boot 3 集成Spring AOP实现系统日志记录
本文介绍了如何在Spring Boot 3中集成Spring AOP实现系统日志记录功能。通过定义`SysLog`注解和配置相应的AOP切面,可以在方法执行前后自动记录日志信息,包括操作的开始时间、结束时间、请求参数、返回结果、异常信息等,并将这些信息保存到数据库中。此外,还使用了`ThreadLocal`变量来存储每个线程独立的日志数据,确保线程安全。文中还展示了项目实战中的部分代码片段,以及基于Spring Boot 3 + Vue 3构建的快速开发框架的简介与内置功能列表。此框架结合了当前主流技术栈,提供了用户管理、权限控制、接口文档自动生成等多项实用特性。
56 8
|
1月前
|
Java Spring
一键注入 Spring 成员变量,顺序编程
介绍了一款针对Spring框架开发的插件,旨在解决开发中频繁滚动查找成员变量注入位置的问题。通过一键操作(如Ctrl+1),该插件可自动在类顶部添加`@Autowired`注解及其成员变量声明,同时保持光标位置不变,有效提升开发效率和代码编写流畅度。适用于IntelliJ IDEA 2023及以上版本。
一键注入 Spring 成员变量,顺序编程
|
25天前
|
缓存 前端开发 Java
【Spring】——SpringBoot项目创建
SpringBoot项目创建,SpringBootApplication启动类,target文件,web服务器,tomcat,访问服务器
|
2月前
|
监控 Java 数据库连接
详解Spring Batch:在Spring Boot中实现高效批处理
详解Spring Batch:在Spring Boot中实现高效批处理
343 12
|
1月前
|
JavaScript 安全 Java
java版药品不良反应智能监测系统源码,采用SpringBoot、Vue、MySQL技术开发
基于B/S架构,采用Java、SpringBoot、Vue、MySQL等技术自主研发的ADR智能监测系统,适用于三甲医院,支持二次开发。该系统能自动监测全院患者药物不良反应,通过移动端和PC端实时反馈,提升用药安全。系统涵盖规则管理、监测报告、系统管理三大模块,确保精准、高效地处理ADR事件。
|
2月前
|
安全 Java 测试技术
详解Spring Profiles:在Spring Boot中实现环境配置管理
详解Spring Profiles:在Spring Boot中实现环境配置管理
121 10
|
1月前
|
负载均衡 Java 开发者
深入探索Spring Cloud与Spring Boot:构建微服务架构的实践经验
深入探索Spring Cloud与Spring Boot:构建微服务架构的实践经验
167 5