说明
在上篇《springboot学习(十五):Kafka的使用》博文中,通过简单的示例介绍了如何在springboot项目中使用kafka。代码十分简单,通过配置文件和注解就可以操作kakfa集群。本篇博文将通过springboot的源码来了解springboot如何自动装配kafka。
创建SpringApplication
从程序启动入口入手阅读代码:
@SpringBootApplication
public class Kafka2Application {
public static void main(String[] args) {
SpringApplication.run(Kafka2Application.class, args);
}
}
在以上代码中,使用了@SpringBootApplication注解,在main方法中调用了SpringApplication的run方法。
@SpringBootApplication注解是一个组合注解:
它主要包含了@SpringBootConfiguration, @EnableAutoConfiguration, @ComponentScan等注解,通过这三个注解实现了bean的配置和加载。
其中@EnableAutoConfiguration注解中通过@import引入了AutoConfigurationImportSelector类,该类对springboot的自动装配十分重要。
@ComponentScan注解通过扫描包中的@Bean注解来实现bean加载,当没有指定包的位置时,会默认扫描该注解所在包,所以启动类被放置在“最外面”。
在调用SpringApplication的run方法时,将启动类作为参数,创建SpringApplication对象。
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class[]{primarySource}, args);
}
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return (new SpringApplication(primarySources)).run(args);
}
在创建SpringApplication对象的方法中,通过判断classpath中类的类型来设置WebApplication的类型,并设置项目初始化器和监听器。
this.webApplicationType = WebApplicationType.deduceFromClasspath(); // 设置WebApplication的类型
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class)); // 设置初始化器
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class)); // 设置监听器
在设置初始化器和监听器时,都调用了getSpringFactoriesInstances方法,并设置了不同类类对象做为参数,而在该改方法中使用了SpringFactoriesLoader的loadFactoryNames方法,获取META-INF/spring.factories文件中配置的对应类的全限定名。
在springboot2.0版本中对loadFactoryNames方法做了改进,一次加载spring.factories文件中的所有内容并缓存起来。在之前的版本中会不断重复加载,只获取当前需要的内容。
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
if (result != null) {
return result;
} else {
try {
Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
LinkedMultiValueMap result = new LinkedMultiValueMap();
while(urls.hasMoreElements()) {
URL url = (URL)urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
Iterator var6 = properties.entrySet().iterator();
while(var6.hasNext()) {
Entry<?, ?> entry = (Entry)var6.next();
String factoryClassName = ((String)entry.getKey()).trim();
String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
int var10 = var9.length;
for(int var11 = 0; var11 < var10; ++var11) {
String factoryName = var9[var11];
result.add(factoryClassName, factoryName.trim());