springboot自动配置实现初探

结合源码探究springboot如何实现自动配置

1。@SpringBootApplication一切从这里开始
@SpringBootApplication
public class Demo2Application {
public static void main(String[] args) {
SpringApplication.run(Demo2Application.class, args);
}
}
这是一个典型的springboot启动入口,自动配置功能的启用也是从这里开始。
2。详细看一下@SpringBootApplication
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM,
classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
看一下元注解,@EnableAutoConfiguration自动配置,再近一点,
**3。**放大@EnableAutoConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
这里有一个@Import(AutoConfigurationImportSelector.class),自动配置选择器,这个类实现了自动装配的逻辑
4。更近一点AutoConfigurationImportSelector关键方法:
protected AutoConfigurationEntry getAutoConfigurationEntry(
AutoConfigurationMetadata autoConfigurationMetadata,//4.1
AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
List configurations = getCandidateConfigurations(annotationMetadata,
attributes);
configurations = removeDuplicates(configurations);
Set exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
4.1>有些同学可能对这个数据怎么来的很疑惑,这个都在文件spring-autoconfigure-metadata.properties中有配置,这个文件可以通过开发工具如idea进行配置自动生成,感兴趣的小伙伴可以看一下。
接下来咋们进入configurations = filter(configurations, autoConfigurationMetadata);看一下是怎么过滤的,private List filter(List configurations,
AutoConfigurationMetadata autoConfigurationMetadata) {
long startTime = System.nanoTime();
String[] candidates = StringUtils.toStringArray(configurations);
boolean[] skip = new boolean[candidates.length];
boolean skipped = false;
for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {//4.2
invokeAwareMethods(filter);
boolean[] match = filter.match(candidates, autoConfigurationMetadata);//4.3
for (int i = 0; i < match.length; i++) {
if (!match[i]) {
skip[i] = true;
candidates[i] = null;
skipped = true;
}
}
}。。。
4.2>通过spring的spi机制加载过滤器
protected List getAutoConfigurationImportFilters() {
return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class,
this.beanClassLoader);
}
这是配置的三种过滤器:
# Auto Configuration Import Filters
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=
org.springframework.boot.autoconfigure.condition.OnBeanCondition,
org.springframework.boot.autoconfigure.condition.OnClassCondition,
org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition

4.3>按过滤器规则对装配类进行匹配
中间我省略了部分方法调用,最终是这个方法返回在类路径中是否有这个类的:
public static boolean isPresent(String className, ClassLoader classLoader) {
if (classLoader == null) {
classLoader = ClassUtils.getDefaultClassLoader();
}
try {
forName(className, classLoader);
return true;
}
catch (Throwable ex) {
return false;
}
}
这里可以看到,当类加载器加载的类不存在时,抛出异常,匹配失败。

基本的自动匹配结束了,接下来是spring注解流程实例化类等操作。

5。介绍一下spring支持的条件选择
OnBeanCondition
OnClassCondition
OnCloudPlatformCondition
OnExpressionCondition
OnJavaCondition
OnJndiCondition
OnPropertyCondition
OnPropertyListCondition
OnResourceCondition
OnWebApplicationCondition
springboot对这个类型进行匹配的类,springboot对应的几个条件注解:
ConditionalOnBean
ConditionalOnClass
ConditionalOnCloudPlatform
ConditionalOnExpression
ConditionalOnJava
ConditionalOnJndi
ConditionalOnMissingBean
ConditionalOnMissingClass
ConditionalOnNotWebApplication
ConditionalOnProperty
ConditionalOnResource
ConditionalOnSingleCandidate
ConditionalOnWebApplication

6。最后看一下一些实现方案吧
@Configuration//一个spring配置类
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)//顺序
@ConditionalOnClass(ServletRequest.class)//当classpath中有ServletRequest时生效
@ConditionalOnWebApplication(type = Type.SERVLET)//当应用的类型是SERVLET生效
@EnableConfigurationProperties(ServerProperties.class)//支持用户复写属性
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
//整合配置
public class ServletWebServerFactoryAutoConfiguration {

在看一下:
@Configuration
@ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })
@ConditionalOnMissingBean(value = ServletWebServerFactory.class,
search = SearchStrategy.CURRENT)
public static class EmbeddedTomcat {
@Bean
public TomcatServletWebServerFactory tomcatServletWebServerFactory() {
return new TomcatServletWebServerFactory();
}
}
这是一个配置类,在有Servlet.class, Tomcat.class, UpgradeProtocol.class生效,当没有ServletWebServerFactory生效,所以我们可以自定义一个bean,复写自动配置的默认实现,如:
@Bean
public TomcatServletWebServerFactory tomcatServletWebServerFactory() {
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
tomcat.setPort(9090);
return tomcat
}
这样我们就可以自定义一个tomcat了,这个tomcat监听9090端口。

猜你喜欢

转载自blog.csdn.net/strive____/article/details/91347230