3.4 FreeMarkerAutoConfiguration实例分析
本节通过FreeMarkerAutoConfiguration实例来分析Spring Boot中集成Freemarker模板引擎的整个自动配置的过程。
3.4.1 spring-boot-starter-freemarker工程
spring-boot-starter-freemarker工程是实现Free Marker模板引擎自动配置的启动工程,其目录结构如下:
. ├── pom.xml ├── spring-boot-starter-freemarker.iml └── src └── main └── resources └── META-INF
└── spring.provides 4 directories, 3 files
我们可以看出,这个工程没有任何Java代码,只有两个文件:pom.xml与spring.provides,其中,spring.provides文件如下:
provides: freemarker, spring-context-support
主要是给这个starter起个好区分的名字。
Spring Boot通过starter对项目的依赖进行统一管理.starter利用了Maven的传递依赖解析机制,把常用库聚合在一起,组成了针对特定功能而定制的依赖starter。
我们可以使用IDEA提供的Maven依赖图分析的功能,得到spring-boot-starter-freemarker依赖的module,如图3-4所示。
图3-4 spring-boot-starter-freemarker依赖的module
从图中我们可以看出其中的依赖关系。
当Spring Boot Application中自动配置EnableAutoConfiguration的相关类执行完毕之后,Spring Boot会进一步解析对应类的配置信息。如果我们配置了spring-boot-starter-freemarker, Maven就会通过这个starter所依赖的spring-boot-autoconfigure,自动传递到spring-boot-autoconfigure工程中。
3.4.2 spring-boot-autoconfigure工程
我们来简单分析一下spring-boot-autoconfigure工程中关于FreeMarker自动配置的逻辑实现。FreeMarker自动配置的入口类是:
org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration
这个配置类中导入了FreeMarkerServletWebConfiguration、FreeMarkerReactiveWebCon-figuration、FreeMarkerNonWebConfiguration配置类:
@Configuration @ConditionalOnClass({ freemarker.template.Configuration.class, FreeMarkerConfigurationFactory.class }) @EnableConfigurationProperties(FreeMarkerProperties.class) @Import({ FreeMarkerServletWebConfiguration.class, FreeMarkerReactiveWebConfiguration.class, FreeMarkerNonWebConfigura
tion.class }) public class FreeMarkerAutoConfiguration
其中:
❑@Configuration是org.springframework.context.annotation包里面的注解。我们已经知道用@Configuration注解该类,等价于XML中配置Bean;用@Bean标注方法等价于XML中配置Bean。
❑@ConditionalOnClass是org.springframework.boot.autoconfigure.condition包里面的注解。意思是当类路径下有指定的类的条件下,才会去注册被标注的类为一个Bean。在上面的代码中的意思就是,当类路径中有:
freemarker.template.Configuration.class FreeMarkerConfigurationFactory.class
这两个类的时候,才会去配置FreeMarkerAutoConfiguration。
❑@EnableConfigurationProperties,表示启动对FreeMarkerProperties.class的内嵌配置支持,自动将FreeMarkerProperties注册为一个Bean。这个FreeMarkerProperties类里面就是关于FreeMarker属性的配置:
@ConfigurationProperties(prefix = "spring.freemarker") public class FreeMarkerProperties extends AbstractTemplateViewResolverProperties { public static final String DEFAULT_TEMPLATE_LOADER_PATH = "classpath:/ templates/"; public static final String DEFAULT_PREFIX = ""; public static final String DEFAULT_SUFFIX = ".ftl"; … }
接下来,我们来看一下FreeMarkerServletWebConfiguration这个类。该类主要是用于配置基于servlet web context的Freemarker的配置。这个类的代码如下:
@Configuration @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) @ConditionalOnClass({ Servlet.class, FreeMarkerConfigurer.class }) @AutoConfigureAfter(WebMvcAutoConfiguration.class) class FreeMarkerServletWebConfiguration extends AbstractFreeMarkerConfiguration { protected FreeMarkerServletWebConfiguration(FreeMarkerProperties pro perties) { super(properties); } @Bean @ConditionalOnMissingBean(FreeMarkerConfig.class) public FreeMarkerConfigurer freeMarkerConfigurer() {
FreeMarkerConfigurer configurer = new FreeMarkerConfigurer(); applyProperties(configurer); return configurer; } @Bean public freemarker.template.Configuration freeMarkerConfiguration( FreeMarkerConfig configurer) { return configurer.getConfiguration(); } @Bean @ConditionalOnMissingBean(name = "freeMarkerViewResolver") @ConditionalOnProperty(name = "spring.freemarker.enabled", matchIfMis sing = true) public FreeMarkerViewResolver freeMarkerViewResolver() { FreeMarkerViewResolver resolver = new FreeMarkerViewResolver(); getProperties().applyToMvcViewResolver(resolver); return resolver; } @Bean @ConditionalOnMissingBean @ConditionalOnEnabledResourceChain public ResourceUrlEncodingFilter resourceUrlEncodingFilter() { return new ResourceUrlEncodingFilter(); } }
其中:
1)当该应用是基于Servlet的Web应用时,Spring容器内有Servlet.class、FreeMarker Configurer.class类实例存在。
2)Spring容器中不存在freeMarkerViewResolver的Bean。
3)应用程序的属性配置文件中没有匹配到"spring.freemarker.enabled"。
当1)2)3)三个条件都满足,则初始化freeMarkerViewResolver这个Bean。
我们也可以自定义自己的starter,以及实现对应的@MyEnableAutoConfiguration。Spring Boot有很多第三方starter,其自动配置的原理基本都是这样,比如mybatis-spring-boot-starter的MybatisAutoConfiguration,源码在如下地址:https://github.com/mybatis/spring-boot-starter,阅读源码可加深理解。