Loading

SpringBoot自动配置-@Conditional注解和Condition接口

Condition是Spring4.0后引入的条件化配置接口,通过实现Condition接口可以完成有条件的加载相应的Bean,@Conditional要配和Condition的实现类(ClassCondition)进行使用。

@Conditional注解案例1:

需求: 导入Jedis坐标后创建Bean
思路:判断redis.clients.jedis.Jedis.class文件是否存在

自定义类ClassCondition实现Condition接口:

package com.itheima.springbootcondition.condtion;

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

import java.util.Map;

public class ClassCondition implements Condition {
    /**
     * @param context  上下文对象。用于获取环境,IOC容器,ClassLoader对象
     * @param metadata 注解元对象。 可以用于获取注解定义的属性值
     * @return
     */
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        //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;
    }
}

注入User类型的Bean:

package com.itheima.springbootcondition.config;

import com.itheima.springbootcondition.condtion.ClassCondition;
import com.itheima.springbootcondition.condtion.ConditionOnClass;
import com.itheima.springbootcondition.domain.User;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
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();
    }

}

pom文件中引入jedis坐标测试:

        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>
        User user = context.getBean("user", User.class);
        System.out.println(user);

@Conditional注解案例2:

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

思路:配合自定义注解来动态指定加载bean需要哪个字节码文件

自定义注解ConditionOnClass:

package com.itheima.springbootcondition.condtion;

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的matches(ConditionContext var1, AnnotatedTypeMetadata var2)方法判断逻辑,根据自定义注解指定的value值来动态判断是否可以加载某个bean:

//2.需求:导入通过注解属性值 value 指定坐标后创建 Bean
        // 获取注解属性值 value
        Map<String, Object> map = metadata.getAnnotationAttributes(ConditionOnClass.class.getName());
        if (map == null) {
            return false;
        }
        //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;

测试是否引入fastjson的坐标来加载user的bean:

    @ConditionOnClass("com.alibaba.fastjson.JSON")
    public User user() {
        return new User();
    }
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.4</version>
        </dependency>

 查看条件注解源码:

SpringBoot 提供的常用条件注解:

ConditionalOnProperty:判断配置文件中是否有对应属性和值才初始化Bean

ConditionalOnClass:判断环境中是否有对应字节码文件才初始化Bean

ConditionalOnMissingBean:判断环境中没有对应Bean才初始化Bean

 springDataRedis配置自动装配源码:

包名:

org.springframework.boot.autoconfigure.data.redis;

类RedisAutoConfiguration:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.springframework.boot.autoconfigure.data.redis;

import java.net.UnknownHostException;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;

@Configuration
@ConditionalOnClass({RedisOperations.class})
@EnableConfigurationProperties({RedisProperties.class})
@Import({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class})
public class RedisAutoConfiguration {
    public RedisAutoConfiguration() {
    }

    @Bean
    @ConditionalOnMissingBean(
        name = {"redisTemplate"}
    )
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        RedisTemplate<Object, Object> template = new RedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

    @Bean
    @ConditionalOnMissingBean
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
}
@ConditionalOnProperty注解使用:
@ConditionalOnProperty(name = "username", havingValue = "yyj")

则必须在application.properties配置文件中配置:

username=yyj

 

posted @ 2023-02-11 15:37  1640808365  阅读(197)  评论(0编辑  收藏  举报