我们先来看看以前我们是怎么写Spring的
以前的Spring
整合复杂
相信大家学SSM(Spring+Spring MVC+MyBatis)结构的时候, 最痛苦的莫过于整合了..
既然要整合三者, 那么需要做哪些配置呢?
- 选择各种依赖的版本,spring核心的lib: spring-core, spring-context, spring-beans, spring-context-support, spring-aop. spring mvc相关的lib: spring-web,spring-webmvc; 数据库相关的模块: mysql-connector-java, mybatis, mybatis-spring. log相关模块slf4j-api, slf4j-log4j12. json处理模块jackson, 数据库连接池commons-dbcp..等..(要自己选版本, 注意兼容性问题)
- 配置spring的xml: 配置自动扫描, 配置datasource, 配置spring和mybatis的整合的SqlSessionFactoryBean, 配置mybatis扫描的MapperScannerConfigurer. 配置事务管理器.
- 配置spring mvc的xml: 配置annotation-driven, 配置自动扫描Controller(有遇到过因为两个容器重复扫描导致事务注解失效的问题吗?), 配置InternalResourceViewResolver.
- 因为跑在tomcat里面, 所以需要配置web.xml, 来启动spring, 且需要配置DispatchServlet, 将所有的请求转发给spring mvc.
大概经过一天的配置, 终于可以开始写代码了…
你看, 我也弄过..
https://github.com/Frank-Hust/SSMTemplate
试错成本高
如果这作为主工程倒还好, 配一次以后就不需要弄了.
但是这对于想要学习Spring的特性的人(比如Spring MVC的参数映射, Spring的事务机制, Spring Data等), 以及想尝试Spring, 或者想快速开发新服务的人(比如微服务), 都非常的不友好. 从有想法去要做, 到真正开始做我想做的事, 好几个小时就过去了, 试错成本太大, 完全没有心思去尝试了.
配置复杂, 历史版本多
更痛苦的是对于初学程序员甚至一些有经验的程序员, Spring从03年开始到17年, 10多年的发展历程, xml, 注解, java config好几种风格的配置纠缠一起, 分不清哪些配置是推荐的, 哪些配置是有用的, 哪些配置是不被推荐了的, 哪些配置是废弃了的, 哪些配置间是冲突的 …
默认配置
用久了Spring, 你会发现, 很多东西都其实应该有默认配置的.
- 一般我们都要去指定spring和spring mvc的配置文件地址…为什么不直接告诉我们, 用的是application.properties就好了..不想用这个的话, 那就自己再去改吧.
- 比如用了Spring 3.X以后的版本, 基本都会开启注解扫描, 既然大家都开启, 那么默认开启就好了. 为什么还要自己去要搜索, 如何开启注解, 网络上各种乱七八糟的配置.
- 比如我用了mysql, 不管是JPA, MyBatis还是JdbcTemplate, 基本都会配置对应的事务管理器..既然这样, 为什么框架不自动帮我配置对应的事务管理器.
- 比如我用了Spring MVC, 一般我都不在意资源文件位置如何, 直接给我生成一个默认的文件夹, 我把资源文件放进去就好了. 省得我自己去设置一个mvc:resources标签.
等等..
也就是说, 你会发现你做的那些整合配置, 几乎在所有的新项目中, 都不需要改动, 既然这些配置都可以默认, 那么为什么还需要我们去写!!!
Spring Boot !!!
https://start.spring.io/, 选择web, 然后再用ide打开这个工程.
或者像下面一样, 自己新建一个maven工程, 然后添加以下依赖到pom.xml中.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.haoyifen</groupId>
<artifactId>actuator</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>actuator</name>
<description>Demo project for Spring Boot Actuator</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
写一个java文件, hello/SampleController.java
package hello;
import org.springframework.boot.*;
import org.springframework.boot.autoconfigure.*;
import org.springframework.stereotype.*;
import org.springframework.web.bind.annotation.*;
@Controller
@SpringBootApplication
public class SampleController {
@RequestMapping("/")
@ResponseBody
String home() {
return "Hello World!";
}
public static void main(String[] args) throws Exception {
SpringApplication.run(SampleController.class, args);
}
}
直接运行这个类的main方法…在浏览器中访问http://localhost:8080, 就可以看到激动人心的Hello World了!
一个基于Spring MVC的web应用demo就完成了.
不需要自己选择各种依赖版本, 不需要配置DispatchServlet, .不需要tomcat, 不需要部署到tomcat..只需要简单的代码, 直接运行main方法就好了.
Spring Boot如何解决这几个问题
前面我们提到的以前写Spring时, 有几个比较烦的问题.
1. 依赖太多了, 且存在版本问题
2. 配置太多了且每次都一样, 大部分工程, 配置每次都是一样的, 从一个地方拷贝到另外一个地方. 且Spring发展10多年, 各种配置版本太多, 对于很多程序员来说, 分不清哪个是有效, 哪个无效.
3. 部署太麻烦. 需要tomcat部署, 项目结构也需要照着java ee的目录结构来写.
魔法
dependencyManagement:
我们可以看到上面的pom.xml文件中. 指定了我们的模块父project是spring-boot-starter-parent.
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
我们可以看到上面的pom.xml依赖类型是spring-boot-starter-*, 以spring-boot-starter-web为例. 不需要指定version, 通过父工程的dependencyManagement来获得其版本为1.5.3. spring-boot-starter-web本身的pom.xml文件中有引用到以下的lib, 且paretn也为1.5.3版本, 然后通过maven的依赖传递, spring-boot-starter-web会为该工程引入1.5.3版本的spring-boot-starters对应的spring-boot和spring mvc模块.
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starters</artifactId>
<version>1.5.3.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
</dependencies>
这样就完成了依赖的管理.
EnableAutoConfiguration
前面SampleController类上有SpringBootApplication注解, 这个注解上面又有EnableAutoConfiguration注解. 自动配置默认的配置就是由这个注解生效的. 你如果添加了spring-boot-starter-web依赖, 那么就给你配置一堆和Spring MVC相关的默认配置, 如果你添加了spring-boot-starter-jdbc,那么就给你自动配置jdbcTemplate和事务管理器. 如果你添加了spring-boot-starter-mongodb, 那么就给你自动配置mongodbTemplate等等..
大概原理举例说明:
比如我们添加了spring-boot-starter-jdbc依赖, 那么类路径下就会有JdbcTemplate这个类.
Spring Boot自动配置检测classpath有jdbcTemplate这个类, 且beanFactory中没有JdbcTemplate的bean, 也就是说没有手动配置, 就从BeanFactory中取出我们配置的datasource, 然后自动配置一个JdbcTemplate. 然后对于事务管理器也是相应的逻辑. 配置一个事务管理器的bean.
相关代码可见JdbcTemplateAutoConfiguration和DataSourceTransactionManagerAutoConfiguration.
Spring Boot通过自动配置的魔法, 大大减少了Spring的配置.
嵌入式tomcat和Spring Boot自定义的FatJar
之前的Spring Web应用都是根据java ee的项目结构来写, 打包成War格式, 然后部署到tomcat中, 十分的麻烦.
Spring Boot可以使用内嵌的Tomcat, 由我们的main方法来启动Spring, 接着启动Tomcat, 而不是由Tomcat来启动Spring.
EmbeddedServletContainerAutoConfiguration会进行Tomcat的配置, 由TomcatEmbeddedServletContainer进行启动.
在本地开发时, 直接和普通java程序一样, 使用main方法启动.
Spring Boot应用可以直接由maven的plugin打包成其定义的FatJar内容的jar包, 在部署时, 直接使用java -jar application.jar进行启动, 部署十分方便.
总结
Spring是一个无所不包的一站式java开发平台. 但由于10多年的发展, Spring的体系太过庞大, 程序员无法掌握其历史, 同时复杂的依赖, 大量的配置, 复杂的部署给开发带来了很大的阻碍.
Spring Boot基于约定大于配置的理念, 简化了依赖管理, 简化了配置, 简化了部署. 大大降低了使用Spring开发的难度, 大大加快了开发速度. 我认为必将是Java后台开发下一个5年的杀手级框架.