为什么使用Spring Boot

原文:https://dzone.com/articles/why-springboot
作者:Siva Prasad Reddy Katamreddy
译者:Oopsguy

本文将介绍各种 Spring 的配置方式,帮助你了解配置 Spring 应用的复杂性。

Spring 是一个非常受欢迎的 Java 框架,它用于构建 Web 和企业应用。不像许多其他框架只关注一个领域,Spring 框架提供了各种功能,通过项目组合来满足当代业务需求。

Spring 框架提供了多种灵活的方式来配置 Bean。例如 XML注解Java 配置。随着功能数量的增加,复杂性也随之增加,配置 Spring 应用将变得乏味且容易出错。

针对上述问题,Spring 团队创建了 Spring Boot 以解决配置复杂的问题。

但在开始将 Spring Boot 之前,我们将快速浏览一下 Spring 框架,看看 Spring Boot 正在决解什么样的问题。

在本文中,我们将介绍:

  • Spring 框架概述
  • 一个使用了 Spring MVC 和 JPA(Hibernate)的 Web 应用
  • 快速尝试 Spring Boot

Spring 框架概述

如果你是一名 Java 开发人员,那你很可能听说过 Spring 框架,甚至可能已经在自己的项目中使用了它。Spring 框架主要是作为依赖注入容器,但它的作用远不止这些。

Spring 很受欢迎的原因有几点:

  • Spring 的依赖注入方式鼓励编写可测试的代码
  • 具备简单但功能强大的数据库事务管理功能
  • Spring 简化了与其他 Java 框架的集成工作,比如 JPA/Hibernate ORM 和 Struts/JSF 等 Web 框架
  • 构建 Web 应用最先进的 Web MVC 框架。

连同 Spring 一起的,还有许多其他的 Spring 姊妹项目,可以帮助构建满足当代业务需求的应用:

  • Spring Data:简化关系数据库和 NoSQL 数据存储的数据访问
  • Spring Batch:提供强大的批处理能力
  • Spring Security:用于保护应用的安全框架
  • Spring Social:支持与 Facebook、Twitter、Linkedin、Github 等社交网站集成
  • Spring Integration:实现了企业集成模式,以便于使用轻量级消息和声明式适配器与其他企业应用集成

还有许多其他有趣的项目涉及各种其他当代应用开发需求。有关更多信息,请查看 http://spring.io/projects

刚开始,Spring 框架只提供了基于 XML 的方式来配置 bean。后来,Spring 引入了基于 XML 的 DSL、注解和基于 Java 配置的方式来配置 bean。

让我们快速了解一下这些配置风格的大概模样。

基于 XML 的配置

1
2
3
4
5
6
7
8
9
10
11
12
<bean id="userService" class="com.sivalabs.myapp.service.UserService">
<property name="userDao" ref="userDao"/>
</bean>
<bean id="userDao" class="com.sivalabs.myapp.dao.JdbcUserDao">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/test"/>
<property name="username" value="root"/>
<property name="password" value="secret"/>
</bean>

基于注解的配置

1
2
3
4
5
6
7
8
9
10
11
@Service
public class UserService
{
private UserDao userDao;
@Autowired
public UserService(UserDao dao){
this.userDao = dao;
}
...
...
}
1
2
3
4
5
6
7
8
9
10
11
@Repository
public class JdbcUserDao
{
private DataSource dataSource;
@Autowired
public JdbcUserDao(DataSource dataSource){
this.dataSource = dataSource;
}
...
...
}

基于 Java 代码的配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Configuration
public class AppConfig
{
@Bean
public UserService userService(UserDao dao){
return new UserService(dao);
}
@Bean
public UserDao userDao(DataSource dataSource){
return new JdbcUserDao(dataSource);
}
@Bean
public DataSource dataSource(){
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/test");
dataSource.setUsername("root");
dataSource.setPassword("secret");
return dataSource;
}
}

Spring 提供了多种方式来做同样的事,我们甚至可以混合使用,在同一个应用中使用基于 Java 配置和注解配置的方式。

这非常灵活,但它有好有坏。刚开始接触 Spring 的新人可能会困惑应该使用哪一种方式。到目前为止,Spring 团队建议使用基于 Java 配置的方式,因为它更具灵活性。

没有哪一种方案是万能,我们应该根据自己的需求来选择合适的方式。

到此,你已经了解了多种 Spring Bean 配置方式的基本形式。

让我们快速地了解一下典型的 Spring MVC+JPA/Hibernate Web 应用的配置。

一个使用了 Spring MVC 和 JPA(Hibernate)的 Web 应用

在了解 Spring Boot 是什么以及它提供了什么样的功能之前,我们先来看一下典型的 Spring Web 应用配置是怎样的,哪些是痛点,然后我们将讨论 Spring Boot 是如何解决这些问题的。

步骤 1、配置 Maven 依赖

首先需要做的是配置 pom.xml 中所需的依赖:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
<?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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.sivalabs</groupId>
<artifactId>springmvc-jpa-demo</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>springmvc-jpa-demo</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<failOnMissingWebXml>false</failOnMissingWebXml>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.9.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.13</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.13</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.13</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.190</version>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>4.3.11.Final</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring4</artifactId>
<version>2.1.4.RELEASE</version>
</dependency>
</dependencies>
</project>

我们配置了所有的 Maven jar 依赖,包括 Spring MVC、Spring Data JPA、JPA/Hibernate、Thymeleaf 和 Log4j。

步骤 2、使用 Java 配置配置 Service/DAO 层的 Bean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages="com.sivalabs.demo")
@PropertySource(value = { "classpath:application.properties" })
public class AppConfig
{
@Autowired
private Environment env;
@Bean
public static PropertySourcesPlaceholderConfigurer placeHolderConfigurer()
{
return new PropertySourcesPlaceholderConfigurer();
}
@Value("${init-db:false}")
private String initDatabase;
@Bean
public PlatformTransactionManager transactionManager()
{
EntityManagerFactory factory = entityManagerFactory().getObject();
return new JpaTransactionManager(factory);
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory()
{
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(Boolean.TRUE);
vendorAdapter.setShowSql(Boolean.TRUE);
factory.setDataSource(dataSource());
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan("com.sivalabs.demo");
Properties jpaProperties = new Properties();
jpaProperties.put("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
factory.setJpaProperties(jpaProperties);
factory.afterPropertiesSet();
factory.setLoadTimeWeaver(new InstrumentationLoadTimeWeaver());
return factory;
}
@Bean
public HibernateExceptionTranslator hibernateExceptionTranslator()
{
return new HibernateExceptionTranslator();
}
@Bean
public DataSource dataSource()
{
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(env.getProperty("jdbc.driverClassName"));
dataSource.setUrl(env.getProperty("jdbc.url"));
dataSource.setUsername(env.getProperty("jdbc.username"));
dataSource.setPassword(env.getProperty("jdbc.password"));
return dataSource;
}
@Bean
public DataSourceInitializer dataSourceInitializer(DataSource dataSource)
{
DataSourceInitializer dataSourceInitializer = new DataSourceInitializer();
dataSourceInitializer.setDataSource(dataSource);
ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator();
databasePopulator.addScript(new ClassPathResource("data.sql"));
dataSourceInitializer.setDatabasePopulator(databasePopulator);
dataSourceInitializer.setEnabled(Boolean.parseBoolean(initDatabase));
return dataSourceInitializer;
}
}

AppConfig.java 配置类中,我们完成了以下操作:

  • 使用 @Configuration 注解标记为一个 Spring 配置类
  • 使用 @EnableTransactionManagement 开启基于注解的事务管理
  • 配置 @EnableJpaRepositories 指定去哪查找 Spring Data JPA 资源库(repository)
  • 使用 @PropertySource 注解和 PropertySourcesPlaceholderConfigurer Bean 定义配置 PropertyPlaceHolder bean 从 application.properties 文件加载配置
  • DataSource、JAP 的 EntityManagerFactoryJpaTransactionManager 定义 Bean
  • 配置 DataSourceInitializer Bean,在应用启动时,执行 data.sql 脚本来初始化数据库

我们需要在 application.properties 中完善配置,如下所示:

1
2
3
4
5
6
7
8
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test
jdbc.username=root
jdbc.password=admin
init-db=true
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.show_sql=true
hibernate.hbm2ddl.auto=update

我们可以创建一个简单的 SQL 脚本 data.sql 来将演示数据填充到 USER 表中:

1
2
3
4
delete from user;
insert into user(id, name) values(1,'Siva');
insert into user(id, name) values(2,'Prasad');
insert into user(id, name) values(3,'Reddy');

我们可以创建一个附带基本配置的 log4j.properties 文件,如下所示:

1
2
3
4
5
6
log4j.rootCategory=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p %t %c{2}:%L - %m%n
log4j.category.org.springframework=INFO
log4j.category.com.sivalabs=DEBUG

步骤 3、配置 Spring MVC Web 层的 Bean

我们必须配置 Thymleaf 的 ViewResolver、处理静态资源的 ResourceHandler 和处理 I18n 的 MessageSource 等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
@Configuration
@ComponentScan(basePackages = { "com.sivalabs.demo"})
@EnableWebMvc
public class WebMvcConfig extends WebMvcConfigurerAdapter
{
@Bean
public TemplateResolver templateResolver() {
TemplateResolver templateResolver = new ServletContextTemplateResolver();
templateResolver.setPrefix("/WEB-INF/views/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode("HTML5");
templateResolver.setCacheable(false);
return templateResolver;
}
@Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver());
return templateEngine;
}
@Bean
public ThymeleafViewResolver viewResolver() {
ThymeleafViewResolver thymeleafViewResolver = new ThymeleafViewResolver();
thymeleafViewResolver.setTemplateEngine(templateEngine());
thymeleafViewResolver.setCharacterEncoding("UTF-8");
return thymeleafViewResolver;
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry)
{
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer)
{
configurer.enable();
}
@Bean(name = "messageSource")
public MessageSource configureMessageSource()
{
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasename("classpath:messages");
messageSource.setCacheSeconds(5);
messageSource.setDefaultEncoding("UTF-8");
return messageSource;
}
}

WebMvcConfig.java 配置类中,我们完成了以下操作:

  • 使用 @Configuration 注解标记为一个 Spring 配置类
  • 使用 @EnableWebMvc 注解启用基于注解的 Spring MVC 配置
  • 通过注册 TemplateResolverSpringTemplateEngine 和 `hymeleafViewResolver Bean 来配置 Thymeleaf 视图解析器
  • 注册 ResourceHandler Bean 将 URI 为 /resource/** 的静态资源请求定位到 /resource/ 目录下
  • 配置 MessageSource Bean 从 classpath 中加载 messages-{国家代码}.properties 文件来加载 I18n 配置

现在我们没有配置任何 I18n 内容,因此需要在 src/main/resources 文件夹下创建一个空的 messages.properties 文件。

步骤 4、注册 Spring MVC 的前端控制器 DispatcherServlet

在 Servlet 3.x 规范之前,我们必须在 web.xml 中注册 Servlet/Filter。由于当前是 Servlet 3.x 环境,我们可以使用 ServletContainerInitializer 以编程的方式注册 Servlet/Filter。

Spring MVC 提供了一个惯例类 AbstractAnnotationConfigDispatcherServletInitializer 来注册 DispatcherServlet

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class SpringWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer
{
@Override
protected Class<?>[] getRootConfigClasses()
{
return new Class<?>[] { AppConfig.class};
}
@Override
protected Class<?>[] getServletConfigClasses()
{
return new Class<?>[] { WebMvcConfig.class };
}
@Override
protected String[] getServletMappings()
{
return new String[] { "/" };
}
@Override
protected Filter[] getServletFilters() {
return new Filter[]{ new OpenEntityManagerInViewFilter() };
}
}

SpringWebAppInitializer.java 配置类中,我们完成了以下操作:

  • 我们将 AppConfig.class 配置为 RootConfigurationClass,它将成为包含所有子上下文(DispatcherServlet)共享的 Bean 定义的父 ApplicationContext
  • 我们将 WebMvcConfig.class 配置为 ServletConfigClass,它是包含了 WebMvc Bean 定义的子 ApplicationContext
  • 我们将 / 配置为 ServletMapping,这意味所有的请求将由 DispatcherServlet 处理
  • 我们将 OpenEntityManagerInViewFilter 注册为 Servlet 过滤器,以便在渲染视图时可以延迟加载 JPA Entity 的延迟集合

步骤 5、创建一个 JPA 实体和 Spring Data JPA 资源库

为 User 实体创建一个 JPA 实体 User.java 和一个 Spring Data JPA 资源库。

1
2
3
4
5
6
7
8
@Entity
public class User
{
@Id @GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
private String name;
//setters and getters
}
1
2
3
public interface UserRepository extends JpaRepository<User, Integer>
{
}

步骤 6、创建一个 Spring MVC 控制器

创建一个 Spring MVC 控制器来处理 URL 为 /,并渲染一个用户列表。

1
2
3
4
5
6
7
8
9
10
11
@Controller
public class HomeController
{
@Autowired UserRepository userRepo;
@RequestMapping("/")
public String home(Model model)
{
model.addAttribute("users", userRepo.findAll());
return "index";
}
}

步骤 7、创建一个 Thymeleaf 视图 /WEB-INF/views/index.html 来渲染用户列表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8"/>
<title>Home</title>
</head>
<body>
<table>
<thead>
<tr>
<th>Id</th>
<th>Name</th>
</tr>
</thead>
<tbody>
<tr th:each="user : ${users}">
<td th:text="${user.id}">Id</td>
<td th:text="${user.name}">Name</td>
</tr>
</tbody>
</table>
</body>
</html>

所有都配置好了,可以启动应用了。但在此之前,我们需要在 IDE 中下载并配置像 TomcatJetty 或者 Wildfly 等服务器。

你可以下载 Tomcat 8 并配置在你喜欢的 IDE 中,之后运行应用并将浏览器指向 http://localhost:8080/springmvc-jpa-demo。你应该看到一个以表格形式展示的用户详细信息列表。

真激动,我们做到了!

但是等等,做了那么多的工作仅仅是为了从数据库中获取用户信息然后展示一个列表?

让我们坦诚公平地来看待,所有的这些配置不仅仅是为了这次示例,这些配置也是其他应用的基础。

但我还是想说,如果你想早点起床跑步,那对不起,你还有太多的工作要做。

另一个问题是,假设你想要开发另一个 Spring MVC 应用,你会使用类似的技术栈?

好,你要做的就是复制粘贴配置并调整它。对么?请记住一件事:如果你一次又一次地做同样的事情,你应该寻找一种自动化的方式来完成它。

除了一遍又一遍地编写相同的配置,你还能发现其他问题么?

这样吧,让我列出我从中发现的问题。

  • 你需要寻找特定版本的 Spring 以便完全兼容所有的类库,并进行配置。
  • 我们花费了 95% 的时间以同样的方式配置 DataSourceEntityManagerFactoryTransactionManager 等 bean。如果 Spring 能自动帮我们完成这些事,是不是非常棒?
  • 同样,我们大多时候以同样的方式配置 Spring MVC 的 bean,比如 ViewResolverMessageResource 等。

如果 Spring 可以自动帮我做这些事情,那真的是非!常!棒!

想象一下,如果 Spring 能够自动配置 bean 呢?如果你可以使用简单的自定义配置方式来定义自动配置又将会怎么?

例如,你可以将 DispatcherServlet 的 url-pattern 映射到 /app/,而不是 /。你可以将 Theymeleaf 视图放在 /WEB-INF/template/ 文件夹下,而不是 /WEB-INF/views 中。

所以基本上你希望 Spring 能自动执行这些操作,Spring 它有没有提供一个简单灵活的方式来覆盖掉默认配置呢?

很好,你即将踏进入 Spring Boot 的世界,你将梦想成真!

快速尝试 Spring Boot

欢迎来到 Spring Boot 世界!Spring Boot 正是你一直在寻找的。它可以自动为你完成某些事情,但如果有必要,你可以覆盖掉这些默认配置。

与其夸夸而谈,不如来点案例实战。

步骤 1、创建一个基于 Maven 的 Spring Boot 应用

创建一个 Maven 项目并配置如下依赖:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<?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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.sivalabs</groupId>
<artifactId>hello-springboot</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>hello-springboot</name>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.2.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
</project>

太神奇了,我们的 pom.xml 文件一下子变小了许多!

步骤 2、如下在 application.properties 中配置 DataSoure/JPA

1
2
3
4
5
6
7
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=admin
spring.datasource.initialize=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true

你可以将相同的 data.sql 文件拷贝到 src/main/resources 文件加中。

步骤 3、为实体创建一个 JPA 实体和 Spring Data JPA 资源库接口

springmvc-jpa-demo 应用一样,创建 User.javaUserRepository.javaHomeController.java

步骤 4、创建用于显示用户列表的 Thymeleaf 视图

springmvc-jpa-demo 项目中复制之前创建的 /WEB-INF/views/index.htmlsrc/main/resources/template 文件夹中。

步骤 5、创建 Spring Boot 入口类

创建一个含有 main 方法的 Java 类 Application.java,如下所示:

1
2
3
4
5
6
7
8
@SpringBootApplication
public class Application
{
public static void main(String[] args)
{
SpringApplication.run(Application.class, args);
}
}

现在把 Application.java 当作一个 Java 应用运行,并将你的浏览其指向 http://localhost:8080/

不出意外,你将看到一个以表格的形式展示的用户列表,真的很酷!

我仿佛听到你在喊:“这到底发生了什么事?”。

让我解释刚刚所发生的事情。

  1. 简单的依赖管理

    • 首先要注意的是我们使用了一些名为 spring-boot-start-* 的依赖。记住我说过我花费 95% 的时间来配置同样的配置。当你在开发 Spring MVC 应用时添加了 spring-boot-start-web 依赖,它已经包含了一些常用的类库,比如 spring-webmvcjackson-jsonvalidation-apitomcat 等。

    • 我们添加了 spring-boot-starter-data-jpa 依赖。它包含了所有的 spring-data-jpa 依赖,并且还添加了 Hibernate 库,因为很多应用使用 Hibernate 作为 JPA 实现。

  2. 自动配置

    • spring-boot-starter-web 不仅添加了上面所说的这些库,还配置了经常被注册的 bean,比如 DispatcherServletResourceHandlerMessageSource 等 bean,并且应用了合适的默认配置。

    • 我们还添加了 spring-boot-starter-Thymeleaf,它不仅添加了 Thymeleaf 的依赖,还自动配置了 ThymeleafViewResolver bean。

    • 虽然我们没有定义任何 DataSourceEntityManagerFactoryTransactionManager 等 bean,但它们可以被自动创建。怎么样?如果在 classpath 下没有任何内存数据库驱动,如 H2 或者 HSQL,那么 Spring Boot 将自动创建一个内存数据库的 DataSource,然后应用合适的默认配置自动注册 EntityManagerFactoryTransactionManager 等 bean。但是我们使用的是 MySQL,因此我们需要明确提供 MySQL 的连接信息。我们已经在 application.properties 文件中配置了 MySQL 连接信息,Spring Boot 将应用这些配置来创建 DataSource

  3. 支持嵌入式 Servlet 容器

    • 最重要且最让人惊讶的是,我们创建了一个简单的 Java 类,标记了一个神奇的注解 @SpringApplication,它有一个 main 方法。通过运行 main 方法,我们可以启动这个应用,并可通过 http://localhost:8080/ 来访问。

Servlet 容器来自哪里?

我们添加了 spring-boot-starter-web,它会自动引入 spring-boot-starter-tomcat。当我们运行 main() 方法时,它将 tomcat 作为一个嵌入式容器启动,我们不需要部署自己的应用到外部安装好的 tomcat 上。

顺便说一句,你看到我们在 pom.xml 中配置的打包类型是 jar 而不是 war,真有趣!

非常好,但如果我想使用 jetty 服务器而不是 tomcat 呢?很简单,只需要从 spring-boot-starter-web 中排除掉 sprig-boot-starter-tomcat,并包含 spring-boot-starter-jetty 依赖即可。

就是这样。

但这看起来真的很神奇!

我可以想象此时你在想什么。你正在感叹 Spring Boot 真的很酷,它为你自动完成了很多事情。但是,你还没了完全明白它幕后是怎样工作的,对不对?

我可以理解,就像观看魔术表演,过程非常有趣,但你不知道魔术师是如何做到的。软件开发则不一样,你不用担心,未来我们还将看到各种新奇的东西,并在以后的文章中详细地解释它们幕后的工作原理。很遗憾的是,我不能在这篇文章中把所有的东西都教给你。

总结

在本文中,我们快速介绍了 Spring 的各种配置风格,并了解了配置 Spring 应用的复杂性。此外,我们通过创建一个简单的 Web 应用来快速了解 Spring Boot。

在下一篇文章中,我们将深入了解 Spring Boot,了解它的工作原理。