博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
spring boot约定优于配置的这种做法在如今越来越流行了
阅读量:5231 次
发布时间:2019-06-14

本文共 14396 字,大约阅读时间需要 47 分钟。

约定优于配置的这种做法在如今越来越流行了,它的特点是简单、快速、便捷。但是这是建立在程序员熟悉这些约定的前提上。而 Spring 拥有一个庞大的生态体系,刚开始转到 Spring Boot 完全舍弃 XML 时肯定是不习惯的,所以也会造成一些困扰。

 

运行方式

spring-boot-starter-web 包含了 Spring MVC 的相关依赖(包括 Json 支持的 Jackson 和数据校验的 Hibernate Validator)和一个内置的 Tomcat 容器,这使得在开发阶段可以直接通过 main方法或是 JAR 包独立运行一个 WEB 项目。而在部署阶段也可以打成 WAR 包放到生产环境运行。

 

@SpringBootApplicationpublic class Application extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { return application.sources(Application.class); } public static void main(String[] args) throws Exception { SpringApplication.run(Application.class, args); } }

在拥有 @SpringBootApplication 注解的类中,使用 SpringApplication 的 run 方法可以通过JAR启动项目。

 

继承 SpringBootServletInitializer 类并实现 configure 方法,使用 application 的 sources 方法可以通过WAR启动项目。

 

 

配置文件

Spring boot 的默认配置文件是 resources 下的 application.properties 和 application.yml

 

 

配置文件

Spring boot 的默认配置文件是 resources 下的 application.properties 和 application.yml

我曾在项目中遇到过 application.properties 出现中文乱码问题,当时尝试了很多办法都没有解决。Spring Boot 总是会以 iso-8859 的编码方式读取该文件,后来改用 YAML 了就再也没有出现过乱码了。并且它也拥有更简洁的语法,所以在此也更推荐使用 application.yml 作为默认的配置文件。

配置文件中可以定义一个叫做 spring.profiles.active 的属性,该属性可以根据运行环境自动读取不同的配置文件。例如将该属性定义为 dev 的话,Spring Boot 会额外从 application-dev.yml 文件中读取该环境的配置。

Spring Boot 注入配置文件属性的方法有两种,一种是通过 @Value 注解接受配置文件中的属性,另外一种是通过 @ConfigurationProperties 注解通过 set 方法自动为Bean注入对应的属性。

通过 @Value 注入属性,接收者既可以是方法参数,也可以是成员变量。例如配置文件为:

dataSource:    url: jdbc:mysql://127.0.0.1:3306/test username: test password: test filters: stat,slf4j redis: host: 192.168.1.222 port: 6379

通过 @Value 接受方法参数初始化Bean:

@Beanpublic JedisPool jedisPool(@Value("${redis.host}") String host,                            @Value("${redis.port}") int port) { return new JedisPool(host, port); } 注入配置文件属性
注入配置文件属性
注入配置文件属性
 

通过 @ConfigurationProperties 读取配置初始化Bean,会直接调用对应的 set 方法注入:

@Bean(initMethod="init",destroyMethod="close")@ConfigurationProperties(prefix="dataSource") public DataSource dataSource() { return new DruidDataSource(); }

Spring Boot 目前还无法直接注入的静态变量。我目前使用的方法是专门建立一个读取配置文件的Bean,然后使用 @PostConstruct 注解修饰的方法对这些静态属性进行初始化,例如:

@Configurationpublic class ConstantsInitializer { @Value("${paging_size}") private String pagingSize; @PostConstruct public void initConstants() { Constants.PAGING_SIZE = this.pagingSize; } }
 

Servlet

Servlet 中最重要的配置文件就是 web.xml ,它的主要用途是配置Servlet映射和过滤器。而在 Spring Boot 中这将简单很多,只需要将对应的 Servlet 和 Filter 定义为 Bean 即可。

声明一个映射根路径的 Servlet ,例如 Spring MVC 的 DispatcherServlet :

 

 

Spring MVC

Spring MVC 主要的配置都可以通过继承 WebMvcConfigurerAdapter (或者 WebMvcConfigurationSupport )类进行修改,这两个类的主要方法有:

Spring MVC 主要的配置都可以通过继承 WebMvcConfigurerAdapter (或者 WebMvcConfigurationSupport )类进行修改,这两个类的主要方法有:

Spring MVC 主要的配置都可以通过继承 WebMvcConfigurerAdapter (或者 WebMvcConfigurationSupport )类进行修改,这两个类的主要方法有:

  • addFormatters :增加格式化工具(用于接收参数)
  • configureMessageConverters :配置消息转换器(用于 @RequestBody 和 @ResponseBody )
  • configurePathMatch :配置路径映射
  • addArgumentResolvers :配置参数解析器(用于接收参数)
  • addInterceptors :添加拦截器

总之几乎所有关于 Spring MVC 都可以在这个类中配置。之后只需要将其设为 @Configuration,Spring Boot 就会在运行时加载这些配置。

只需要将其设为 @Configuration,Spring Boot 就会在运行时加载这些配置。

只需要将其设为 @Configuration,Spring Boot 就会在运行时加载这些配置。

只需要将其设为 @Configuration,Spring Boot 就会在运行时加载这些配置。

 

还有一些常用的 Bean 默认会自动创建,但是可以通过自定义进行覆盖,例如负责 @RequestBody 和 @RequestBody 进行转换的 MappingJackson2HttpMessageConverter 和 ObjectMapper ,可以直接这样覆盖掉:

@Beanpublic MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() { return new CustomMappingJackson2HttpMessageConverter(); } @Bean public ObjectMapper jsonMapper(){ ObjectMapper objectMapper = new ObjectMapper(); //null输出空字符串 objectMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer() { @Override public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException { jgen.writeString(""); } }); return objectMapper; }

DataSource

如果使用了 spring-boot-starter-data-jpa ,Spring Boot将会自动创建一个 DataSource Bean。可以直接在配置文件中定义它的属性,前缀是 spring.datasource 。并且无需指定数据库的方言,这个 Bean 会自动根据项目中依赖的数据库驱动判断使用的哪种数据库。

同样的,如果使用了 spring-boot-starter-data-redis ,也会自动创建 RedisTemplate 、 ConnectionFactory 等 Bean。也同样可以在配置文件中定义属性,前缀是 spring.redis 。

还有一些常用的 Bean 默认会自动创建,但是可以通过自定义进行覆盖,例如负责 @RequestBody 和 @RequestBody 进行转换的 MappingJackson2HttpMessageConverter 和 ObjectMapper ,可以直接这样覆盖掉:

@Beanpublic MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() { return new CustomMappingJackson2HttpMessageConverter(); } @Bean public ObjectMapper jsonMapper(){ ObjectMapper objectMapper = new ObjectMapper(); //null输出空字符串 objectMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer() { @Override public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException { jgen.writeString(""); } }); return objectMapper; }

DataSource

如果使用了 spring-boot-starter-data-jpa ,Spring Boot将会自动创建一个 DataSource Bean。可以直接在配置文件中定义它的属性,前缀是 spring.datasource 。并且无需指定数据库的方言,这个 Bean 会自动根据项目中依赖的数据库驱动判断使用的哪种数据库。

同样的,如果使用了 spring-boot-starter-data-redis ,也会自动创建 RedisTemplate 、 ConnectionFactory 等 Bean。也同样可以在配置文件中定义属性,前缀是 spring.redis 。

 

 

springboot用来简化Spring框架带来的大量XML配置以及复杂的依赖管理,让开发人员可以更加关注业务逻辑的开发。

比如不使用springboot而使用SpringMVC作为web框架进行开发的时候,需要配置相关的SpringMVC配置以及对应的依赖,比较繁琐;而使用springboot的话只需要以下短短的几行代码就可以使用SpringMVC,可谓相当地方便:

 

@RestControllerclass App {  @RequestMapping("/")  String home() {    "hello"  }}

其中maven配置如下:

org.springframework.boot
spring-boot-starter-parent
1.3.5.RELEASE
org.springframework.boot
spring-boot-starter-web

我们以使用SpringMVC并且视图使用freemarker为例,分析springboot内部是如何解析freemarker视图的。

如果要在springboot中使用freemarker视图框架,并且使用maven构建项目的时候,还需要加入以下依赖:

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

这个spring-boot-starter-freemarker依赖对应的jar包里的文件如下:

META-INF├── MANIFEST.MF├── maven│   └── org.springframework.boot│       └── spring-boot-starter-freemarker│           ├── pom.properties│           └── pom.xml└── spring.provides

这个spring-boot-starter-parent的pom文件在 里。

它内部也有一个parent:

org.springframework.boot
spring-boot-dependencies
1.3.5.RELEASE
../../spring-boot-dependencies

这个spring-boot-dependencies的pom文件在

 

 

其中spring-boot-starter-web内部依赖了spring的两个spring web依赖:spring-web和spring-webmvc。

spring-boot-starter-web内部还依赖spring-boot-starter,这个spring-boot-starter依赖了spring核心依赖spring-core;还依赖了spring-bootspring-boot-autoconfigure这两个。

spring-boot定义了很多基础功能类,像运行程序的SpringApplication,Logging系统,一些tomcat或者jetty这些EmbeddedServlet容器,配置属性loader等等。

包括了这些包:

spring-boot-autoconfigure定义了很多自动配置的类,比如jpa,solr,redis,elasticsearch、mongo、freemarker、velocity,thymeleaf等等自动配置的类。

以freemarker为例,看一下它的自动化配置类:

@Configuration // 使用Configuration注解,自动构造一些内部定义的bean@ConditionalOnClass({ freemarker.template.Configuration.class,        FreeMarkerConfigurationFactory.class }) // 需要freemarker.template.Configuration和FreeMarkerConfigurationFactory这两个类存在在classpath中才会进行自动配置@AutoConfigureAfter(WebMvcAutoConfiguration.class) // 本次自动配置需要依赖WebMvcAutoConfiguration这个配置类配置之后触发。这个WebMvcAutoConfiguration内部会配置很多Wen基础性的东西,比如RequestMappingHandlerMapping、RequestMappingHandlerAdapter等@EnableConfigurationProperties(FreeMarkerProperties.class) // 使用FreeMarkerProperties类中的配置public class FreeMarkerAutoConfiguration {    private static final Log logger = LogFactory            .getLog(FreeMarkerAutoConfiguration.class);    @Autowired    private ApplicationContext applicationContext;    @Autowired    private FreeMarkerProperties properties;    @PostConstruct // 构造之后调用的方法,组要检查模板位置是否存在    public void checkTemplateLocationExists() {        if (this.properties.isCheckTemplateLocation()) {            TemplateLocation templatePathLocation = null;            List
locations = new ArrayList
(); for (String templateLoaderPath : this.properties.getTemplateLoaderPath()) { TemplateLocation location = new TemplateLocation(templateLoaderPath); locations.add(location); if (location.exists(this.applicationContext)) { templatePathLocation = location; break; } } if (templatePathLocation == null) { logger.warn("Cannot find template location(s): " + locations + " (please add some templates, " + "check your FreeMarker configuration, or set " + "spring.freemarker.checkTemplateLocation=false)"); } } } protected static class FreeMarkerConfiguration { @Autowired protected FreeMarkerProperties properties; 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); } } @Configuration @ConditionalOnNotWebApplication // 非Web项目的自动配置 public static class FreeMarkerNonWebConfiguration extends FreeMarkerConfiguration { @Bean @ConditionalOnMissingBean public FreeMarkerConfigurationFactoryBean freeMarkerConfiguration() { FreeMarkerConfigurationFactoryBean freeMarkerFactoryBean = new FreeMarkerConfigurationFactoryBean(); applyProperties(freeMarkerFactoryBean); return freeMarkerFactoryBean; } } @Configuration // 自动配置的类 @ConditionalOnClass(Servlet.class) // 需要运行在Servlet容器下 @ConditionalOnWebApplication // 需要在Web项目下 public static class FreeMarkerWebConfiguration extends FreeMarkerConfiguration { @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") // 没有配置freeMarkerViewResolver这个bean的话,会自动构造一个freeMarkerViewResolver @ConditionalOnProperty(name = "spring.freemarker.enabled", matchIfMissing = true) // 配置文件中开关开启的话,才会构造 public FreeMarkerViewResolver freeMarkerViewResolver() { // 构造了freemarker的ViewSolver,这就是一开始我们分析的为什么没有设置ViewResolver,但是最后却还是存在的原因 FreeMarkerViewResolver resolver = new FreeMarkerViewResolver(); this.properties.applyToViewResolver(resolver); return resolver; } }}

freemarker对应的配置类:

@ConfigurationProperties(prefix = "spring.freemarker") // 使用配置文件中以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"; // 默认后缀    ...}

下面是官网上的freemarker配置:

# FREEMARKER (FreeMarkerAutoConfiguration)spring.freemarker.allow-request-override=false # Set whether HttpServletRequest attributes are allowed to override (hide) controller generated model attributes of the same name.spring.freemarker.allow-session-override=false # Set whether HttpSession attributes are allowed to override (hide) controller generated model attributes of the same name.spring.freemarker.cache=false # Enable template caching.spring.freemarker.charset=UTF-8 # Template encoding.spring.freemarker.check-template-location=true # Check that the templates location exists.spring.freemarker.content-type=text/html # Content-Type value.spring.freemarker.enabled=true # Enable MVC view resolution for this technology.spring.freemarker.expose-request-attributes=false # Set whether all request attributes should be added to the model prior to merging with the template.spring.freemarker.expose-session-attributes=false # Set whether all HttpSession attributes should be added to the model prior to merging with the template.spring.freemarker.expose-spring-macro-helpers=true # Set whether to expose a RequestContext for use by Spring's macro library, under the name "springMacroRequestContext".spring.freemarker.prefer-file-system-access=true # Prefer file system access for template loading. File system access enables hot detection of template changes.spring.freemarker.prefix= # Prefix that gets prepended to view names when building a URL.spring.freemarker.request-context-attribute= # Name of the RequestContext attribute for all views.spring.freemarker.settings.*= # Well-known FreeMarker keys which will be passed to FreeMarker's Configuration.spring.freemarker.suffix= # Suffix that gets appended to view names when building a URL.spring.freemarker.template-loader-path=classpath:/templates/ # Comma-separated list of template paths.spring.freemarker.view-names= # White list of view names that can be resolved.

所以说一开始我们加入了一个spring-boot-starter-freemarker依赖,这个依赖中存在freemarker的lib,满足了FreeMarkerAutoConfiguration中的ConditionalOnClass里写的freemarker.template.Configuration.class这个类存在于classpath中。

所以就构造了FreeMarkerAutoConfiguration里的ViewResolver,这个ViewResolver被自动加入到SpringMVC中。

同样地,如果我们要使用velocity模板,springboot内部也有velocity的自动配置类VelocityAutoConfiguration,原理是跟freemarker一样的。

其他:

是Mybatis提供的springboot的自动配置模块,由于springboot官方没有提供mybatis的自动化配置模块,所以mybatis自己写了这么一个模块,观察它的源码,发现基本上跟freemarker的autoconfigure模块一样,只需要构造对应的实例即可。

总结:

springboot内部提供了很多自动化配置的类,这些类会判断classpath中是否存在自己需要的那个类,如果存在则会自动配置相关的配置,否则就不会自动配置。

如果我们需要使用一些框架,只需要加入依赖即可,这些依赖内部是没有代码的,只是一些对应框架需要的lib,有了这些lib就会触发自动化配置,于是就能使用框架了。

这一点跟当时看springmvc的时候对response进行json或xml渲染的原理相同。springmvc中的requestmapping注解加上responsebody注解后会返回xml或者json,如果依赖中加入jackson依赖就会转换成json,如果依赖中加入xstream依赖就会转换成xml。当然,前提是springmvc中有了这两种依赖的HttpMessageConverter代码,这个HttpMessageConverter代码就相当于springboot中的各种AutoConfiguration。

 

转载于:https://www.cnblogs.com/panxuejun/p/6705167.html

你可能感兴趣的文章
在.net core上使用Entity FramWork(Db first)
查看>>
UIImage 和 iOS 图片压缩UIImage / UIImageVIew
查看>>
MongoDB的数据库、集合的基本操作
查看>>
ajax向后台传递数组
查看>>
疯狂JAVA16课之对象与内存控制
查看>>
[转载]树、森林和二叉树的转换
查看>>
软件测试-----Graph Coverage作业
查看>>
django ORM创建数据库方法
查看>>
创建Oracle synonym 详解
查看>>
php7 新特性整理
查看>>
RabbitMQ、Redis、Memcache、SQLAlchemy
查看>>
linux查看端口占用
查看>>
Sql常见面试题 受用了
查看>>
知识不是来炫耀的,而是来分享的-----现在的人们却…似乎开始变味了…
查看>>
CSS背景颜色、背景图片、平铺、定位、固定
查看>>
口胡:[HNOI2011]数学作业
查看>>
我的第一个python web开发框架(29)——定制ORM(五)
查看>>
中国剩余定理
查看>>
基础笔记一
查看>>
uva 10137 The trip
查看>>