spring boot集成了jetty,tomcat,undertow等WEB容器,启动时可以智能的选择初始化哪个容器。接下来我们具体分析怎么实现智能选择。
spring boot容器的配置在org.springframework.boot.autoconfigure.web包下的EmbeddedServletContainerAutoConfiguration类,我们看下这个类的具体实现:
@Configuration
@ConditionalOnWebApplication
@Import(BeanPostProcessorsRegistrar.class)
public class EmbeddedServletContainerAutoConfiguration {
/**
* TOMCAT 容器实例bean配置信息
*/
@Configuration
@ConditionalOnClass({ Servlet.class, Tomcat.class })
@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
public static class EmbeddedTomcat {
@Bean
public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() {
return new TomcatEmbeddedServletContainerFactory();
}
}
/**
* Jetty 容器实例bean配置信息
*/
@Configuration
@ConditionalOnClass({ Servlet.class, Server.class, Loader.class,
WebAppContext.class })
@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
public static class EmbeddedJetty {
@Bean
public JettyEmbeddedServletContainerFactory jettyEmbeddedServletContainerFactory() {
return new JettyEmbeddedServletContainerFactory();
}
}
/**
* Undertow 容器实例bean配置信息
*/
@Configuration
@ConditionalOnClass({ Servlet.class, Undertow.class, SslClientAuthMode.class })
@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
public static class EmbeddedUndertow {
@Bean
public UndertowEmbeddedServletContainerFactory undertowEmbeddedServletContainerFactory() {
return new UndertowEmbeddedServletContainerFactory();
}
}
源码中分别存在jetty,tomcat,undertow的配置信息,那么spring-boot初始化时,具体是加载哪个呢,我们看到每个配置上都有@ConditionalOnClass与@ConditionalOnMissingBean注解,这两个注解是扩展的Conditional注解,根据条件判断是否加载bean
- @ConditionalOnClass 注解为判断classpath下是否有注解上给定的class类,存在加载,不存在,则不加载, 根据这个spring-boot会查找当前classpath下是否有注解给定的类,拿tomcat容器来说,会查找Servlet,Tomcat类是否存在,也就是tomcat容器的jar文件是否存在,这样就智能的根据我们引入的jar文件,智能的判断我们要加载的容器。
- @ConditionalOnMissingBean注解也是判断条件,具体可以查看源码
自定义注解Conditional
在org.springframework.boot.autoconfigure.condition包下,我们可以看到spring boot扩展了很多新的Conditional注解,当然我们也可以定义自己的扩展注解,完成自己特定的需求,上一篇使用Conditional注解完成我们的初始化服务动态加载,接下来,改造以前代码自定义我们的扩展注解完成同样的功能。
- 自定义注解MeetingConditional
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional({OnMeetingConditional.class})
public @interface MeetingConditional {
//当前注解需要传入env值,OnMeetingConditional类是Conditional注解的实际处理类,
当前注解同时加上Conditional注解,标识需要Conditional处理
String env() default "local";
}
- 定义Conditional注解的处理类OnMeetingConditional
public class OnMeetingConditional implements Condition {
// 获取环境信息类的meeting_type会议类型
private final static String type = System.getProperty("meeting_type") == null ? "local" :System.getProperty("meeting_type");
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//获取要装载的bean上配置的环境信息
List<String> envs = this.getEnvMultiValue(metadata, MeetingConditional.class);
//对比装载bean与环境信息的配置信息是否相同,相同返回true标识装载当前bean的信息
return envs.contains(type);
}
/**
* 获取自定义注解上配置的环境值
* @param metadata
* @param annotationType
* @return
*/
private List<String> getEnvMultiValue(AnnotatedTypeMetadata metadata, Class<?> annotationType){
MultiValueMap<String, Object> attributes = metadata.getAllAnnotationAttributes(annotationType.getName(), true);
List<String> candidates = new ArrayList();
if(attributes == null)
return Collections.emptyList();
candidates.addAll((List)attributes.get("evn"));
return candidates;
}
}
- 修改配置bean 加入自定义注解MeetingConditional
@Configuration
public class
MeetingInstanceConfig {
//当前bean只有环境信息是local的时候装载
@Bean
@MeetingConditional(evn = "local")
public IMeetingService localMeetingService() {
return new LocalMeetingServiceImpl();
}
//当前bean只有环境信息是romte的时候装载
@Bean
@MeetingConditional(evn = "romte")
public IMeetingService romteMeetingService() {
return new RomteMeetingServiceImpl();
}
}
下来测试:
- 设置System.setProperty("meeting_type","romte")初始化
运行结果:
this is Romte Meeting!
- 设置System.setProperty("meeting_type","local")初始化
运行结果:
this is Local Meeting!
结语
通过代码模拟了根据环境信息动态装载实例,在这一过程对spring-boot通过条件注解动态加载web容器有了进一步的认知,同时可以根据业务的需要定制出我们自己的智能代码。
网友评论