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

创建模块:

springboot之三:原理分析之自动配置condition_第1张图片

需求一:

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

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

新建domain软件包,User 类:

package com.itheima.springbootcondition.domain;

public class User {
}

新建config软件包,UserConfig 类:

package com.itheima.springbootcondition.config;


import com.itheima.springbootcondition.condition.ClassCondition;
import com.itheima.springbootcondition.domain.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;

@Configuration
public class UserConfig {
    @Bean
    @Conditional(ClassCondition.class)
    public User user(){
        return new User();
    }
}

新建condition软件包:ClassCondition类:

package com.itheima.springbootcondition.condition;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;


public class ClassCondition implements Condition {
    /**
     *
     * @param context  上下文对象。用于获取环境,ioc容器,classloader对象
     * @param metadata 注解元对象。用于获取注解定义的属性值。
     * @return
     */
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {

        //需求1: 导入Jedis坐标后,加载该Bean,没导入,则不加载。
        try {
            Class cls = Class.forName("redis.clients.jedis.Jedis");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }
}

SpringbootConditionApplication类:

package com.itheima.springbootcondition;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;


@SpringBootApplication
public class SpringbootConditionApplication {
    public static void main(String[] args) {
        //启动springboot的应用,返回spring的ioc容器
        ConfigurableApplicationContext context = SpringApplication.run(SpringbootConditionApplication.class, args);
        
        Object user = context.getBean("user");
        System.out.println(user);
    }

}

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


   redis.clients
   jedis

需求二:

在 Spring 的 IOC 容器中有一个 User 的 Bean,现要求:
将类的判断定义为动态的。判断哪个字节码文件存在可以动态指定。
在condition包下,新建注解ConditionOnClass :
package com.itheima.springbootcondition.condition;

import org.springframework.context.annotation.Conditional;

import java.lang.annotation.*;

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(ClassCondition.class)
public @interface ConditionOnClass {
    String[] value();
}

ClassCondition 类:

package com.itheima.springbootcondition.condition;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;

import java.util.Iterator;
import java.util.Map;

public class ClassCondition implements Condition {
    /**
     *
     * @param context  上下文对象。用于获取环境,ioc容器,classloader对象
     * @param metadata 注解元对象。用于获取注解定义的属性值。
     * @return
     */
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {


        //需求2:导入通过注解属性值value指定坐标后创建bean

        //获取注解属性值 value
        Map map = metadata.getAnnotationAttributes(ConditionOnClass.class.getName());
//        System.out.println(map);
        String[] value = (String[]) map.get("value");
        try {
            for (String classname : value) {
                Class cls = Class.forName(classname);
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }
}

UserConfig 类:

package com.itheima.springbootcondition.config;


import com.itheima.springbootcondition.condition.ClassCondition;
import com.itheima.springbootcondition.condition.ConditionOnClass;
import com.itheima.springbootcondition.domain.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;

@Configuration
public class UserConfig {
    @Bean
//    @Conditional(ClassCondition.class)
    @ConditionOnClass("redis.clients.jedis.Jedis")
    public User user(){
        return new User();
    }
}

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

整体项目结构:

springboot之三:原理分析之自动配置condition_第2张图片

你可能感兴趣的:(spring,boot,java,后端)