Java 不烂 - 玩转 JVM

工程 | Brian Dussault | 2015年2月11日 | ...

最近,James Ward 写了一篇很棒的博客文章,“Java 不烂 – 你只是用错了”,其中重点介绍了企业级 Java 开发者在日常构建 Java 应用时面临的诸多挑战。好消息是,摆脱开发困境比你想象的要容易得多。在过去几年里,Spring 重新定义了现代 Java 应用的构建方式,同时显著提高了开发效率。在这篇文章中,我将以 James Ward 的博客文章为背景,解释 Spring 如何帮助开发者(使用 Java)玩转 JVM,同时解决 James 提出的每一个问题。

##即时开发环境搭建太棒了 在 James 的博客中,他断言“设置开发环境需要 10 页 Wiki 太糟糕了”。我们职业生涯中都曾创建过这些 Wiki 页面,并努力尝试保持其更新。这些 Wiki 长期以来一直是新团队成员的沮丧来源,因为它们常常充斥着过时的信息。好消息是,Spring Boot 的构建支持使得自动化这一过程变得相当容易。

从现有应用开始,只需克隆源代码仓库并运行应用即可。Spring Boot 支持 Java 最流行的构建工具 Maven 和 Gradle。使用你喜欢的构建工具运行一个功能齐全的应用就这么简单:

Maven 示例

mvn spring-boot:run

Gradle 示例

gradle bootRun

由于 Spring Boot 应用是一个自包含的工作负载,将应用代码、服务器和第三方依赖项组合成一个构建和部署单元(可执行的 .jar 文件),因此无论使用何种 IDE,开发团队都能获得直接、可重复的开发体验。开发者摆脱了繁琐的环境设置说明,可以专注于构建出色的应用。在构建过程之外运行 Spring Boot 应用可以通过执行以下命令实现:

java -jar target/my-application-1.0.1-SNAPSHOT.jar

提示:想自己尝试一下?请按照 spring.io 上的众多入门指南之一进行操作。对于刚接触 Spring Boot 的开发者来说,一个很好的起点是使用 Spring Boot 构建应用指南。

##一致的部署环境太棒了 James Ward 强调的下一个挑战是“为了最大限度地降低将构建从开发环境推送到预生产环境再到生产环境的风险,唯一应该在各个环境之间变化的是配置”。手动修改部署工件是灾难的根源,最终会导致部署延迟或失败。特定于环境的配置应该外部化,确保在开发环境中测试的代码是最终将进入生产环境的“黄金副本”。这是证明您测试的内容就是您部署的内容的唯一经济有效的方法!

Spring Boot 通过一种非常特定的 PropertySource 顺序,使得外部化配置变得轻而易举,这种顺序旨在允许合理地覆盖值。通常希望在项目中提供用于本地开发的默认配置,但在跨环境推广代码时覆盖这些值。Spring Boot 通过命令行参数、JNDI 属性、Java 系统属性、操作系统环境变量、配置文件、基于 Profile 的配置变体以及更多方式为外部化配置提供了全面的支持。Spring Boot 对环境变量的支持使得遵循十二要素应用配置最佳实践(代码与配置严格分离)变得轻而易举。

提示 1:在使用 Cloud Foundry 等云平台时,Spring Boot 应用可以利用Spring Cloud Connectors 自动绑定到 Cloud Foundry 服务,如数据库和消息系统。这样做的好处是减少了应用需要维护的环境特定配置属性的数量,显著降低了在跨环境推广代码时出错的风险。

提示 2:想知道为什么十二要素应用很重要吗?请查看这篇博客文章:为什么十二要素应用模式、微服务和 CloudFoundry 很重要

##快速的服务器启动太棒了 Spring Boot 支持轻量级、嵌入式容器/服务器,它们可以快速启动。一个简单的 REST 应用可以在短短 3 秒内启动。从 Spring Boot 1.2 开始,支持嵌入式应用服务器包括 Tomcat(默认容器)、Jetty 和 Undertow。Spring Boot 不仅支持领先的轻量级容器,而且通过使其易于替换默认容器,让开发者完全掌控这些决策。

以下 Gradle 构建配置启用了全栈 Web 开发支持,包括嵌入式 Tomcat 和 spring-webmvc 的支持。

Gradle 示例

...

apply plugin: 'java'

repositories { jcenter() }
dependencies {
    compile("org.springframework.boot:spring-boot-starter-web:1.2.0.RELEASE")
}

...

正如 James Ward 在其原始博客文章中所指出的那样,通过将单体部署拆分为微服务,启动时间可以得到进一步改善。在本文后面,将进一步详细讨论微服务的主题(请参阅标题为 微服务风格架构太棒了 的部分)。

受管理的依赖项太棒了

现代开发者需要能够让他们快速上手且阻力最小的工具和技术。他们还要求模块化、轻量级且具有明确观点的技术来优化生产力。Spring Boot 正是针对快速启动和运行的问题,同时显著提高了开发速度。

正如 James Ward 正确指出的那样,“如果你的任何库依赖项不是由构建工具管理的,那太糟糕了”。Spring Boot 不仅支持现代构建技术,还提供了名为Starter POMs 的便捷依赖项描述符,从而将这一最佳实践变为首要实践。Starter POMs 为常见的开发工作负载提供了一组依赖项,你可以直接将其包含在你的应用中。

要开始使用 Spring Boot,你可以将浏览器指向 Spring Initializr - http://start.spring.io。Spring Initializr 提供了一个基于 Web 的界面,允许开发者选择应用/工作负载和相关依赖项。然后,它将生成一个带有构建支持的入门应用(支持 Maven POM、Maven 项目、Gradle 配置、Gradle 项目)。

Spring Initializr 截图:Spring Initializr 截图

对于喜欢命令行的开发者,您可以通过执行以下命令安装 Spring Boot CLI:

curl http://start.spring.io/install.sh | sh

可以通过简单地执行以下命令来使用命令行初始化新项目:

spring init --dependencies=web,data-jpa my-project

此初始化(通过 Spring Initializer 或 Boot CLI)的结果是一个完全可用的应用,其中所需的依赖项已被包含并由 Spring Boot 自动配置。

Spring IO Platform(包括 Spring Boot)也提供了 Spring Boot starter POMs 所管理的依赖项的超集。Spring IO 平衡了 Spring 产品组合中各依赖项的版本,并且发布周期比 Spring Boot 更长,为企业提供了一个经过测试且已知可以协同工作的依赖项版本快照。Spring IO Platform 分发版不是一个巨大的库下载包,开发者可以自由选择应用中需要的任何部分。Spring IO 分发版包含 Spring 模块、测试库、日志框架、数据库管理、SQL/No-SQL 等众多组件的版本。Spring IO 分发版非常适合希望以更平缓的节奏使用 Spring IO Platform 依赖项的企业。

以下 Gradle 配置演示了如何配置 Spring IO Platform 的物料清单 (bill-of-materials) 并利用 Spring Boot 的 web starter POM


buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'io.spring.gradle:dependency-management-plugin:0.3.0.RELEASE'
    }
}

apply plugin: 'io.spring.dependency-management'

repositories {
    mavenCentral()
}

dependencyManagement {
    imports {
        mavenBom 'io.spring.platform:platform-bom:1.1.0.RELEASE'
    }
}

dependencies {
    compile 'org.springframework.boot:spring-boot-starter-web'
}

##短开发/验证周期真的很棒 大多数现代应用都构建有富用户界面,与后端服务通信。以这种方式构建应用的好处在于 UI 和服务器端逻辑之间实现了良好的关注点分离。大多数现代 IDE 都提供静态资源的动态重载,允许开发者无需重启服务器即可看到更改。

Spring Boot 还支持服务器端模板技术,如 Thymeleaf、Freemarker 和 Groovy。Spring Boot 允许动态重载这些模板技术,而无需重启服务器。对于 Thymeleaf,只需在 application.properties 文件中设置以下属性即可实现:

spring.thymeleaf.cache: false

在服务器端,将您的单体应用拆分为微服务将减少 Spring Boot 应用的启动时间(由于使用了轻量级嵌入式容器,启动时间已经相当快)。此外,Spring Boot 还支持测试工具的自动配置。启用 Boot 的测试自动配置就像包含 spring-boot-starter-test starter POM 一样简单。这使得 Spring Test、JUnit、Hamcrest 和 Mockito 依赖项可用,从而轻松地将测试驱动开发 (TDD) 集成到日常工作流程中。TDD 使开发者能够立即收到对其代码更改的反馈。

最后,JRebel 为类重载提供了全面的支持,支持 80 多种 Java 框架(包括 Spring)。请查看 Josh Long 和 Adam Koblentz 主讲的在线研讨会 Spring Boot and JRebel 6 以获取更多详情。

##微服务风格架构太棒了 James 关于“单体发布太糟糕了”的说法对于大型或复杂的分布式系统来说是正确的。大多数开发者希望以更迭代的方式(敏捷)工作并更频繁地发布。微服务风格的架构作为一种应对单体应用挑战的方式越来越受欢迎。对于不熟悉微服务的人,Martin Fowler 在他的博客中提供了对这种架构风格的出色描述。

在构建分布式应用(包括微服务风格应用)时,会出现许多常见的系统模式。Spring Cloud 通过提供开箱即用的服务来解决最常见的挑战,从而使其易于采用这些模式。Spring Cloud 实现了诸如配置管理、服务发现、断路器、智能路由、微代理和控制总线等模式。Spring Boot 使将这些功能集成到您的应用中变得异常简单。

例如,Spring Cloud Netflix 项目使得使用 Netflix 的 Eureka 搭建服务发现服务变得像这样简单:


@SpringBootApplication 
@EnableEurekaServer

public class Application {
    public static void main(String[] args) {
        new SpringApplicationBuilder(Application.class).web(true).run(args);
    }

}

客户端应用只需使用 @EnableEurekaClient 即可注册为 Eureka 客户端。


@SpringBootApplication
@EnableEurekaClient
@RestController
public class Application {

    @RequestMapping("/")
    public String home() {
        return "Hello world";
    }

    public static void main(String[] args) {
        new SpringApplicationBuilder(Application.class).web(true).run(args);
    }

}

提示 1:Spring Cloud 支持多种分布式处理模式。为了帮助您入门,请查看 Spring Cloud Samples GitHub 仓库。Dave Syer 和 Spencer Gibb 在 SpringOne 的演讲 Spring Cloud, Spring Boot and Netflix OSS 是理解和学习如何操作微服务风格架构的另一个绝佳途径。

提示 2:如果您希望构建超媒体风格的 REST API,请务必查看入门指南 使用 REST 访问 JPA 数据Spring Data REST 将有助于加速您的服务开发。Spring Data REST 支持 SQL 和 No-SQL 仓库。

拥有能够让您快速编写微服务的技术只是成功的一半。开发者常常受到将代码部署到生产平台中的各种延迟困扰。一些最常见的障碍包括手动部署、测试、基础设施供应和服务供应。持续交付旨在自动化将代码推向生产环境的过程,同时最大限度地降低风险。这使得组织能够对应用进行增量更改,使部署成为业务决策而非资源决策。这本身是一个很大的话题,但我强烈推荐 Matt Stine 的演讲 使用 Spring 和 Cloud Foundry 为 PaaS 开发微服务,该演讲出色地强调了将敏捷工程实践与 Pivotal Cloud Foundry 的自动化相结合的益处。

##无状态应用太棒了 James 指出,“粘性会话和服务器状态通常是扼杀性能和弹性的最佳方法之一。会话状态(传统 Servlet 意义上的)使得持续交付和水平扩展变得异常困难。”

从应用中移除会话状态可以显著简化操作,允许应用在无需担心丢失会话数据的情况下重新部署、终止或扩展。保留状态存在有效的用例,例如共享认证状态,但这种状态应该持久化在应用外部(通常在高性能存储库中,如 NoSQL、分布式缓存,甚至是内存数据存储)。外部化应用状态不必是一项繁重的工作,Spring Session 提供了通用基础设施,使这一过程变得简单且可移植。Spring Session 提供:

  • 以供应商中立的方式支持集群
  • RESTful API 支持 - 支持在 Header 中使用会话 ID
  • 用于确定会话 ID 的可插拔策略
  • 在 WebSocket 活动时保持 HttpSession 活跃的支持
  • 支持基于 Redis 和 Hazelcast 的会话存储
  • 在单个浏览器中管理多个并发会话的能力(例如,类似于支持多个 Google 账号)

使用 Redis 配置 Spring Session 就像这样简单:

@EnableRedisHttpSession
public class Config {

    @Bean
    public JedisConnectionFactory connectionFactory() {
        return new JedisConnectionFactory();
    }
}

提示:Spring Session 1.0 最近已正式发布 (GA),所以请尝试Spring Session 示例来亲身体验。Dave Syer 最近发表了一篇题为API 网关模式:Angular JS 和 Spring Security 第四部分的博客文章,其中详细介绍了共享认证状态的用例。强烈推荐阅读!

最后,如果您正在使用 Pivotal Cloud Foundry,Cloud Foundry Java 构建包提供了另一种通过自动配置的 CF 会话状态存储来轻松外部化状态的选项。请查看这篇博客文章了解详情。

##非阻塞应用太棒了 许多现代应用架构可以从异步和非阻塞请求处理中受益匪浅。这些用例可以包括组合多个后端服务调用和 WebSocket 风格的应用。

Project Reactor(Spring IO Platform 的一部分)为构建这些异步、非阻塞应用提供了基础。在 2.0 版本中,Reactor 将提供Reactive Streams 规范的完整实现,从而实现了与其他 Reactive Streams 实现(如 Akka StreamsRatpackRxJava)的集成。

以下代码片段展示了如何使用 Reactive Streams API 创建流、添加业务逻辑,然后向其中发布数据:

// by default Streams use the Disruptor RingBufferDispatcher
Broadcaster<String> helloStream = Streams.broadcast(env);

helloStream.map(s -> "Hello " + s + "!")
           .consume(log::info);

helloStream.onNext("World");

提示:Spring Boot 支持 Project Reactor,使其易于入门。请按照使用 Reactor 创建异步事件驱动应用入门指南来创建您的第一个响应式应用。此外,请务必查看在线研讨会:使用 Reactor 构建异步、非阻塞微服务

Spring Framework 4 引入了对 WebSocket 风格的事件驱动应用的支持。这种务实的方法远超 JSR-356 规范,包括通过 SockJS 提供客户端回退选项、支持消息子协议 (STOMP)、安全(Spring Security 4)、消息代理支持、基于 Reactor 的 MessageChannel 用于消息传递、客户端断开连接处理以及熟悉的 Spring 编程模型。

提示:Spring Boot 使 WebSocket 应用的配置变得轻而易举。请按照使用 WebSocket 构建交互式 Web 应用指南来开始。

Java 语言太棒了

Spring Boot 为开发者提供了使用 Java 6、7、8 以及 Groovy 来构建下一代应用的选择。在 James 的文章中,他提到“Java 语言有点糟糕”,但随着 Java 8 的发布,Java 得到了极大的推动,并提供了许多能够提高生产力的强大语言特性。Java 8 的一些出色特性包括支持 Lambda 表达式、Stream 和并发改进。Spring Boot 使您轻松开始使用 Java 8 或 Groovy。

提示:如果您是 Java 8 特性的新手,我强烈推荐 Venkat Subramaniam 的书 Java 中的函数式编程:利用 Java 8 Lambda 表达式的力量 以及他在 SpringOne2GX 2014 上的演讲。

##结论 构建现代 Java 应用不必是一个痛苦的经历。Spring Boot 已经消除了构建应用的繁琐仪式,让 Java 再次变得有趣。Spring 从您应用的每一层移除样板代码——业务逻辑(Spring Foundation 项目)、配置和运行时(Spring Boot)以及分布式系统模式(Spring Cloud)。最佳入门方法是深入研究Spring 的入门指南,并部署到Pivotal Web Services(一个公共托管版本的 Cloud Foundry,可免费试用 60 天)。

获取 Spring 资讯

订阅 Spring 资讯,保持联系

订阅

取得领先

VMware 提供培训和认证,助您加速进步。

了解更多

获取支持

Tanzu Spring 在一个简单的订阅中提供对 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件。

了解更多

即将举行的活动

查看 Spring 社区中所有即将举行的活动。

查看全部