SpringBoot高级-自动配置原理剖析一

前言:在使用SpringBoot开发时,发现它非常的方便,很多东西就是导入依赖,拿来即用,并不清楚其中的原理是什么,所有心理多少会有些疑惑,了解自动配置原理之后,我们可以更好的使用SpringBoot,并且学习其中的设计思想。

示例1:我们对SpringBoot引导类进行修改,通过IOC容器,获取redisTemplate这个Bean,看能否获取?

@SpringBootApplication
public class SpringbootConditionApplication {

    public static void main(String[] args) {
        //启动SpringBoot的应用,返回Spring的IOC容器
        ConfigurableApplicationContext context = SpringApplication.run(SpringbootConditionApplication.class, args);

        //获取Bean,redisTemplate
        Object redisTemplate = context.getBean("redisTemplate");
        System.out.println(redisTemplate);
    }
}

控制台结果:可知默认的时候,SpringBoot不会为我们加载redisTemplate这个Bean。

下一步,我们在pom.xml中加入redis的起步依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

再次启动程序:可以成功的获取redisTemplate的Bean

小结:通过上述示例,我们可以了解到,通过添加依赖,IOC容器就可以获取到相关(redisTemplate)的Bean,由此就可以使用具体的方法了。SpringBoot具体是怎么实现的呢?我们继续往下做示例。

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

示例2:实现在Spring容器中有一个User的Bean。

1、新建一个User类

/**
 * @description:User类:属性略
 * @date: 2020/10/9 15:25
 * @author: winson
 */
public class User {
}

2、新建一个User的配置类,实现Bean注册到Spring容器中

/**
 * @description:User配置类
 * @date: 2020/10/9 15:25
 * @author: winson
 */
@Configuration
public class UserConfig {
    @Bean
    public User user() {
        return new User();
    }
}

3、测试user的Bean是否成功注入到IOC容器中

@SpringBootApplication
public class SpringbootConditionApplication {

    public static void main(String[] args) {
        //启动SpringBoot的应用,返回Spring的IOC容器
        ConfigurableApplicationContext context = SpringApplication.run(SpringbootConditionApplication.class, args);

        /*//获取Bean,redisTemplate
        Object redisTemplate = context.getBean("redisTemplate");
        System.out.println(redisTemplate);*/

        Object user = context.getBean("user");
        System.out.println(user);
    }
}

4、结果:测试成功。

接着示例2,在此基础上做示例3。

示例3:示例2完成了自动注入user的Bean,即使我们不想要user的Bean,它还是存在于IOC容器中了,现在我们将程序继续改造,实现当导入Jedis坐标后,才加载user的Bean,没导入,IOC容器中不加载user的Bean。这里我们先介绍一个注解@Conditional


All classes that must in order for the component to be registered.:注册组件必须使用的所有类。
使用@Conditional注解的类,必须按照条件泛型要求,即:泛型条件类,必须Condition接口的子类

此时我们再来看Condition接口,该接口有一个方法matches(),返回值是一个boolean类型的

由此可知,使用@Conditional注解时,参数(类)可以为一个数组,此数组中的类必须是Condition接口的子类(实现此接口并重写matches()方法,如果matches()返回的是true,@Conditional注解生效,否则不生效),由此我们就可以继续做测试了。
1、修改UserConfig配置类

/**
 * @description:User配置类
 * @date: 2020/10/9 15:25
 * @author: winson
 */
@Configuration
public class UserConfig {

    //添加@Conditional注解
    @Conditional(ClassCondition.class)
    @Bean
    public User user() {
        return new User();
    }

}

2、新建一个条件类,该条件类必须实现Condition接口,并重写其matches()方法

/**
 * @description:条件类
 * @date: 2020/10/9 16:24
 * @author: winson
 */
public class ClassCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return false;
    }
}

3、再次启动程序,测试结果可知,当条件类ClassCondition返回false后,我们再从IOC容器中获取user类的Bean,就会失败。

4、再修改条件类ClassCondition,使其返回true。

public class ClassCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return true;
    }
}

5、重启程序可知,又可以获取user的Bean了

6、回到示例3的需求:实现当导入Jedis坐标后,才加载user的Bean,没导入,IOC容器中不加载user的Bean。
6.1、修改ClassCondition类,思路见代码注释

/**
 * @description:条件类
 * @date: 2020/10/9 16:24
 * @author: winson
 */
public class ClassCondition implements Condition {
    //1、需求:导入Jedis坐标后创建Bean
    //思路:判断redis.clients.jedis.Jedis文件是否存在
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        boolean flag = true;
        try {
            Class<?> cls = Class.forName("redis.clients.jedis.Jedis");
        } catch (ClassNotFoundException e) {
            flag = false;
        }
        return flag;
    }
}

7、测试
7.1、pom.xml中先不导入Jedis依赖

7.2、导入Jedis依赖

        <dependency>
            <groupId>Jedis</groupId>
            <artifactId>jedis</artifactId>
            <version>2.9.0</version>
        </dependency>

7.3、测试结果,导入Jedis依赖后,成功从IOC容器中获取到了user的Bean

posted @ 2020-10-09 15:23  温森  阅读(273)  评论(0编辑  收藏  举报