SpringBoot整合FreeMarker&&FreeMarkerAutoConfiguration 自动装配相关源码跟踪分析

Freemarker 简介
这是一个相当老牌的开源的免费的模版引擎。通过 Freemarker 模版,我们可以将数据渲染成 HTML 网页、电子邮件、配置文件以及源代码等。Freemarker 不是面向最终用户的,而是一个 Java 类库,我们可以将之作为一个普通的组件嵌入到我们的产品中。

SpringBoot整合FreeMarker&&FreeMarkerAutoConfiguration 自动装配相关源码跟踪分析_第1张图片
Freemarker 模版后缀为 .ftl(FreeMarker Template Language)。FTL 是一种简单的、专用的语言,它不是像 Java 那样成熟的编程语言。在模板中,你可以专注于如何展现数据, 而在模板之外可以专注于要展示什么数据。

这里先把代码显示咯,再做分析解释

就不从新建项目讲起来了,这样废话就太多了,就是记得加上SpringBoot官方给的Freemarker的依赖。
在这里插入图片描述

结构
SpringBoot整合FreeMarker&&FreeMarkerAutoConfiguration 自动装配相关源码跟踪分析_第2张图片

依赖
新建时,没加也问题不大,我们自己在pom.xml中手动加上就好


    org.springframework.boot
    spring-boot-starter-freemarker


    org.springframework.boot
    spring-boot-starter-web


UserController

/**
 * @author ZSL
 * @ClassName UserController
 * @description
 * @date 2019/8/6
 */
@Controller
public class UserController {


    @GetMapping("/user")
    public String getUser( Model  model){
        User user = new User();
        user.setId("zid");
        user.setName("zsl");
        user.setAge(18);
        model.addAttribute("user",user);
        return "index";
    }

}

在resources目录下的templates文件夹下新建.ftl的FreeMarker文件
这里你直接新建是没有.ftl文件的,你可以通过html文件改后缀也可以直接新定义新建.ftl文件的选项,.ftl和html文件差不多。
SpringBoot整合FreeMarker&&FreeMarkerAutoConfiguration 自动装配相关源码跟踪分析_第3张图片




    
    Title



    ${user.id}
    ${user.name}
    ${user.age}




相信上面的代码不用注释你能看得懂,都是基础代码。

那么我们来分析一下,我们知道Starter中知道了有个自动装配类xxxAutoConfiguration的,那么我们来看看在FreeMarker中的自动装配类。
我们从头慢慢来分析

启动类
SpringBoot整合FreeMarker&&FreeMarkerAutoConfiguration 自动装配相关源码跟踪分析_第4张图片

@SpringBootApplication是个组合注解
SpringBoot整合FreeMarker&&FreeMarkerAutoConfiguration 自动装配相关源码跟踪分析_第5张图片

@EnableAutoConfiguration 表示启用 Spring 应用程序上下文的自动配置,该注解会自动导入一个名为 AutoConfigurationImportSelector 的类,而这个类会去读取一个名为 spring.factories 的文件, spring.factories 中则定义需要加载的自动化配置类
没错是的,我们的FreeMarkerAutoConfiguration 自动装配类就是在这个pring.factories文件中。
SpringBoot整合FreeMarker&&FreeMarkerAutoConfiguration 自动装配相关源码跟踪分析_第6张图片

而这个spring.factories的路径:

org\springframework\boot\spring-boot-autoconfigure\2.1.6.RELEASE\spring-boot-autoconfigure-2.1.6.RELEASE-sources.jar!\META-INF\spring.factories

那么我们来看这个FreeMarkerAutoConfiguration自动装配类
org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration

/**
 * {@link EnableAutoConfiguration Auto-configuration} for FreeMarker.
 *
 * @author Andy Wilkinson
 * @author Dave Syer
 * @author Kazuki Shimizu
 * @since 1.1.0
 */
@Configuration
@ConditionalOnClass({ freemarker.template.Configuration.class, FreeMarkerConfigurationFactory.class })
@EnableConfigurationProperties(FreeMarkerProperties.class)
@Import({ FreeMarkerServletWebConfiguration.class, FreeMarkerReactiveWebConfiguration.class,
      FreeMarkerNonWebConfiguration.class })
public class FreeMarkerAutoConfiguration {

   private static final Log logger = LogFactory.getLog(FreeMarkerAutoConfiguration.class);

   private final ApplicationContext applicationContext;

   private final FreeMarkerProperties properties;

   public FreeMarkerAutoConfiguration(ApplicationContext applicationContext, FreeMarkerProperties properties) {
      this.applicationContext = applicationContext;
      this.properties = properties;
   }

   @PostConstruct
   public void checkTemplateLocationExists() {
      if (logger.isWarnEnabled() && this.properties.isCheckTemplateLocation()) {
         List locations = getLocations();
         if (locations.stream().noneMatch(this::locationExists)) {
            logger.warn("Cannot find template location(s): " + locations + " (please add some templates, "
                  + "check your FreeMarker configuration, or set "
                  + "spring.freemarker.checkTemplateLocation=false)");
         }
      }
   }

   private List getLocations() {
      List locations = new ArrayList<>();
      for (String templateLoaderPath : this.properties.getTemplateLoaderPath()) {
         TemplateLocation location = new TemplateLocation(templateLoaderPath);
         locations.add(location);
      }
      return locations;
   }

   private boolean locationExists(TemplateLocation location) {
      return location.exists(this.applicationContext);
   }

}

SpringBoot整合FreeMarker&&FreeMarkerAutoConfiguration 自动装配相关源码跟踪分析_第7张图片

  1. @Configuration这是个配置类

  2. @ConditionalOnClass({ freemarker.template.Configuration.class, FreeMarkerConfigurationFactory.class })
    当 classpath 下存在 freemarker.template.Configuration 以及 FreeMarkerConfigurationFactory 时,配置才会生效,也就是说当我们引入了 Freemarker 之后,配置就会生效。你也可以理解为加了相关依赖。

  3. @Import({ FreeMarkerServletWebConfiguration.class, FreeMarkerReactiveWebConfiguration.class,FreeMarkerNonWebConfiguration.class })
    FreeMarkerServletWebConfiguration.class在web环境中,,FreeMarkerNonWebConfiguration.class不在web环境中,本地的。

但是这个FreeMarkerAutoConfiguration 自动化配置只做了模板位置检查。
因为这里不是在本地中使用FreeMarker,而是在Web环境中使用,所以配置是导入到了FreeMarkerServletWebConfiguration这个配置中

@Configuration
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@ConditionalOnClass({ Servlet.class, FreeMarkerConfigurer.class })
@AutoConfigureAfter(WebMvcAutoConfiguration.class)
class FreeMarkerServletWebConfiguration extends AbstractFreeMarkerConfiguration {

   protected FreeMarkerServletWebConfiguration(FreeMarkerProperties properties) {
      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", matchIfMissing = true)
   public FreeMarkerViewResolver freeMarkerViewResolver() {
      FreeMarkerViewResolver resolver = new FreeMarkerViewResolver();
      getProperties().applyToMvcViewResolver(resolver);
      return resolver;
   }

   @Bean
   @ConditionalOnEnabledResourceChain
   @ConditionalOnMissingFilterBean(ResourceUrlEncodingFilter.class)
   public FilterRegistrationBean resourceUrlEncodingFilter() {
      FilterRegistrationBean registration = new FilterRegistrationBean<>(
            new ResourceUrlEncodingFilter());
      registration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ERROR);
      return registration;
   }

}

在这里插入图片描述

  1. @Configuration这是个配置类

2.@ConditionalOnWebApplication 表示当前配置在 web 环境下才会生效。
3.ConditionalOnClass 表示当前配置在存在 Servlet 和 FreeMarkerConfigurer 时才会生效。
4.@AutoConfigureAfter 表示当前自动化配置在 WebMvcAutoConfiguration 之后完成。

freeMarkerConfigurer方法分析
SpringBoot整合FreeMarker&&FreeMarkerAutoConfiguration 自动装配相关源码跟踪分析_第8张图片 在这里插入图片描述

那么我们来看这个applyProperties

protected void applyProperties(FreeMarkerConfigurationFactory factory) {
   factory.setTemplateLoaderPaths(this.properties.getTemplateLoaderPath());
   factory.setPreferFileSystemAccess(this.properties.isPreferFileSystemAccess());
   factory.setDefaultEncoding(this.properties.getCharsetName());
   Properties settings = new Properties();
   settings.putAll(this.properties.getSettings());
   factory.setFreemarkerSettings(settings);
}

这里的applyProperties的参数是一个FreeMarkerConfigurationFactory
而我们传过来的是FreeMarkerConfigurer,查看它们的继承关系
SpringBoot整合FreeMarker&&FreeMarkerAutoConfiguration 自动装配相关源码跟踪分析_第9张图片

在applyProperties中,通过在FreeMarkerConfigurationFactory中,从配置文件中获取配置信息来进行装配的。

FreeMarkerConfigurer 是 Freemarker 的一些基本配置,例如 templateLoaderPath、defaultEncoding 等

freeMarkerViewResolver方法分析

@Bean
@ConditionalOnMissingBean(name = "freeMarkerViewResolver")
@ConditionalOnProperty(name = "spring.freemarker.enabled", matchIfMissing = true)
public FreeMarkerViewResolver freeMarkerViewResolver() {
   FreeMarkerViewResolver resolver = new FreeMarkerViewResolver();
   getProperties().applyToMvcViewResolver(resolver);
   return resolver;
}

  1. @ConditionalOnMissingBean(name = “freeMarkerViewResolver”)
    在不存在freeMarkerViewResolver这个对象时有效
    2。@ConditionalOnProperty(prefix = “rest”, name = “auth-open”, havingValue = “true”, matchIfMissing = true)
    prefix application.properties配置的前缀
    name 属性是从application.properties配置文件中读取属性值
    havingValue 配置读取的属性值跟havingValue做比较,如果一样则返回true;否则返回false。
    如果返回值为false,则该configuration不生效;为true则生效
    matchIfMissing = true表示如果没有在application.properties设置该属性,则默认为条件符合

    意思就是在application.properties等配置文件中如果没有配置视图解析器,就默认这个配置类生效

3.FreeMarkerViewResolver 则是视图解析器的基本配置,包含了viewClass、suffix、allowRequestOverride、allowSessionOverride 等属性。
SpringBoot整合FreeMarker&&FreeMarkerAutoConfiguration 自动装配相关源码跟踪分析_第10张图片
在这里插入图片描述
SpringBoot整合FreeMarker&&FreeMarkerAutoConfiguration 自动装配相关源码跟踪分析_第11张图片

FreeMarkerServletWebConfiguration的构造方法

protected FreeMarkerServletWebConfiguration(FreeMarkerProperties properties) {
   super(properties);
}

查看FreeMarkerProperties 这个类

@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";

   /**
    * Well-known FreeMarker keys which are passed to FreeMarker's Configuration.
    */
   private Map settings = new HashMap<>();

   /**
    * Comma-separated list of template paths.
    */
   private String[] templateLoaderPath = new String[] { DEFAULT_TEMPLATE_LOADER_PATH };

   /**
    * Whether to prefer file system access for template loading. File system access
    * enables hot detection of template changes.
    */
   private boolean preferFileSystemAccess = true;

   public FreeMarkerProperties() {
      super(DEFAULT_PREFIX, DEFAULT_SUFFIX);
   }

   public Map getSettings() {
      return this.settings;
   }

   public void setSettings(Map settings) {
      this.settings = settings;
   }

   public String[] getTemplateLoaderPath() {
      return this.templateLoaderPath;
   }

   public boolean isPreferFileSystemAccess() {
      return this.preferFileSystemAccess;
   }

   public void setPreferFileSystemAccess(boolean preferFileSystemAccess) {
      this.preferFileSystemAccess = preferFileSystemAccess;
   }

   public void setTemplateLoaderPath(String... templateLoaderPaths) {
      this.templateLoaderPath = templateLoaderPaths;
   }

}

看到这个类的很多东西是不是很眼熟了?
SpringBoot整合FreeMarker&&FreeMarkerAutoConfiguration 自动装配相关源码跟踪分析_第12张图片
这里的类名都是看到类名就知道它的作用的,就不一一去说了,太多废话了。

在 SSM 的 XML 文件中配置 Freemarker ,也是配置这些东西。只不过这些配置在SpringBoot中有自动装配类 FreeMarkerServletWebConfiguration 帮我们完成了。

你可能感兴趣的:(SpringBoot)