领先一步
VMware 提供培训和认证,以加速您的进步。
了解更多开发、部署和运行云应用程序应该像(甚至比)本地应用程序更容易。这是任何云平台、库或工具背后的指导原则。Spring Cloud——一个开源库——使开发用于云的 JVM 应用程序变得容易。借助它,应用程序可以轻松地连接到服务并在多个云(例如 Cloud Foundry 和 Heroku)中轻松发现有关云环境的信息。此外,您可以将其扩展到其他云平台和新服务。
在这个博客(系列中的第一个)中,我将介绍 Spring Cloud 并从应用程序开发人员的角度展示其用法。我们将开发一个简单的应用程序并部署到Cloud Foundry和Heroku。在后续博客中,我将探讨可扩展性方面。
在云中运行应用程序的众多优势之一是各种服务的易用性。无需管理硬件、安装、操作、备份等,只需单击按钮或使用 shell 命令即可创建和绑定服务。
应用程序如何访问这些服务?例如,如果您有一个绑定到应用程序的关系数据库,则需要根据该服务创建一个DataSource
对象。这就是 Spring Cloud 提供帮助的地方。它消除了访问和配置服务连接器所需的所有工作,让您可以专注于使用这些服务。它还公开应用程序实例信息(主机地址、端口、名称等)。
Spring Cloud 通过云连接器的概念以独立于云的方式完成所有这些工作。虽然它为 Cloud Foundry 和 Heroku 提供了实现,但您可以(或云提供商可以)通过实现接口并利用库的其余部分将其扩展到其他云。然后,只需将包含扩展的库添加到应用程序的类路径中;无需分叉和构建 Spring Cloud。
Spring Cloud 还认识到它不可能满足每个云上每个服务的需要。因此,虽然它开箱即用地支持许多常见服务,但它允许您(或服务提供商)将其功能扩展到其他服务。与扩展到其他云一样,您可以将包含服务扩展的 jar 文件添加到应用程序的类路径中。
最后,它对Spring应用程序(在一个单独的模块中)提供了特殊支持,包括Spring Boot应用程序,其形式为 Java 和 XML 配置支持,并以易于使用的形式公开应用程序和服务属性。这是 Spring Cloud 中唯一依赖于 Spring 的模块。其他框架提供商可以以类似的方式为其框架贡献特定支持。
让我们看看 Spring Cloud 的实际应用。
我们将从一个基于 Spring Boot 的简单应用程序开始(源代码)(传统的 Spring MVC 应用程序也可以正常工作,尽管需要编写更多设置代码)。该应用程序包含一个控制器,其中注入的 bean 代表绑定的服务,以及一个打印绑定到应用程序的服务信息的首页。
@Controller
public class HomeController {
@Autowired(required = false) DataSource dataSource;
@Autowired(required = false) RedisConnectionFactory redisConnectionFactory;
@Autowired(required = false) MongoDbFactory mongoDbFactory;
@Autowired(required = false) ConnectionFactory rabbitConnectionFactory;
@Autowired ApplicationInstanceInfo instanceInfo;
@RequestMapping("/")
public String home(Model model) {
Map<Class<?>, String> services = new LinkedHashMap<Class<?>, String>();
services.put(dataSource.getClass(), toString(dataSource));
services.put(mongoDbFactory.getClass(), toString(mongoDbFactory));
services.put(redisConnectionFactory.getClass(), toString(redisConnectionFactory));
services.put(rabbitConnectionFactory.getClass(), toString(rabbitConnectionFactory));
model.addAttribute("services", services.entrySet());
model.addAttribute("instanceInfo", instanceInfo);
return "home";
}
// ... various toString() methods to create a string representation for each service
}
HomeController
具有四个注入的依赖项,这些依赖项代表可以绑定到应用程序的服务,以及另一个用于ApplicationInstanceInfo
的依赖项。"/”
路由将表示每个服务及其类的字符串以及实例信息添加到模型中。关联视图 呈现所有这些信息。
对于配置,我们添加如下所示的CloudConfig
@Configuration
@ServiceScan
@Profile("cloud")
public class CloudConfig extends AbstractCloudConfig {
@Bean
public ApplicationInstanceInfo applicationInfo() {
return cloud().getApplicationInstanceInfo();
}
}
该类扩展了AbstractCloudConfig
,这是使用 Spring Cloud 的 Java 配置方法的方式。我们将@Profile(“cloud”)
设置为确保仅在云环境中加载此配置。@ServiceScan
注解扫描所有绑定的服务并为每个服务创建一个 bean(然后自动装配到HomeController
中)。如果您想知道@ComponentScan
和@ServiceScan
之间的并行关系,您是对的。前者扫描可以实例化为 bean 的候选类,而后者扫描绑定的服务。我们还创建了一个与应用程序实例信息相对应的 bean。
我们包含以下manifest.yml
,它绑定了我们为了说明目的而需要的全部四项服务(您需要使用cf create-service
命令创建这些服务)
---
applications:
- name: hello-spring-cloud
memory: 512M
instances: 1
host: hello-spring-cloud-${random-word}
domain: cfapps.io
path: target/hello-spring-cloud-0.0.1-SNAPSHOT.jar
services:
- postgres-service
- amqp-service
- mongodb-service
- redis-service
env:
SPRING_PROFILES_DEFAULT: cloud
现在我们只需要构建和推送
$ mvn package
$ cf push
```
Now when we visit the page, we see information about all four services:
![Application deployed on Cloud Foundry](https://raw.githubusercontent.com/cloudfoundry-samples/hello-spring-cloud/gh-pages/img/hello-spring-cloud-cf.png)
In a real app, you probably would inject these services into service beans and do something more useful that printing their connection information! Please head over to http://projects.spring.io/spring-cloud to see a list of sample apps that do more interesting things with Spring Cloud. Speaking of https://springframework.org.cn, it too uses Spring Cloud underneath.
# Deploying it to Heroku
We can deploy the same application to Heroku. We need to add a couple of files (neither are specific to Spring Cloud): `system.properties` to make Heroku use Java 7 and `Procfile` to make it execute the right command to start the application and enable the `cloud` profile. We push the application to Heroku as follows:
```sh
$ heroku apps:create
$ heroku addons:add mongolab
$ heroku addons:add rediscloud
$ heroku addons:add cloudamqp
$ heroku config:set SPRING_CLOUD_APP_NAME=hello-spring-cloud
$ git push heroku master
```
Here we create add-ons (similar to Cloud Foundry services) for a MongoDb, Redis, and AMQP service provider. Heroku automatically provisions a Postgres service, therefore we don’t need to explicitly add it. Heroku app’s environment, unlike Cloud Foundry, doesn’t expose the app name, so we use `heroku config:set` to explicitly set it (if not, Spring Cloud will set it to `<unknown>`). There are a few other differences in how Spring Cloud adapts to differences between these two clouds; we will cover those in a later blog.
That’s all we need to do. When we visit our application, it shows all services info much the same way it did on Cloud Foundry.
![Application deployed on Heroku](https://raw.githubusercontent.com/cloudfoundry-samples/hello-spring-cloud/gh-pages/img/hello-spring-cloud-heroku.png)
# Taking some control
The use of `@ServiceScan` made it easy to grab all services and start using them. But in practice, you often need more control over creating a service connector such as setting their pooling parameters. If that is the case, you can use Spring Cloud’s Java Config or XML config support. Let’s change the `CloudConfig` class as follows:
```java
@Configuration
@Profile("cloud")
public class CloudConfig extends AbstractCloudConfig {
@Bean
public ConnectionFactory rabbitConnectionFactory() {
return connectionFactory().rabbitConnectionFactory();
}
@Bean
public DataSource dataSource() {
return connectionFactory().dataSource();
}
@Bean
public MongoDbFactory mongoDb() {
return connectionFactory().mongoDbFactory();
}
@Bean
public RedisConnectionFactory redisConnectionFactory() {
return connectionFactory().redisConnectionFactory();
}
@Bean
public ApplicationInstanceInfo applicationInfo() {
return cloud().getApplicationInstanceInfo();
}
}
```
Compared to the first version, we removed the `@ServiceScan` annotation. Instead, we use the API exposed by `AbstractCloudConfig` to create beans for each of the services. For now, the beans created this way are identical to that created by `@ServiceScan`, but we now have a possibility of configuring it further. For example, if we wanted to bind the `DataSource` bean to a specific service (presumably among many bound to the app) and initialize it with a specific pool configuration, we can make the following change:
```java
@Bean
public DataSource dataSource() {
PoolConfig poolConfig = new PoolConfig(20, 200);
ConnectionConfig connectionConfig =
new ConnectionConfig("sessionVariables=sql_mode='ANSI';characterEncoding=UTF-8");
DataSourceConfig serviceConfig =
new DataSourceConfig(poolConfig, connectionConfig);
return connectionFactory().dataSource("my-service", serviceConfig);
}
```
The `DataSource` created this way will have max pool size of 20 and max wait time of 200 milliseconds along with a specific connection property string.
# Summary
Spring Cloud abstracts connecting to cloud services and makes it possible to have the same application deployed to multiple clouds with little extra effort. In this blog we merely scratched the surface of what Spring Cloud offers. In the next blog, we will explore more about the Java and XML config as well as how you can use its core API in non-spring apps. In the blogs that follow we will dive deeper into the extensibility angle of Spring Cloud.