SpringBoot自动配置-@Conditional注解和Condition接口
@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>
查看条件注解源码:
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