技术经常会发生变划,框架也是换了又换,但是java中Spring是一个常青树,流行了很多年,Spring本身也存在一些缺点,比如使用xml配置维护起来比较困难,并不直观,于是Spring公司退出了SpringBoot弥补了Spring的不足。
今天就来说一说Springboot
他有哪些优点
1 通过构建Starter模块来引用,不是维护复杂的pom依赖
2 嵌入了Tomcat,Jetty等容器,让项目启动很简单
3 引入actuator可以对项目进行监控
基础的就不多说了,我想大部分人也都使用过,毕竟SpringBoot是一个非常流行的框架,现在来说说,SpringBoot的自动装配的源码,源码版本2.4.2,下面为该版本依赖
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.2</version>
为什么什么源码版本,因为SpringBoot不同的源码版本还是有区别的,在1.x的时候,自动装配调用的方法和2.4.2调用的方法是不同的,网上很多说的都是1.x版本的SpringBoot源码
下面我们一点点分析
首先查看一下启动类
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
看下 @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 {
@AliasFor(
annotation = EnableAutoConfiguration.class
)
Class<?>[] exclude() default {};
我们看到@EnableAutoConfiguration注解,通过注解的名字我们知道他肯定和自动装配有关,然后看看他的源码
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
我们看到@Import({AutoConfigurationImportSelector.class}),先说一下这个@Import,我第一次看到他是有疑问的,他的作用是把对象放到Spring的Bean工厂,那什么我们要用这种形式呢,因为AutoConfigurationImportSelector.class并不在SpringBoot默认扫描的范围,那仍然有疑问,那既然不在,我们也可以使用@ComponentScan("com.**")来进行扫描加载呀,答案就是AutoConfigurationImportSelector.class在jar包里面,并不是在com包下面,所以这时候使用@Import就是最好的了。
我们继续说EnableAutoConfiguration注解,我们看到这个注解加载了AutoConfigurationImportSelector.class,一样的通过类名我们基本上就知道,他和自动装配是分不开的,然后我们看下他的源码
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
private static final AutoConfigurationImportSelector.AutoConfigurationEntry EMPTY_ENTRY = new AutoConfigurationImportSelector.AutoConfigurationEntry();
private static final String[] NO_IMPORTS = new String[0];
private static final Log logger = LogFactory.getLog(AutoConfigurationImportSelector.class);
private static final String PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE = "spring.autoconfigure.exclude";
private ConfigurableListableBeanFactory beanFactory;
private Environment environment;
private ClassLoader beanClassLoader;
private ResourceLoader resourceLoader;
private AutoConfigurationImportSelector.ConfigurationClassFilter configurationClassFilter;
内容还是很丰富的,看下他的类图
我们发现AutoConfigurationImportSelector类是没有子类的,就说明最终干活的就是他,然后我们看到他实现了DeferredImportSelector类,而DeferredImportSelector又实现了ImportSelector接口类,那我们看看ImportSelector类中的方法
public interface ImportSelector {
/**
* Select and return the names of which class(es) should be imported based on
* the {@link AnnotationMetadata} of the importing @{@link Configuration} class.
* @return the class names, or an empty array if none
*/
String[] selectImports(AnnotationMetadata importingClassMetadata);
这个selectImports最终被AutoConfigurationImportSelector类重写,那最终启动调用的是不是他呢,我通过打断点尝试了一下,发现并不是他,为什么提这个方法呢,因为在SpringBoot 1.x的版本,SpringBoot启动是调用他的,而2.4.2版本就不是调用他了。
那是调用的哪一个? 如果看过自动装配介绍的同学一定会发现,其实SpringBoot加载的装配都是在spring.factory这个文件中,那我们就去找是哪个方法加载了这个文件
最终我们找到是AutoConfigurationImportSelector类中的getAutoConfigurationEntry方法,我们打上断点,启动一下看看他的调用流程,是不是调用了他
没错就是他,通过栈针我们发现调用他的方法是AutoConfigurationGroup类的process方法,而AutoConfigurationGroup类是AutoConfigurationImportSelector的内部类,再往上一层的调用是ConfigurationClassParser类的getImports方法
public Iterable<Group.Entry> getImports() {
for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
this.group.process(deferredImport.getConfigurationClass().getMetadata(),
deferredImport.getImportSelector());
}
return this.group.selectImports();
}
getImports() 方法调用了 this.group.process()以及this.group.selectImports()都是内部类中的方法,我们分析自动装配就是由这两个方法来实现
看看process方法中做了什么
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector, () -> {
return String.format("Only %s implementations are supported, got %s", AutoConfigurationImportSelector.class.getSimpleName(), deferredImportSelector.getClass().getName());
});
//调用getAutoConfigurationEntry方法得到自动配置类放入autoConfigurationEntry对象中
AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector)deferredImportSelector).getAutoConfigurationEntry(annotationMetadata);
//将封装了自动配置类的autoConfigurationEntry对象装进autoConfigurationEntries集合
this.autoConfigurationEntries.add(autoConfigurationEntry);
//遍历刚获取的自动配置类
Iterator var4 = autoConfigurationEntry.getConfigurations().iterator();
while(var4.hasNext()) {
String importClassName = (String)var4.next();
// 这里符合条件的自动配置类作为key,annotationMetadata作为值放进entries集合
this.entries.putIfAbsent(importClassName, annotationMetadata);
}
}
然后我们看看getAutoConfigurationEntry方法
// 获取符合条件的自动配置类
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
// 获取是否有配置spring.boot.enableautoconfiguration属性,默认返回true
if (!this.isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
} else {
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
//获取spring.factories文件配置的所有自动配置类
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
//删除重复的配置类
configurations = this.removeDuplicates(configurations);
//获取要排除的自动配置类,比如注解属性exclude的配置
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
//调用AutoConfigurationImportFilter的match方法来判断是否符合@ConditionalOnBean,@ConditionalOnClass或@ConditionalOnWebApplication
configurations = this.getConfigurationClassFilter().filter(configurations);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
//将符合条件的自动配置类返回
return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
}
}
因为@ConditionalOnBean可以实现条件装配,所以要仔细看一下是怎样实现的,看一下this.getConfigurationClassFilter().filter(configurations)
List<String> filter(List<String> configurations) {
long startTime = System.nanoTime();
// 将从spring.factories中获取的自动配置类转出字符串数组
String[] candidates = StringUtils.toStringArray(configurations);
boolean skipped = false;
Iterator var6 = this.filters.iterator();
int i;
while(var6.hasNext()) {
// getAutoConfigurationImportFilters方法:拿到OnBeanCondition,OnClassCondition和OnWebApplicationCondition
AutoConfigurationImportFilter filter = (AutoConfigurationImportFilter)var6.next();
// @ConditionalOnClass,@ConditionalOnBean和@ConditionalOnWebApplication里面的注解值)是否匹配,
boolean[] match = filter.match(candidates, this.autoConfigurationMetadata);
for(i = 0; i < match.length; ++i) {
if (!match[i]) {
candidates[i] = null;
skipped = true;
}
}
}
if (!skipped) {
return configurations;
} else {
List<String> result = new ArrayList(candidates.length);
String[] var12 = candidates;
int var14 = candidates.length;
for(i = 0; i < var14; ++i) {
String candidate = var12[i];
if (candidate != null) {
result.add(candidate);
}
}
if (AutoConfigurationImportSelector.logger.isTraceEnabled()) {
int numberFiltered = configurations.size() - result.size();
AutoConfigurationImportSelector.logger.trace("Filtered " + numberFiltered + " auto configuration class in " + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) + " ms");
}
// 返回符合条件的自动配置类
return result;
}
}
以上就是对条件装配的实现,最后我们调用this.group.selectImports()方法。整个自动装配的流程就基本结束了。