前言
上面几篇文章介绍了SpringFramework的一些原理,这里开始介绍一下SpringBoot,并通过自定义一些功能来介绍SpringBoot的原理。SpringBoot在SpringFramework的基础上集成了Web容器,日志等功能,可以快速的实现Web服务。
先看SpringBoot必要的依赖。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
spring-boot包含了SpringBoot的核心实现类。
spring-boot-autoconfigure则是根据当前classpath的类来注入不同的实现类。
EnableAutoConfiguration
先看一个基本的例子,这个例子实现了一个简单的web服务。
- 引入必要的依赖,开启web服务需要引入对应的EmbedWeb容器。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
- 程序入口,这里使用了EnableAutoConfiguration注解。
@Configuration
@EnableAutoConfiguration
public class Bootstrap {
public static void main(String[] args) {
SpringApplication springApplication = new SpringApplication(Bootstrap.class);
springApplication.run(args);
}
@Controller
public static class MyController {
@RequestMapping
@ResponseBody
public Map index() {
Map<String, String> map = new HashMap<String, String>();
map.put("hello", "world");
return map;
}
}
}
观察EnableAutoConfiguration可以发现,这里Import了EnableAutoConfigurationImportSelector。
Import主要是配合Configuration来使用的,用来导出更多的Configuration类,ConfigurationClassPostProcessor会读取Import的内容来实现具体的逻辑。
EnableAutoConfigurationImportSelector实现了DeferredImportSelector接口,并实现了selectImports方法,用来导出Configuration类。
String[] selectImports(AnnotationMetadata importingClassMetadata);
导出的类是通过SpringFactoriesLoader.loadFactoryNames()读取了ClassPath下面的META-INF/spring.factories文件,这个文件内容大致如下。
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
...
org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration
...
其中EmbeddedServletContainerAutoConfiguration是实现web服务的主要的配置类。这个类会根据当前存在的类的信息注入必要的EmbeddedServletContainerFactory类。
spring-boot-starter-tomcat引入了tomcat的依赖,所以EmbeddedServletContainerAutoConfiguration发现存在Tomcat.class就会注入TomcatEmbeddedServletContainerFactory来内置web容器。
@Configuration
@ConditionalOnClass({ Servlet.class, Tomcat.class })
@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
public static class EmbeddedTomcat {
@Bean
public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() {
return new TomcatEmbeddedServletContainerFactory();
}
}
自定义EnableAutoConfiguration
自定义EnableAutoConfiguration就比较简单了。完整的代码在Github上了。
- 自定义EnableAutoConfiguration,这里Import了MyEnableAutoConfigurationImport。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(MyEnableAutoConfigurationImport.class)
public @interface MyEnableAutoConfiguration {
}
- 自定义EnableAutoConfigurationImport,注入了ClassLoader,并调用SpringFactoriesLoader.loadFactoryNames()方法,导出Configuration的类。
public class MyEnableAutoConfigurationImport implements DeferredImportSelector, BeanClassLoaderAware {
private ClassLoader classLoader;
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
List<String> beanNames = SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class, classLoader);
return beanNames.toArray(new String[beanNames.size()]);
}
}
- 入口类,这里使用了MyEnableAutoConfiguration注解。
@Configuration
@MyEnableAutoConfiguration
public class CustomizeEnableAutoConfigure {
public static void main(String[] args) {
SpringApplication application = new SpringApplication(CustomizeEnableAutoConfigure.class);
application.run(args);
}
@Controller
public static class MyController {
@RequestMapping
@ResponseBody
public Map index() {
Map<String, String> map = new HashMap<String, String>();
map.put("hello", "world");
return map;
}
}
}
结语
这里主要介绍了SpringBoot的EnableAutoConfiguration的实现,后面会介绍更多关于SpringBoot的内容。
网友评论