SpringBoot自动配置-Condition
Condition是Spring4.0后引入的条件化配置接口,通过实现Condition接口可以完成有条件的加载相应的Bean
一:@Conditional要配和Condition的实现类(ClassCondition)进行使用
1.创建:ClassCondition类实现Condition接口
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; } }
@Configuration
public class UserConfig {
@Bean
@Conditional(ClassCondition.class)
public User user(){
return new User();
}
}
3.测试
@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);
}
}
通过@Conditional条件注解,当我们引入redis的maven坐标时候,创建了User的bean
二:在上面我们发现 redis.clients.jedis.Jedis的坐标是写死的,那有什么办法根据不同的坐标动态的创建bean吗?
我们自定义来实现一下@ConditionalOnClass这个注解
1.自定义注解@ConditionalOnClass
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(ClassCondition.class)
public @interface ConditionOnClass {
String[] value();
}
2.创建UserConfig 配置类
@Configuration
public class UserConfig {
@Bean
//@Conditional(ClassCondition.class)
@ConditionOnClass("com.alibaba.fastjson.JSON")
public User user(){
return new User();
}
@Bean
@ConditionalOnProperty(name = "itcast",havingValue = "itheima")
public User user2(){
return new User();
}
}
3.修改ClassCondition 类
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<String, Object> map = metadata.getAnnotationAttributes(ConditionOnClass.class.getName());
//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;
}
}
4.测试
@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);
}
}
通过添加@ConditionalOnClass,并在@ConditionalOnClass的参数里面填写,回传到ClassCondition里面,完成导入坐标动态创建bean
三:上面的两个案例中,我们学会了@Conditional条件注解,以及创建自定义注解@ConditionalOnClass来实现动态创建Userbean,Springboot中redis实际是怎么创建redisTemplate的?
其实springboot为我们提供了很多condition的依赖,他们都放到了包:org.springframework.boot:spring-boot-autoconfigure:x.x.x
我们可以在此包中找到condition包:
我们再次找到data包中redis包,我们可以看到RedisAutoConfiguration
类,在里面可以看到创建redisTemplate的bean。
在里面我们可以看到引入了@ConditionalOnClass(RedisOperations.class)
,标识必须存在字节码文件RedisOperations.class,并且容器中不存在redisTemplate的时候。才能创建redisTemplate 。这和我们动态创建User的bean是一个套路
四:切换springboot内置web服务器
SpringBoot的web环境中默认使用tomcat作为内置服务器,其实SpringBoot提供了4中内置服务器供我们选择,我们可以很方便的进行切换。
我们在依赖包:org.springframework.boot.autoconfigure 中找到web 包,里面有个embedded 包。
- JettyWebServerFactoryCustomizer :用来配置jetty服务器
- NettyWebServerFactoryCustomizer:用来配置netty服务器
- TomcatWebServerFactoryCustomizer:用来配置tomcat服务器
- UndertowWebServerFactoryCustomizer:用来配置Undertow服务器
- EmbeddedWebServerFactoryCustomizerAutoConfiguration:用来根据条件配置不通的服务器。
我们来看一下EmbeddedWebServerFactoryCustomizerAutoConfiguration 类:
- 我们可以看到在EmbeddedWebServerFactoryCustomizerAutoConfiguration 类中有一个注解:@ConditionalOnWebApplication 标识当项目中配置了web环境的时候才能让这个类起作用。
- 我们可以看到配置TomcatWebServerFactoryCustomizerConfiguration 的条件为 @ConditionalOnClass({ Tomcat.class, UpgradeProtocol.class }) ,表示项目中必须存在tomcat.class 和UpgradeProtocol.class,才能去实例化tomcat服务。
- 其他几个web 服务配置条件可以自行查询。
为此,比如我们想使用jettyweb服务器替代tomcat服务器的话,可以直接在项目中排除tomcat依赖,并引入jetty依赖。
在springboot项目中,默认使用的是tomcat服务器,是嵌入在依赖spring-boot-starter-web
中的,我们只需要排除tomcat依赖,并导入jetty依赖即可。
最后再引入jetty