SpringBoot自动配置

embedded/2024/12/22 2:38:44/

一.Condition接口

        Condition 是在Spring 4.0 增加的条件判断功能,通过这个可以功能可以实现选择性的创建 Bean 操 作。

        当我们为spring容器添加了redis坐标后,我们就可以通过getBean()方法获取到redisTemplate对象,如果没有添加坐标则会报错,那么spring容器是怎么知道我们要配置那个类呢?

二.@conditional注解

        其实spring容器是通过@conditional注解来判断我们是否添加了Redis坐标。

        @conditional注解只有一个属性,就是一个Condition类型的数组,在Condition接口中只有一个matches方法,用于判断是否注入相关类,当matches返回值为true时,spring会进行注入,所以我们使用 @conditional注解时要给它一个属性值作为判断是否注入相关类的条件

        所以我们用一个案例说明:

案例:

需求1: 在 Spring 的 IOC 容器中有一个 User 的 Bean,现要求:

1. 导入Jedis坐标后,加载该Bean,没导入,则不加载。

        我们自定义一个配置类(UserConfig)和一个Condition的实现类(ClassCondition):

java">public class ClassCondition  implements Condition {@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {/**** @param context 上下文对象。用于获取环境,IOC容器,ClassLoader对象* @param metadata 注解元对象。 可以用于获取注解定义的属性值* @return*///1.需求: 导入Jedis坐标后创建Bean//思路:判断redis.clients.jedis.Jedis.class文件是否存在boolean flag = true;try {Class<?> cls = Class.forName("redis.clients.jedis.Jedis");} catch (ClassNotFoundException e) {flag = false;}return flag;}}
java">public class UserConfig {//@Conditional中的ClassCondition.class的matches方法,返回true执行以下代码,否则反之@Bean@Conditional(value= ClassCondition.class)public User user(){return new User();}}

         @conditional注解的属性是我们自定义的Condition的实现类,在这个实现类中,我们重写了matches方法,用于自定义判断条件,当这个条件成立时,即我们导入了jedis坐标,spring会为我们自动注入相关类。

        当我们没有注入jedis坐标时,matches返回值为false,所以就无法创建User对象:

java">@SpringBootApplication
public class Springboot815ConditionZidongpeizhiApplication {public static void main(String[] args) {//启动SpringBoot的应用,返回Spring的IOC容器ConfigurableApplicationContext context =  SpringApplication.run(Springboot815ConditionZidongpeizhiApplication.class, args);/********************案例1********************/Object user = context.getBean("user");System.out.println(user);}
}

        当我们注入jedis坐标后,我们成功获取到了User对象:

        那当我们的判断条件为添加多个坐标时才创建对象,要是一个一个重写太麻烦,所以我们使用动态装配。

需求二:

在 Spring 的 IOC 容器中有一个 User 的 Bean,现要求:

将类的判断定义为动态的。判断哪个字节码文件存在可以动态指定

实现步骤:

不使用@Conditional(ClassCondition.class)注解 自定义注解@ConditionOnClass,因为他和之前@Conditional注解功能一直,所以直接复制 编写ClassCondition中的matches方法:

//1.自定义注解(ConditionOnClass):

java">import java.lang.annotation.*;
//自定义注解(仿照conditional注解)
@Target({ElementType.TYPE, ElementType.METHOD})//可以修饰在类与方法上
@Retention(RetentionPolicy.RUNTIME)//注解生效节点runtime
@Documented//生成文档
@Conditional(value=ClassCondition.class)public @interface ConditionOnClass {String[] value();//设置此注解的属性redis.clients.jedis.Jedis}

//2.配置类

用一个map存所有的标签名,然后通过遍历来一个个判断他们的坐标是否导入了,所有坐标都添加了才会创建对象。

java">public class ClassCondition implements Condition {/**** @param context 上下文对象。用于获取环境,IOC容器,ClassLoader对象* @param metadata 注解元对象。 可以用于获取注解定义的属性值* @return*/@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {Map<String, Object> map = metadata.getAnnotationAttributes(ConditionOnClass.class.getName());System.out.println(map);String[] value = (String[]) map.get("value");boolean flag = true;try {for (String className : value) {Class<?> cls = Class.forName(className);}} catch (ClassNotFoundException e) {flag = false;}return flag;}
}

此处的value为:"com.alibaba.fastjson.JSON","redis.clients.jedis.Jedis",只有这两个坐标均添加,才会创建user对象:

情况1:没有添加fastjson坐标

user对象无法创建:

当两个坐标都添加后:

 三.@Enable注解

        SpringBoot中提供了很多Enable开头的注解,这些注解都是用于动态启用某些功能的。而其底层原理 是使用@Import注 解导入一些配置类,实现Bean的动态加载

@Import注解

        @Enable底层依赖于@Import注解导入一些类,使用@Import导入的类会被Spring加载到IOC容器中。 而@Import提供4中用法:

我们先创建一个import_demo工程,将他里面的对象导入另一个工程(demo):

//1.创建两个实体类(User和Student):

java">public class User {
}
java">public class Student {
}

//2.创建配置类:

java">@Configuration
public class UserConfig {@Beanpublic User user() {return new User();}@Beanpublic Student student() {return new Student();}}

//3.ImportSelector 实现类:

java">public class MyImportSelector implements ImportSelector {@Overridepublic String[] selectImports(AnnotationMetadata importingClassMetadata) {//目前字符串数组的内容是写死的,未来可以设置在配置文件中动态加载return new String[]{"com.apesource.domain.User", "com.apesource.domain.Student"};}

//4.ImportBeanDefinitionRegistrar实现类:

java">public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {//AnnotationMetadata注解//BeanDefinitionRegistry向spring容器中注入//1.获取user的definition对象AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(User.class).getBeanDefinition();//2.通过beanDefinition属性信息,向spring容器中注册id为user的对象registry.registerBeanDefinition("user", beanDefinition);}
}

demo工程:

//1.导入 import_demo坐标

 

① 导入Bean

java">@SpringBootApplication
//@ComponentScan("com.apesource.import_demo02.config")
@Import(User.class)//导入javaBean
public class SpringbootImportDemo01Application {public static void main(String[] args) {ConfigurableApplicationContext context = SpringApplication.run(ImportDemo02Application.class, args);/*** @SpringBootApplication中有@ComponentScan注解, 扫描范围:当前引导类所在包及其子包*  当前引导类所在包com.apesource.springbootenable03*  注入user类所在包com.apesource.springbootenable_other04.config*  因此扫描不到,所以容器中没有user*  解决方案:*          1.使用@ComponentScan扫描com.apesource.springbootenable_other04.config包*          2.可以使用@Import注解,加载类。这些类都会被Spring创建,并放入IOC容器*          3.可以对Import注解进行封装。**/
//Student student = context.getBean(Student.class);System.out.println(student);//获取BeanUser user = context.getBean(User.class);System.out.println(user);}
}

② 导入配置类

java">@SpringBootApplication
@Import(UserConfig.class)
public class SpringbootImportDemo01Application {public static void main(String[] args) {ConfigurableApplicationContext context = SpringApplication.run(ImportDemo02Application.class, args);/*** @SpringBootApplication中有@ComponentScan注解, 扫描范围:当前引导类所在包及其子包*  当前引导类所在包com.apesource.springbootenable03*  注入user类所在包com.apesource.springbootenable_other04.config*  因此扫描不到,所以容器中没有user*  解决方案:*          1.使用@ComponentScan扫描com.apesource.springbootenable_other04.config包*          2.可以使用@Import注解,加载类。这些类都会被Spring创建,并放入IOC容器*          3.可以对Import注解进行封装。**/
//Student student = context.getBean(Student.class);System.out.println(student);//获取BeanUser user = context.getBean(User.class);System.out.println(user);}
}

③ 导入 ImportSelector 实现类。

  

java">@SpringBootApplication
@Import(MyImportSelector.class)
public class SpringbootImportDemo01Application {public static void main(String[] args) {ConfigurableApplicationContext context = SpringApplication.run(ImportDemo02Application.class, args);/*** @SpringBootApplication中有@ComponentScan注解, 扫描范围:当前引导类所在包及其子包*  当前引导类所在包com.apesource.springbootenable03*  注入user类所在包com.apesource.springbootenable_other04.config*  因此扫描不到,所以容器中没有user*  解决方案:*          1.使用@ComponentScan扫描com.apesource.springbootenable_other04.config包*          2.可以使用@Import注解,加载类。这些类都会被Spring创建,并放入IOC容器*          3.可以对Import注解进行封装。**/
//Student student = context.getBean(Student.class);System.out.println(student);//获取BeanUser user = context.getBean(User.class);System.out.println(user);}
}

④ 导入 ImportBeanDefinitionRegistrar 实现类。

java">@SpringBootApplication
@Import({MyImportBeanDefinitionRegistrar.class})
public class SpringbootImportDemo01Application {public static void main(String[] args) {ConfigurableApplicationContext context = SpringApplication.run(ImportDemo02Application.class, args);/*** @SpringBootApplication中有@ComponentScan注解, 扫描范围:当前引导类所在包及其子包*  当前引导类所在包com.apesource.springbootenable03*  注入user类所在包com.apesource.springbootenable_other04.config*  因此扫描不到,所以容器中没有user*  解决方案:*          1.使用@ComponentScan扫描com.apesource.springbootenable_other04.config包*          2.可以使用@Import注解,加载类。这些类都会被Spring创建,并放入IOC容器*          3.可以对Import注解进行封装。**/
//Student student = context.getBean(Student.class);System.out.println(student);//获取BeanUser user = context.getBean(User.class);System.out.println(user);}
}

结果:


http://www.ppmy.cn/embedded/97380.html

相关文章

计算机图形学 | 动画模拟

动画模拟 布料模拟 质点弹簧系统&#xff1a; 红色部分很弱地阻挡对折 Steep connection FEM:有限元方法 粒子系统 粒子系统本质上就是在定义个体和群体的关系。 动画帧率 VR游戏要不晕需要达到90fps Forward Kinematics Inverse Kinematics 只告诉末端p点&#xff0c;中间…

实现父组件调用子组件方法时报错:[Vue warn]: Invalid vnode type when creating vnode: null.

使用uniapp实现父组件调用子组件方法时报错&#xff1a;[Vue warn]: Invalid vnode type when creating vnode: null. 实现代码如下&#xff1a; 子组件&#xff1a; <template><view><view class"toolsHeader"><view class"toolsTitl…

使用PowerShell自动化Windows系统管理任务(上)

使用PowerShell自动化Windows系统管理任务是一个广泛而深入的主题&#xff0c;它涵盖了从简单的日常任务到复杂的系统维护和优化策略。PowerShell作为Microsoft提供的强大脚本和自动化工具&#xff0c;已经成为Windows系统管理员不可或缺的一部分。在本文中&#xff0c;我们将深…

H5接入企微JS-SDK,使用wx.previewFile进行文件预览

最近上项目&#xff0c;需求是做一个附件预览并且可以进行保存到手机、用其他应用打开的需求&#xff0c;用企微的JS-SDK的wx.previewFile就可以满足我目前的需求 详细的可以参考&#xff1a;企业微信官方文档 前端 1、在项目的index.html中添加&#xff1a;jweixin-1.2.0.js …

Repeat方法:取模运算教材与Unity控制台输出数值不同的原因

学习该知识点的参考教材&#xff1a;Unity API解析/陈宏泉编著.——北京&#xff1a;人民邮电出版社&#xff0c;2014.9 编辑脚本的环境&#xff1a;Visual Studio 2022 在学习该本教材的第五章Mathf类的内容&#xff0c;通过跟随教材上的代码了解不同UnityAPI的具体用法时&a…

商业环境洞察:PEST分析法全解析

PEST 分析法是什么 PEST 分析作为一种企业战略规划中的关键工具&#xff0c;主要用于评估企业所处的宏观环境。"P"代表政治因素&#xff0c;涉及政府政策、法律法规及其对企业运营的潜在影响。"E"指的是经济环境&#xff0c;包括经济增长、汇率波动、通货…

【问题记录+总结】VS Code Tex Live 2024 Latex Workshop Springer模板----更新ing

目录 Summary 道阻且长 少即是多 兵马未动粮草先行 没有万能 和一劳永逸 具体问题具体分析 心态 Detail 1、关于模板[官网] 2、settings.json 3、虫和杀虫剂 4、擦 换成Tex Studio都好了。。。 Summary 道阻且长 某中意期刊&#xff0c;只有Latex。之前只简单用过…

Modbus 通信协议详解

目录 一、概述二、Modbus 的作用三、Modbus 的工作原理1、四种数据类型2、三种工作模式3、三类功能码3.1 标志功能码3.2 Modbus 封装接口3.3 异常 4、Modbus 协议层4.1 协议数据单元4.2 访问数据4.3 数据模型寻址4.3.1 数据寻址范围4.3.2 数据地址起始值 4.4 大数据类型4.4.1 位…