编程

Spring 与 Spring Boot 之比较

303 2024-10-20 11:36:00

1. 概述

在本教程中,我们将研究标准 Spring 框架和 Spring Boot 之间的差异。

我们将重点讨论 Spring 的模块,如 MVC 和 Security,在核心 Spring 中使用时与在 Boot 中使用时有何不同。

2. Spring 是什么?

简而言之,Spring 框架为开发 Java 应用提供了全面的基础设施支持。

它包含了一些不错的功能,如依赖注入,以及开箱即用的模块,如:

  • Spring JDBC
  • Spring MVC
  • Spring Security
  • Spring AOP
  • Spring ORM
  • Spring Test

这些模块可以大大缩短应用的开发时间。

例如,在 Java web 开发的早期,我们需要编写大量样板代码将记录插入数据源。通过使用 Spring JDBC 模块的 JDBCTemplate,我们可以将其简化为几行代码,只需要几个配置。

3. Spring Boot 是什么?

Spring Boot 基本上是 Spring 框架的一个扩展,它消除了设置 Spring 应用所需的样板配置。

是 Spring 平台坚定的拥护者,为更快、更高效的开发生态系统铺平了道路。

以下是 Spring Boot 中的一些特性:

  • 优化“启动器(starter)”依赖关系,以简化编译和应用配置
  • 嵌入式服务,避免应用部署的复杂性
  • 指标化、健康检查和外部化配置
  • Spring 功能的自动配置——只要可能

让我们来一步步熟悉这两个框架。

4. Maven 依赖

首先,让我们看看使用 Spring 创建 web 应用所需的最小依赖关系:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>5.3.5</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.3.5</version>
</dependency>

与 Spring 不同,Spring Boot 只需要一个依赖项即可启动并运行 web 应用:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>2.4.4</version>
</dependency>

在构建期间,所有其他依赖项都会自动添加到最终存档中。

另一个很好的例子是测试库。我们通常使用 Spring Test、JUnit、Hamcrest 和 Mockito 库。在 Spring 项目中,我们应该将所有这些库作为依赖项添加。

而在 Spring Boot 中,我们只需要用于测试的 starter 依赖项就能自动包含这些库。

Spring Boot 为不同的 Spring 模块提供了许多启动器依赖关系。一些最常用的是:

  • spring-boot-starter-data-jpa
  • spring-boot-starter-security
  • spring-boot-starter-test
  • spring-boot-starter-web
  • spring-boot-starter-thymeleaf

starter 的全列表可参考 Spring 文档

5. MVC 配置

让我们探讨一下使用 Spring 和 Spring Boot 创建 JSP web 应用所需的配置。

Spring 需要定义调度器 servlet、映射和其他支持配置。我们可以使用 web.xml 文件或 Initializer 类来实现这一点:

public class MyWebAppInitializer implements WebApplicationInitializer {
 
    @Override
    public void onStartup(ServletContext container) {
        AnnotationConfigWebApplicationContext context
          = new AnnotationConfigWebApplicationContext();
        context.setConfigLocation("com.baeldung");
 
        container.addListener(new ContextLoaderListener(context));
 
        ServletRegistration.Dynamic dispatcher = container
          .addServlet("dispatcher", new DispatcherServlet(context));
         
        dispatcher.setLoadOnStartup(1);
        dispatcher.addMapping("/");
    }
}

同时我们需要将 @EnableWebMvc 注释添加到 @Configuration 类,并定义一个视图解析器来解析从控制器返回的视图:

@EnableWebMvc
@Configuration
public class ClientWebConfig implements WebMvcConfigurer { 
   @Bean
   public ViewResolver viewResolver() {
      InternalResourceViewResolver bean
        = new InternalResourceViewResolver();
      bean.setViewClass(JstlView.class);
      bean.setPrefix("/WEB-INF/view/");
      bean.setSuffix(".jsp");
      return bean;
   }
}

相比之下,一旦我们添加了 web starter,Spring Boot 只需要几个属性就可以正常工作

spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp

通过一个称为自动配置的过程添加 Boot web starter,上述所有 Spring 配置都会自动包含在内。

这意味着 Spring Boot 将查看应用中存在的依赖关系、属性和 bean,并基于这些进行配置。

当然,如果我们想添加自己的自定义配置,那么 Spring Boot 自动配置将退出。

5.1. 配置模板引擎

现在,让我们学习如何在 Spring 和 Spring Boot 中配置 Thymeleaf 模板引擎。

在 Spring 中,我们需要添加 thymeleaf-spring5 依赖项和一些用于视图解析器的配置:

@Configuration
@EnableWebMvc
public class MvcWebConfig implements WebMvcConfigurer {

    @Autowired
    private ApplicationContext applicationContext;

    @Bean
    public SpringResourceTemplateResolver templateResolver() {
        SpringResourceTemplateResolver templateResolver = 
          new SpringResourceTemplateResolver();
        templateResolver.setApplicationContext(applicationContext);
        templateResolver.setPrefix("/WEB-INF/views/");
        templateResolver.setSuffix(".html");
        return templateResolver;
    }

    @Bean
    public SpringTemplateEngine templateEngine() {
        SpringTemplateEngine templateEngine = new SpringTemplateEngine();
        templateEngine.setTemplateResolver(templateResolver());
        templateEngine.setEnableSpringELCompiler(true);
        return templateEngine;
    }

    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        ThymeleafViewResolver resolver = new ThymeleafViewResolver();
        resolver.setTemplateEngine(templateEngine());
        registry.viewResolver(resolver);
    }
}

Spring Boot 1 只需要 spring-boot-starter-thymeleaf 依赖项,就可以在 web 应用中启用 Thymeleaf 支持。由于 Thymeleaf3.0 中的新功能,我们还必须在 Spring Boot 2 web 应用中添加 thymeleaf-layout-dialect 作为依赖项。或者,我们可以选择添加一个 spring-boot-starter-thymeleaf 依赖项,为我们解决所有这些问题。

一旦依赖关系就绪,我们可以将模板添加到 src/main/resources/templates 文件夹中,Spring Boot 将自动显示。

6. Spring Security 配置

为简单起见,我们将看到如何使用这些框架启用默认的 HTTP 基本身份验证。

让我们从使用 Spring 启用 Security 所需的依赖项和配置开始。

Spring 需要标准的 spring-security-web spring-security-config 来在应用中设置 Security。

接下来,我们需要添加一个类来创建 SecurityFilterChain bean,并使用 @EnableWebSecurity 注释:

@Configuration
@EnableWebSecurity
public class CustomWebSecurityConfigurerAdapter {
 
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
          .withUser("user1")
            .password(passwordEncoder()
            .encode("user1Pass"))
          .authorities("ROLE_USER");
    }
 
    @Bean
     public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.authorizeRequests()
          .anyRequest().authenticated()
          .and()
          .httpBasic();
        return http.build();
    }
    
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

这里我们使用 inMemoryAuthentication 来设置身份验证。

Spring Boot 也需要这些依赖项才能正常工作,但我们只需定义 spring-boot-starter-security 依赖项,因为这将自动将所有相关依赖项添加到类路径中。

Spring Boot 中的安全配置与上面的相同。

7. 应用引导

在 Spring 和 Spring Boot 中引导应用的基本区别在于 servlet。Spring 使用 web.xmlSpringServletContainerInitializer 作为其引导入口点。

而 Spring Boot 只使用 Servlet 3 特性来引导应用程序。让我们详细谈谈这件事。

7.1. Spring 如何进行引导的?

Spring 既支持传统的 web.xml 引导方式,也支持最新的 Servlet 3+ 方法。

让我们来逐步了解 web.xml 方式:

  1. Servlet 容器(即服务器)读取 web.xml
  2. web.xml 中定义的 DispatcherServlet 由容器实例化。
  3. DispatcherServlet 通过读取 WEB-INF/{servletName}-servlet.xml 创建 WebApplicationContext
  4. 最后,DispatcherServlet 注册应用上下文中定义的 bean。

接下来是 Spring 如何使用 Servlet 3+ 方式引导:

  1. 容器搜索实现 ServletContainerInitializer 的类并执行。
  2. SpringServletContainerInitializer 查找所有实现 WebApplicationInitializer 的类。
  3. WebApplicationInitializer 使用 XML 或 @Configuration 类创建上下文。
  4. WebApplicationInitializer 使用前面创建的上下文创建 DispatcherServlet。 

7.2. Spring Boot 如何进行引导?

Spring Boot 应用的入口点是注释 @SpringBootApplication 的类:

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

默认情况下,Spring Boot 使用嵌入式容器来运行应用。这种情况下,Spring Boot 使用 public static void main 入口点来启动嵌入式 web 服务器。

它还负责将 Servlet、Filter 和 ServletContextInitializer bean 从应用上下文绑定到嵌入式 Servlet 容器。

Spring Boot 的另一个特性是,它会自动扫描 Main 类的同一包或子包中的所有类以查找组件。

此外,Spring Boot 还提供了将其作为 web 存档部署在外部容器中的选项。这种情况下,我们必须扩展 SpringBootServletInitializer

@SpringBootApplication
public class Application extends SpringBootServletInitializer {
    // ...
}

在这里,外部 servlet 容器查找 web 存档的 META-INF 文件中定义的 Main 类,SpringBootServletInitializer 将负责绑定 Servlet、Filter 和 ServletContextInitializer。

8. 打包及部署

最后,让我们看看如何打包和部署应用。这两个框架都支持 Maven 和 Gradle 等常见的包管理技术;然而,在部署方面,这些框架差异很大。

例如,Spring Boot Maven 插件在 Maven 中提供了 Spring Boot 支持。它还允许打包可执行 jar 或 war 档案,并“就地”运行应用。

在部署环境中,Spring Boot 相较于 Spring 的一些优势包括:

  • 提供嵌入式容器支持
  • 使用命令 java -jar 独立运行 jar
  • 在外部容器中部署时排除依赖关系以避免潜在 jar 冲突的选项
  • 部署时指定活动配置文件的选项
  • 集成测试的随机端口生成

9. 小结

本文中,我们介绍了 Spring 和 Spring Boot 之间的区别。

简而言之,我们可以说 Spring Boot 只是 Spring 本身的扩展,使开发、测试和部署更加方便。