• springboot之三:原理分析之自动配置condition


    导入:

    SpringBoot是如何知道要创建哪个Bean的?比如Spring Boot是如何知道要创建RedisTemplate的?

    Condition:

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

    • 自定义条件:
            ① 定义条件类:自定义类实现Condition接口,重写 matches 方法,在 matches 方法中进行逻辑判断,返回 boolean值 。 matches 方法两个参数:
                    • context:上下文对象,可以获取属性值,获取类加载器,获取BeanFactory等。
                    • metadata:元数据对象,用于获取注解属性。
            ② 判断条件: 在初始化Bean时,使用 @Conditional ( 条件类 . class ) 注解
    • SpringBoot 提供的常用条件注解:
            • ConditionalOnProperty 判断配置文件中是否有对应属性和值才初始化Bean
            • ConditionalOnClass 判断环境中是否有对应字节码文件才初始化Bean
            • ConditionalOnMissingBean 判断环境中没有对应Bean才初始化Bean

    创建模块:

    需求一:

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

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

    新建domain软件包,User 类:

    1. package com.itheima.springbootcondition.domain;
    2. public class User {
    3. }

    新建config软件包,UserConfig 类:

    1. package com.itheima.springbootcondition.config;
    2. import com.itheima.springbootcondition.condition.ClassCondition;
    3. import com.itheima.springbootcondition.domain.User;
    4. import org.springframework.context.annotation.Bean;
    5. import org.springframework.context.annotation.Conditional;
    6. import org.springframework.context.annotation.Configuration;
    7. @Configuration
    8. public class UserConfig {
    9. @Bean
    10. @Conditional(ClassCondition.class)
    11. public User user(){
    12. return new User();
    13. }
    14. }

    新建condition软件包:ClassCondition类:

    1. package com.itheima.springbootcondition.condition;
    2. import org.springframework.context.annotation.Condition;
    3. import org.springframework.context.annotation.ConditionContext;
    4. import org.springframework.core.type.AnnotatedTypeMetadata;
    5. public class ClassCondition implements Condition {
    6. /**
    7. *
    8. * @param context 上下文对象。用于获取环境,ioc容器,classloader对象
    9. * @param metadata 注解元对象。用于获取注解定义的属性值。
    10. * @return
    11. */
    12. @Override
    13. public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
    14. //需求1: 导入Jedis坐标后,加载该Bean,没导入,则不加载。
    15. try {
    16. Class cls = Class.forName("redis.clients.jedis.Jedis");
    17. } catch (ClassNotFoundException e) {
    18. e.printStackTrace();
    19. return false;
    20. }
    21. return true;
    22. }
    23. }

    SpringbootConditionApplication类:

    1. package com.itheima.springbootcondition;
    2. import org.springframework.boot.SpringApplication;
    3. import org.springframework.boot.autoconfigure.SpringBootApplication;
    4. import org.springframework.context.ConfigurableApplicationContext;
    5. @SpringBootApplication
    6. public class SpringbootConditionApplication {
    7. public static void main(String[] args) {
    8. //启动springboot的应用,返回spring的ioc容器
    9. ConfigurableApplicationContext context = SpringApplication.run(SpringbootConditionApplication.class, args);
    10. Object user = context.getBean("user");
    11. System.out.println(user);
    12. }
    13. }

    在pom文件里增删jedis坐标测试:

    1. <dependency>
    2. <groupId>redis.clientsgroupId>
    3. <artifactId>jedisartifactId>
    4. dependency>

    需求二:

    在 Spring 的 IOC 容器中有一个 User 的 Bean,现要求:
    将类的判断定义为动态的。判断哪个字节码文件存在可以动态指定。
    在condition包下,新建注解ConditionOnClass :
    1. package com.itheima.springbootcondition.condition;
    2. import org.springframework.context.annotation.Conditional;
    3. import java.lang.annotation.*;
    4. @Target({ElementType.TYPE, ElementType.METHOD})
    5. @Retention(RetentionPolicy.RUNTIME)
    6. @Documented
    7. @Conditional(ClassCondition.class)
    8. public @interface ConditionOnClass {
    9. String[] value();
    10. }

    ClassCondition 类:

    1. package com.itheima.springbootcondition.condition;
    2. import org.springframework.context.annotation.Condition;
    3. import org.springframework.context.annotation.ConditionContext;
    4. import org.springframework.core.type.AnnotatedTypeMetadata;
    5. import java.util.Iterator;
    6. import java.util.Map;
    7. public class ClassCondition implements Condition {
    8. /**
    9. *
    10. * @param context 上下文对象。用于获取环境,ioc容器,classloader对象
    11. * @param metadata 注解元对象。用于获取注解定义的属性值。
    12. * @return
    13. */
    14. @Override
    15. public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
    16. //需求2:导入通过注解属性值value指定坐标后创建bean
    17. //获取注解属性值 value
    18. Map map = metadata.getAnnotationAttributes(ConditionOnClass.class.getName());
    19. // System.out.println(map);
    20. String[] value = (String[]) map.get("value");
    21. try {
    22. for (String classname : value) {
    23. Class cls = Class.forName(classname);
    24. }
    25. } catch (ClassNotFoundException e) {
    26. e.printStackTrace();
    27. return false;
    28. }
    29. return true;
    30. }
    31. }

    UserConfig 类:

    1. package com.itheima.springbootcondition.config;
    2. import com.itheima.springbootcondition.condition.ClassCondition;
    3. import com.itheima.springbootcondition.condition.ConditionOnClass;
    4. import com.itheima.springbootcondition.domain.User;
    5. import org.springframework.context.annotation.Bean;
    6. import org.springframework.context.annotation.Conditional;
    7. import org.springframework.context.annotation.Configuration;
    8. @Configuration
    9. public class UserConfig {
    10. @Bean
    11. // @Conditional(ClassCondition.class)
    12. @ConditionOnClass("redis.clients.jedis.Jedis")
    13. public User user(){
    14. return new User();
    15. }
    16. }

    在pom文件里增删jedis坐标测试。

    整体项目结构:

  • 相关阅读:
    亚马逊云科技 re:Inforce 2023 中国站,聚焦数据、大模型、应用安全
    【项目】三子棋小游戏(C语言)
    git新建仓库提交项目代码+常用命令
    (蓝桥杯C/C++)——常用库函数
    USB概念介绍
    no permission 这种问题的解决方法
    NAT 技术概览(二)
    史上最短苹果发布会;三星、LG、高通联手进军 XR 市场丨 RTE 开发者日报 Vol.74
    3DTiles 1.0 数据规范详解[4.1] b3dm瓦片二进制数据文件结构
    SD_DATA_SEND_SHIFT_REGISTER
  • 原文地址:https://blog.csdn.net/zhiaidaidai/article/details/132698443