[关闭]
@coldxiangyu 2017-06-02T02:24:48.000000Z 字数 9643 阅读 762

Spring boot相关研究

WEB框架


前言

熟悉Spring完整生态的人应该都听说过spring boot,没有关心过它的也没关系,我们现在来认识一下它。
你需要记住一点,所有的架构方案都是在努力的简化开发人员的工作量的。从最开始spring的出现,service注入的方式走向我们,AOP概念的出现,都是为了简化开发,增加配置,减少代码。
这样的发展过程中,spring开始面临一个问题,就是过多的配置文件。
正如我在经代通的环境搭建中所作的一样,首先你要配置web.xml,配置spring的监听器,你要加入applicationContext.xml,在项目运行时加载spring的相关配置。最后你还要将项目打成war包放入tomcat或者jetty运行。
虽然这些算是一劳永逸的工作,但是,这对于开发人员是极不友好的。回想经代通的搭建过程,由于网络限制,没有复制粘贴的条件,xml文件配置都是一个字母一个字母打出来的,极其痛苦。
不过,随着Spring 3.0的发布,Spring IO团队逐渐开始摆脱XML配置文件,并且在开发过程中大量使用“约定优先配置”(convention over configuration)的思想来摆脱Spring框架中各类繁复纷杂的配置(即时是Java Config)。
Spring boot它本身并不提供Spring框架的核心特性以及扩展功能,只是用于快速、敏捷地开发新一代基于Spring框架的应用程序。也就是说,它并不是用来替代Spring的解决方案,而是和Spring框架紧密结合用于提升Spring开发者体验的工具。同时它集成了大量常用的第三方库配置(例如Jackson, JDBC, Mongo, Redis, Mail等等),Spring Boot应用中这些第三方库几乎可以零配置的开箱即用(out-of-the-box),大部分的Spring Boot应用都只需要非常少量的配置代码,开发者能够更加专注于业务逻辑。

Hello world!


接下来我们就来做一个“Hello world”的demo来看一看,spring boot到底有多简化。
以Maven项目为例,首先引入Spring Boot的开发依赖:

  1. <parent>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-parent</artifactId>
  4. <version>1.4.1.RELEASE</version>
  5. </parent>
  6. <dependencies>
  7. <dependency>
  8. <groupId>org.springframework.boot</groupId>
  9. <artifactId>spring-boot-starter-web</artifactId>
  10. </dependency>
  11. </dependencies>

编写一个类包含处理HTTP请求的方法以及一个main()函数:

  1. @Controller
  2. @EnableAutoConfiguration
  3. public class SampleController {
  4. @RequestMapping("/")
  5. @ResponseBody
  6. String home() {
  7. return "Hello World!";
  8. }
  9. public static void main(String[] args) throws Exception {
  10. SpringApplication.run(SampleController.class, args);
  11. }
  12. }

到这里,已经完事了。我们通过main函数中的SpringApplication.run(SampleController.class, args)就可以将整个springMVC运行起来,运行环境是一个内嵌的tomcat。
运行main函数,控制台输出如下:
image_1bhen0pcggue1r7tmubd3drgm9.png-106.5kB
我们可以看到,启动了一个tomcat。
我们通过浏览器访问一下http://localhost:8080/
image_1bhen5mh914ft1gn40cbmlofgm.png-13.9kB
真的,简单到我都想骂人。

spring boot 解析


我们在上面也说了,spring boot的本质就是一堆库的集合,可以被任意构建的项目所使用。

我们来回想一下我们都做了什么,便可以直接使用这些库了。
首先,在Maven依赖中引入了spring-boot-starter-web,它包含了Spring Boot预定义的一些Web开发的常用依赖:

我们没有一行配置代码、也没有web.xml。基于Spring Boot的应用在大多数情况下都不需要我们去显式地声明各类配置,而是将最常用的默认配置作为约定,在不声明的情况下也能适应大多数的开发场景。

数据库操作

上面介绍了最简单的hello world例子,在真正的项目中还是远远不够的,我们还要访问数据库,正如我们通常配置的jdbc的config文件,username、url、password之类,还有整合mybatis等持久化工具,druid、c3p0数据源之类的。
在spring boot中,这些依然通过maven引入依赖即可:

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-web-jdbc</artifactId>
  4. </dependency>
  5. <dependency>
  6. <groupId>com.h2database</groupId>
  7. <artifactId>h2</artifactId>
  8. </dependency>

spring-boot-starter-web-jdbc引入了spring-jdbc依赖,h2是一个内存关系型数据库。在引入了这些依赖并启动Spring Boot应用程序后,autoconfigure发现spring-jdbc位于类路径中,于是:

接下来开发者的工作就非常简单了,在业务逻辑中直接引入JdbcTemplate即可:

  1. @Service
  2. public class MyService {
  3. @Autowired
  4. JdbcTemplate jdbcTemplate;
  5. }

除了spring-jdbc,Spring Boot还能够支持JPA,以及各种NoSQL数据库——包括MongoDB,Redis,全文索引工具elasticsearch, solr等等。

配置


Spring Boot最大的特色是“约定优先配置”,大量的默认配置对开发者十分的友好。但是在实际的应用开发过程中,默认配置不可能满足所有场景,同时用户也需要配置一些必须的配置项——例如数据库连接信息。Spring Boot的配置系统能够让开发者快速的覆盖默认约定,同时支持Properties配置文件和YAML配置文件两种格式,默认情况下Spring Boot加载类路径上的application.propertiesapplication.yml文件,例如:

  1. spring.datasource.url=jdbc:mysql://localhost/test
  2. spring.datasource.username=dbuser
  3. spring.datasource.password=dbpass
  4. spring.datasource.driver-class-name=com.mysql.jdbc.Driver

YAML格式更加简洁:

  1. spring:
  2. datasource:
  3. url: jdbc:mysql://localhost/test
  4. username: dbuser
  5. password: dbpass
  6. driver-class: com.mysql.jdbc.Driver

一旦发现这些信息,Spring Boot就会根据它们创建DataSource对象。另一个常见的配置场景是Web应用服务器:

  1. # Server settings (ServerProperties)
  2. server:
  3. port: 8080
  4. address: 127.0.0.1
  5. sessionTimeout: 30
  6. contextPath: /
  7. # Tomcat specifics
  8. tomcat:
  9. accessLogEnabled: false
  10. protocolHeader: x-forwarded-proto
  11. remoteIpHeader: x-forwarded-for
  12. basedir:
  13. backgroundProcessorDelay: 30 # secs

通过portaddress可以修改服务器监听的地址和端口,sessionTimeout配置session过期时间(再也不用修改web.xml了,因为它根本不存在)。同时如果在生产环境中使用内嵌Tomcat,当然希望能够配置它的日志、线程池等信息,这些现在都可以通过Spring Boot的属性文件配置,而不再需要再对生产环境中的Tomcat实例进行单独的配置管理了。

@EnableAutoCongiguration


从Spring 3.0开始,为了替代繁琐的XML配置,引入了@Enable...注解对@Configuration类进行修饰以达到和XML配置相同的效果。想必不少开发者已经使用过类似注解:
@EnableTransactionManagement开启Spring事务管理,相当于XMl中的<tx:*>
@EnableWebMvc使用Spring MVC框架的一些默认配置
@EnableScheduling会初始化一个Scheduler用于执行定时任务和异步任务
Spring Boot提供的@EnableAutoCongiguration似乎功能更加强大,一旦加上,上述所有的配置似乎都被包含进来而无需开发者显式声明。它究竟是如何做到的呢,先看看它的定义:

  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Import({ EnableAutoConfigurationImportSelector.class,
  5. AutoConfigurationPackages.Registrar.class })
  6. public @interface EnableAutoConfiguration {
  7. /**
  8. * Exclude specific auto-configuration classes such that they will never be applied.
  9. */
  10. Class<?>[] exclude() default {};
  11. }

EnableAutoConfigurationImportSelector使用的是spring-core模块中的SpringFactoriesLoader#loadFactoryNames()方法,它的作用是在类路径上扫描META-INF/spring.factories文件中定义的类:

  1. # Initializers
  2. org.springframework.context.ApplicationContextInitializer=\
  3. org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer
  4. # Auto Configure
  5. org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  6. org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
  7. org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
  8. org.springframework.boot.autoconfigure.MessageSourceAutoConfiguration,\
  9. org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration,\
  10. org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
  11. org.springframework.boot.autoconfigure.data.JpaRepositoriesAutoConfiguration,\
  12. org.springframework.boot.autoconfigure.data.MongoRepositoriesAutoConfiguration,\
  13. org.springframework.boot.autoconfigure.redis.RedisAutoConfiguration,\
  14. org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
  15. org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
  16. org.springframework.boot.autoconfigure.jms.JmsTemplateAutoConfiguration,\
  17. org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,\
  18. org.springframework.boot.autoconfigure.mobile.DeviceResolverAutoConfiguration,\
  19. org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\
  20. org.springframework.boot.autoconfigure.mongo.MongoTemplateAutoConfiguration,\
  21. org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
  22. org.springframework.boot.autoconfigure.reactor.ReactorAutoConfiguration,\
  23. org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration,\
  24. org.springframework.boot.autoconfigure.security.FallbackWebSecurityAutoConfiguration,\
  25. org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\
  26. org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration,\
  27. org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration,\
  28. org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration,\
  29. org.springframework.boot.autoconfigure.web.MultipartAutoConfiguration,\
  30. org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration,\
  31. org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration,\
  32. org.springframework.boot.autoconfigure.websocket.WebSocketAutoConfiguration

实际上这就是Spring Boot会自动配置的一些对象,例如前面提到的Web框架由EmbeddedServletContainerAutoConfiguration, DispatcherServletAutoConfiguration, ServerPropertiesAutoConfiguration等配置完成,而DataSource的自动配置则是由DataSourceAutoConfiguration完成。现在我们以Mongo的配置MongoAutoConfiguration为例,来探索Spring Boot是如何完成这些配置的:

  1. @Configuration
  2. @ConditionalOnClass(Mongo.class)
  3. @EnableConfigurationProperties(MongoProperties.class)
  4. public class MongoAutoConfiguration {
  5. @Autowired
  6. private MongoProperties properties;
  7. private Mongo mongo;
  8. @PreDestroy
  9. public void close() throws UnknownHostException {
  10. if (this.mongo != null) {
  11. this.mongo.close();
  12. }
  13. }
  14. @Bean
  15. @ConditionalOnMissingBean
  16. public Mongo mongo() throws UnknownHostException {
  17. this.mongo = this.properties.createMongoClient();
  18. return this.mongo;
  19. }
  20. }

首先这是一个Spring的配置@Configuration,它定义了我们访问Mongo需要的@Bean,如果这个@Configuration被Spring Context扫描到,那么Context中自然也就有两个一个Mongo对象能够直接为开发者所用。
但是注意到其它几个Spring注解:

接下来看一看MongoProperties

  1. @ConfigurationProperties(prefix = "spring.data.mongodb")
  2. public class MongoProperties {
  3. private String host;
  4. private int port = DBPort.PORT;
  5. private String uri = "mongodb://localhost/test";
  6. private String database;
  7. // ... getters/ setters omitted
  8. }

显然,它就是以spring.data.mongodb作为前缀的属性,然后通过名字直接映射为对象的属性,同时还包含了一些默认值。如果不配置,那么mongo.uri就是mongodb://localhost/test

Production特性


从前面的例子可以看出,Spring Boot能够非常快速的做出一些原型应用,但是它同样可以被用于生产环境。为了添加生产环境特性支持,需要在Maven依赖中引入:

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-actuator</artifactId>
  4. </dependency>

加入actuator依赖后,应用启动后会创建一些基于Web的Endpoint:

总结

Spring Boot是新一代Spring应用的开发框架,它能够快速的进行应用开发,让人忘记传统的繁琐配置,更加专注于业务逻辑。现在Spring官方文档中所有的Guide中的例子都是使用Spring Boot进行构建,这也是一个学习Spring, Spring Boot非常好的地方。如果想进一步深度学习Spring Boot,可以参考:

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注