From 1b675fa5e7bca618f44a403335517c6e4c18de0b Mon Sep 17 00:00:00 2001 From: Christopher Smith Date: Wed, 16 Jul 2014 17:33:15 -0500 Subject: [PATCH] Overhaul Markdown documentation. Spring connector still needs rework. link check rewrite main README link check rewrite core doc rephrase heading for clarity weird GFM indentation in code blocks info on adding ServiceInfos update docs for Heroku and CF connectors improve docs for local connector tweak description of service connectors edits as discussed in #54 reword Spring registration --- README.md | 157 ++++++++++++------ spring-cloud-cloudfoundry-connector/README.md | 44 ++--- spring-cloud-core/README.md | 154 +++++++++++------ spring-cloud-heroku-connector/README.md | 54 ++++-- spring-cloud-localconfig-connector/README.md | 66 +++++--- 5 files changed, 310 insertions(+), 165 deletions(-) diff --git a/README.md b/README.md index 515d282..2e825db 100644 --- a/README.md +++ b/README.md @@ -1,69 +1,116 @@ -Spring-cloud offers a simple way for JVM apps in cloud to access services and discover their own information during runtime with special support for Spring apps. It offers an extensibility mechanism to make it work on multiple clouds and a variety of cloud services. Through the abstraction of cloud connector, you can make it work with multiple clouds (we include two examples: Cloud Foundry and Heroku) without touching the spring-cloud project itself. Through the service connector abstraction, you can make it work with a variety of services (such as all the new ones on Cloud Foundry marketplace), again, without touching the spring-cloud project itself. +Spring Cloud provides a simple abstraction for JVM-based applications running on cloud platforms +to discover bound services and deployment information at runtime and provides support for registering +discovered services as Spring beans. It is based on a plugin model so that the identical +compiled application can be deployed locally or on multiple clouds, and it supports custom service +definitions through Java SPI. + +Spring Cloud provides out-of-the-box support for discovering common services on Heroku and +Cloud Foundry clouds as well as a properties-based configuration for development and testing. The core concepts used in this project are: -1. **Cloud Connector**: An interface that a cloud provider can implement to allow the rest of the library work with a Platform As a Service (PaaS) offering. -2. **Service Connector**: An object, such as `javax.sql.DataSource`, that represent a connection to a service. -3. **Service information**: Information about the underlying service such as host, port, and credentials. -4. **Application information**: Information about application and instance in which these libraries are embedded. +- [**Cloud connector**](./spring-cloud-core/src/main/java/org/springframework/cloud/CloudConnector.java): + An interface specific to a cloud platform that identifies the presence of the platform and + discovers any services bound to the application deployment. +- **Service connector**: An object, such as a `javax.sql.DataSource`, that represents a runtime + connection to a service. +- [**Service information**](./spring-cloud-core/src/main/java/org/springframework/cloud/service/ServiceInfo.java): + Information about the underlying service such as host, port, and credentials. +- [**Application information**](./spring-cloud-core/src/main/java/org/springframework/cloud/app/ApplicationInstanceInfo.java): + Information about the application and the particular running instance. -The project comprises of four subprojects: +The project contains three major submodules: -1. **[core](spring-cloud-core)**: Core library that is cloud agnostic and Spring agnostic. Provides entry point for application developers that choose to programmatically access cloud services and application information. It also provides an extension mechanism to contribute cloud connectors and service connector creators. -2. **[spring-service-connector](spring-cloud-spring-service-connector)**: Library that provides service connectors creators for javax.sql.DataSource and various connection factories spring-data projects. -3. **[cloudfoundry-connector](spring-cloud-cloudfoundry-connector)**: Cloud connector for [Cloud Foundry](http://www.cloudfoundry.com). -4. **[heroku-connector](spring-cloud-heroku-connector)**: Cloud connector for [Heroku](http://www.heroku.com). +- **[core](spring-cloud-core)**: The core library, cloud- and Spring-agnostic, that provides + a programmatic entry point for developers who prefer to access cloud services and application + information manually. It also provides basic service definitions for several common services + (databases, message queues) and an SPI-based extension mechanism to contribute + cloud and service connectors. +- **[spring-service-connector](spring-cloud-spring-service-connector)**: A Spring Library that + exposes application and cloud information and discovered services as Spring beans of the + appropriate type. For example, SQL services will be exposed as `javax.sql.DataSource`s with + optional connection pooling. +- Cloud connectors: + - **[cloudfoundry-connector](spring-cloud-cloudfoundry-connector)**: Connector for [Cloud Foundry](http://cloudfoundry.org). + - **[heroku-connector](spring-cloud-heroku-connector)**: Connector for [Heroku](https://www.heroku.com). + - **[localconfig-connector](spring-cloud-localconfig-connector)**: Properties-based connector for + manually providing configuration information for development or testing. Allows the use of the + same Spring Cloud configuration wiring in all stages of application deployment. -Getting Started -=============== +##Getting Started -The following assumes that you are using Maven. +The following examples are written for Maven; simply include the appropriate dependencies for +your build system. -Spring apps ------------ +###Including cloud connectors -Add the [`spring-service-connector`](spring-cloud-spring-service-connector) and one or more cloud connectors dependencies (it is okay to add more that one cloud connectors): +Include the connector for each cloud platform you want to be discoverable. Including multiple +connectors is perfectly fine; each connector will determine whether it should be active in a +particular environment. - - org.springframework.cloud - spring-cloud-spring-service-connector - 1.0.0.RELEASE - - - - org.springframework.cloud - spring-cloud-cloudfoundry-connector - 1.0.0.RELEASE - - - - org.springframework.cloud - spring-cloud-heroku-connector - 1.0.0.RELEASE - +````xml + + + org.springframework.cloud + spring-cloud-localconfig-connector + 1.1.0.RELEASE + -Then follow instructions on [how you use the Java config and `` namespace](spring-cloud-spring-service-connector). You can also follow the [instructions](spring-cloud-core) on using the core API directly. + + + org.springframework.cloud + spring-cloud-cloudfoundry-connector + 1.1.0.RELEASE + -Non-spring apps + + + org.springframework.cloud + spring-cloud-heroku-connector + 1.1.0.RELEASE + +```` + +###Spring applications + +Add the [`spring-service-connector`](spring-cloud-spring-service-connector) in +addition to your cloud connectors: + +````xml + + org.springframework.cloud + spring-cloud-spring-service-connector + 1.1.0.RELEASE + + + + + org.springframework.cloud + spring-cloud-localconfig-connector + 1.1.0.RELEASE + + + + + org.springframework.cloud + spring-cloud-cloudfoundry-connector + 1.1.0.RELEASE + + + + + org.springframework.cloud + spring-cloud-heroku-connector + 1.1.0.RELEASE + +```` + +Then follow the instructions on [Spring configuration using Java configuration or +the `` namespace](spring-cloud-spring-service-connector). + +###Non-Spring applications --------------- -Add the [`core`](core) and one or more cloud connectors dependencies (it is okay to add more that one cloud connectors): +The [`spring-cloud-core`](core) dependency is included by each cloud connector, +so simply include the connectors for the platforms you want. - - org.springframework.cloud - spring-cloud-core - 1.0.0.RELEASE - - - - org.springframework.cloud - spring-cloud-cloudfoundry-connector - 1.0.0.RELEASE - - - - org.springframework.cloud - spring-cloud-heroku-connector - 1.0.0.RELEASE - - -Then follow the [instructions](spring-cloud-core) on using spring-cloud API. +Then follow the [instructions](spring-cloud-core) on using the Spring Cloud API. \ No newline at end of file diff --git a/spring-cloud-cloudfoundry-connector/README.md b/spring-cloud-cloudfoundry-connector/README.md index b7fc703..f2e978c 100644 --- a/spring-cloud-cloudfoundry-connector/README.md +++ b/spring-cloud-cloudfoundry-connector/README.md @@ -1,23 +1,27 @@ -Cloud Foundry connector for spring-cloud -======================================== +#Spring Cloud Cloud Foundry connector -Provides Cloud Foundry connector with support for Mysql, Postgres, RabbitMQ, MongoDB, and Redis services. +This connector will discover services bound to an application running in Cloud Foundry. +It currently knows about: -Supporting additional services ------------------------------- -The cloudfoundry-connector offers extending support for additional services -through the same [`ServiceLoader`](http://docs.oracle.com/javase/7/docs/api/java/util/ServiceLoader.html) -mechanism used in the [core](../spring-cloud-core) project. -It allows extending to new services without modifying the [cloudfoundry-connector](../spring-cloud-cloudfoundry-connector) -itself. All you need to do is: +- PostgreSQL +- MySQL +- Oracle +- Redis +- MongoDB +- RabbitMQ +- SMTP gateway +- application monitoring (New Relic) -1. Create a new project declaring dependency of [cloudfoundry-connector](../spring-cloud-cloudfoundry-connector). -2. Add one implementation of [`CloudFoundryServiceInfoCreator`](src/main/java/org/springframework/cloud/cloudfoundry/CloudFoundryServiceInfoCreator.java) - for each service type you wish to extend. - Along the way, you will, of course, add an implementation of [`ServiceInfo`](../core/main/java/org/springframework/cloud/service/ServiceInfo.java) - (consider extending [`BaseServiceInfo`](../core/main/java/org/springframework/cloud/service/BaseServiceInfo.java)), - attach an [`@ServiceLabel`](../core/main/java/org/springframework/cloud/service/ServiceLabel.java) annotation, - and mark appropriate properties with [`@ServiceProperty`]((../core/main/java/org/springframework/cloud/service/ServiceProperty.java)) annotation. -3. Add a file on classpath - `META-INF/services/org.springframework.cloud.cloudfoundry.CloudFoundryServiceInfoCreator` - and add all your implementations of `CloudFoundryServiceInfoCreator`. \ No newline at end of file +Since Cloud Foundry enumerates each service in a consistent format, Spring Cloud does +not care which service provider is providing it. + +##Supporting new service types + +Extend [`CloudFoundryServiceInfoCreator`]((src/main/java/org/springframework/cloud/cloudfoundry/CloudFoundryServiceInfoCreator.java)) +with a creator for [your service's `ServiceInfo` class](../spring-cloud-core/#adding-service-discovery). + +Add the fully-qualified class name for your creator to + +```` +META-INF/service/org.springframework.cloud.cloudfoundry.CloudFoundryServiceInfoCreator +```` \ No newline at end of file diff --git a/spring-cloud-core/README.md b/spring-cloud-core/README.md index 80233e4..b43c208 100644 --- a/spring-cloud-core/README.md +++ b/spring-cloud-core/README.md @@ -1,71 +1,131 @@ -Spring Cloud Core Library -========================= +#Spring Cloud Core -The core library to let cloud applications access application information and services. -While Spring applications is one of the main target for this library, it may be used in -non-Spring projects as well. In fact, **this library doesn't even depend on Spring**. +This core library provides programmatic access to application and service information. This library +has no Spring dependencies and may be used in non-Spring applications. -This library requires Java 6, +This library requires Java 6 or newer. -This library is cloud-agnostic. Through connectors, it supports multiple clouds -(with Cloud Foundry and Heroku as the example clouds). +This library is cloud-agnostic. Using Java SPI, it supports pluggable cloud and service +connectors; support for Cloud Foundry and Heroku is available out-of-the-box, in addition to +locally-provided configuration for development and testing. -This library also supports an extension to create services connectors of user-desired types. +##Connecting to a cloud -Usage pattern: Application Developers -===================================== +> **Note:** If you are using Spring Cloud in a Spring application, you should consider +[automatically injecting Spring beans](../spring-cloud-spring-service-connector) instead. -> **Note:** If you are using spring-cloud in a Spring application, you should consider using the -[Java config](../spring-cloud-spring-service-connector#the-java-config) or the -[XML namespace support](../spring-cloud-spring-service-connector#the-cloud-namespace) instead. +* Include the desired cloud connectors on the runtime classpath +[as described in the main documentation](../#including-cloud-connectors). * Create a [`CloudFactory`](src/main/java/org/springframework/cloud/CloudFactory.java) instance. - Creation of a `CloudFactory` instance is a bit expensive, so caching such an instance is recommended. - If you are using a dependency injection frameworks such as Spring, creating a bean for `CloudFactory` - will achieve the caching effect. + Creation of a `CloudFactory` instance is a bit expensive, so using a singleton instance is recommended. + If you are using a dependency injection framework such as Spring, create a bean for the `CloudFactory`. ```java - CloudFactory cloudFactory = new CloudFactory(); +CloudFactory cloudFactory = new CloudFactory(); ``` -* Obtain a suitable [`Cloud`](src/main/java/org/springframework/cloud/Cloud.java) for the environment + +* Obtain the [`Cloud`](src/main/java/org/springframework/cloud/Cloud.java) object for the environment in which the application is running. ```java - Cloud cloud = cloudFactory.getCloud(); +Cloud cloud = cloudFactory.getCloud(); ``` - Note that you must have a `CloudConnector` implementation suitable - for the environment in which the application is being deployed in your classpath. For example, if you are - deploying the application in Cloud Foundry, you must add [cloudfoundry-connector](../spring-cloud-cloudfoundry-connector) - in your classpath. If no suitable `CloudConnctor` is found, the `getCloud()` method will throw a `CloudException`. -* Use the `Cloud` instance to get access to application info, service infos, and create service + Note that you must have a `CloudConnector` suitable for your deployment environment on your classpath. + For example, if you are deploying the application to Cloud Foundry, you must add [cloudfoundry-connector](../spring-cloud-cloudfoundry-connector) + to your classpath. If no suitable `CloudConnctor` is found, the `getCloud()` method will throw a [ + `CloudException`](../spring-cloud-core/src/main/java/org/springframework/cloud/CloudException.java). + +* Use the `Cloud` instance to access application and service information and to create service connectors. ```java - // ServiceInfo has all the information necessary to connect to the underlying service - cloud.getServiceInfos(); +// ServiceInfo has all the information necessary to connect to the underlying service +List serviceInfos = cloud.getServiceInfos(); ``` ```java - // Alternatively, let the cloud create a service connector for you - DataSource ds = cloud.getServiceConnector("inventory-db", DataSource.class, null /* default config */); +// find the `ServiceInfo` definitions suitable for connecting to a particular service type +List databaseInfos = cloud.getServiceInfos(DataSource.class); + ```` + + ```java +// Alternately, let Spring Cloud create a service connector for you +String serviceId = "inventory-db"; +DataSource ds = cloud.getServiceConnector(serviceId, DataSource.class, null /* default config */); ``` -Usage pattern: Cloud and Service Providers -========================================== -A cloud provider may extends the functionality in two ways: +##Adding cloud connectors -1. Add new [`CloudConnector`](src/main/java/org/springframework/cloud/CloudConnector.java)s to make - spring-cloud related libraries work with a new cloud. - See [cloudfoundry-connector](../spring-cloud-cloudfoundry-connector) - or [heroku-connector](../spring-cloud-heroku-connector) for an example. - This is done declaratively by adding connector classes to: - ``` - META-INF/services/org.springframework.cloud.CloudConnector - ``` -2. Add new [`ServiceConnectorCreator`](src/main/java/org/springframework/cloud/service/ServiceConnectorCreator.java)s - to allow creation of service connector objects. - See [spring-service-connector](../spring-cloud-spring-service-connector) for an example. - This is done declaratively by adding creator classes to: - ``` - META-INF/services/org.springframework.cloud.service.ServiceConnectorCreator - ``` \ No newline at end of file +A cloud provider may extend Spring Cloud by adding a new +[`CloudConnector`](src/main/java/org/springframework/cloud/CloudConnector.java) +to make Spring Cloud work with a new cloud platform. The connector is responsible for +telling whether the application is running in the specific cloud, identifying application +information (such as the name and instance ID of the particular running instance), and +mapping bound services (such as URIs exposed in environment variables) as `ServiceInfo` objects. + +See the [Cloud Foundry](../spring-cloud-cloudfoundry-connector) +and [Heroku](../spring-cloud-heroku-connector) connectors for examples. + +Spring Cloud uses the Java SPI to discover available connectors. New cloud connectors +should list the fully-qualified class name in the provider-configuration file at + +``` +META-INF/services/org.springframework.cloud.CloudConnector +``` + +## Adding service discovery + +To allow Spring Cloud to discover a new type of service (`HelloWorldService`), +create a `ServiceInfo` class containing the information necessary to connect to your +service. If your service can be specified via a URI, extend `UriBasedServiceInfo` +and provide the URI scheme in a call to the `super` constructor. + +This class will expose information for a service available at + +```` +helloworld://username:password@host:port/Bonjour +```` + +````java +public class HelloWorldServiceInfo extends UriBasedServiceInfo { + public static final String URI_SCHEME = "helloworld"; + + // needed to support structured service definitions like Cloud Foundry + public HelloWorldServiceInfo(String id, String host, int port, String username, String password, String greeting) { + super(id, URI_SCHEME, host, port, username, password, greeting); + } + + // needed to support URI-based service definitions like Heroku + public HelloWorldServiceInfo(String id, String uri) { + super(id, uri); + } +} +```` + +Then you will need to create a `ServiceInfoCreator` for each cloud platform you want to support. +You will probably want to extend the appropriate creator base class(es), such as `HerokuServiceInfoCreator`. This is +often as simple as writing a method that instantiates a new `HelloWorldServiceInfo`. + +Register your `ServiceInfoCreator` classes in the appropriate provider-configuration file for +your cloud's `ServiceInfoCreator` base class. + +## Adding service connectors + +A service connector consumes a `ServiceInfo` discovered by the cloud connector and converts +it into the appropriate service object, such as a `DataSource` for a service definition +representing a SQL database. + +Service connectors may be tightly bound to the framework whose service objects they are +creating; for example, some connectors in the +[Spring service connector](../spring-cloud-spring-service-connector) create connection +factories defined by Spring Data, for use in building Spring Data templates. + +To add new service connectors, implement +[`ServiceConnectorCreator`](src/main/java/org/springframework/cloud/service/ServiceConnectorCreator.java) +in your connector classes and list the fully-qualified class names in the +provider-configuration file at + +```` +META-INF/services/org.springframework.cloud.service.ServiceConnectorCreator +```` \ No newline at end of file diff --git a/spring-cloud-heroku-connector/README.md b/spring-cloud-heroku-connector/README.md index 2ad1b06..3a851e0 100644 --- a/spring-cloud-heroku-connector/README.md +++ b/spring-cloud-heroku-connector/README.md @@ -1,23 +1,43 @@ -Heroku connector for spring-cloud -======================================= +#Spring Cloud Heroku connector -Provides Heroku connector with support for Postgres (Mysql, RabbitMQ, MongoDB, and Redis services -coming soon; PR requests welcome). +This connector will discover services bound to an application running in Heroku. It +currently knows about: -Supporting additional services ------------------------------- -Please see the documentation for [cloudfoundry-connector](../spring-cloud-cloudfoundry-connector), since the same -mechanism applies to any cloud connector. +- PostgreSQL (Heroku) +- MySQL (ClearDB) +- Redis (RedisToGo, Redis Cloud, RedisGreen, openredis) +- MongoDB (MongoLab, MongoHQ, MongoSoup) +- RabbitMQ (CloudAMQP) -Limitations ------------ -Unlike CloudFoundry, Heroku exposes very little information about the app that is retrievable from -within a running app. For example, there is no good way to know the name of the application. -Therefore, if an app desires such info, it needs to make that available through environment variables. +Pull requests for adding additional services are welcome. + +##Supporting additional providers for existing service types + +To add support for discovering a new provider for a service already listed above, add +the provider's environment prefix to the list in `getEnvPrefixes()` on the +`ServiceInfoCreator` class. + +##Supporting new service types + +Extend [`HerokuServiceInfoCreator`](src/main/java/org/springframework/cloud/heroku/HerokuServiceInfoCreator.java) +with a creator for [your service's `ServiceInfo` class](../spring-cloud-core/#adding-service-discovery). + +Add the fully-qualified class name for your creator to + +```` +META-INF/service/org.springframework.cloud.heroku.HerokuServiceInfoCreator +```` + +##Limitations + +Unlike CloudFoundry, Heroku exposes very little information about the app that is retrievable +from within a running instance. For example, there is no good way to find the name of the +application. Therefore, if an app desires such info, it needs to make it available through +environment variables. + +To have sensible app name available through [`ApplicationInstanceInfo`](../core/src/main/java/org/springframework/cloud/app/ApplicationInstanceInfo.java), +set the `SPRING_CLOUD_APP_NAME` environment variable -To have sensible app name available through [`ApplicationInstanceInfo`](../core/src/main/java/org/springframework/cloud/app/ApplicationInstanceInfo.java) -(and associated properties), set the `SPRING_CLOUD_APP_NAME `variable - heroku config:add SPRING_CLOUD_APP_NAME=myappname --app myappname - + If this env variable is not set, the app name will be set to ``. \ No newline at end of file diff --git a/spring-cloud-localconfig-connector/README.md b/spring-cloud-localconfig-connector/README.md index 128d2c3..9efeb89 100644 --- a/spring-cloud-localconfig-connector/README.md +++ b/spring-cloud-localconfig-connector/README.md @@ -1,16 +1,21 @@ -Local-configuration connector for Spring Cloud -======================================= +#Spring Cloud local-configuration connector -Provides the ability to configure Spring Cloud services locally for development or testing. -The current implementation reads from Java properties only; in order to prevent dependencies -on the Spring Framework, the placeholder functionality is unavailable in the connector. -Pull requests for also inspecting environment variables are welcome. +This connector provides the ability to configure Spring Cloud services locally for development +or testing. The current implementation reads from Java properties only; in order to prevent +dependencies on the Spring Framework, the placeholder functionality is unavailable in the +connector. Pull requests for also inspecting environment variables are welcome. + +##Quick start -Quick start ------------ Since service URIs contain passwords and should not be stored in code, this connector does not attempt to read properties out of the classpath. You can provide a filename with service definitions -by setting the `spring.cloud.propertiesFile` property or by passing in an open `InputStream`: +by setting the `spring.cloud.propertiesFile` system property: + +```` +java -Dspring.cloud.propertiesFile=/path/to/spring-cloud.properties -jar my-app.jar +```` + + or by passing in an open `InputStream`: ````java InputStream propertyStream = new FileInputStream("/path/to/spring-cloud.properties"); @@ -26,10 +31,12 @@ spring.cloud.appId: myApp spring.cloud.database: mysql://user:pass@host:1234/dbname ```` -Service type is determined by the URI scheme. +Service type is determined by the URI scheme. The connector will activate if it finds a property +(in the system properties, supplied properties, or the file provided in `spring.cloud.propertiesFile`) +named `spring.cloud.appId`. + +##Property sources -Property sources ----------------- This connector first attempts to read the system properties generally and a system property named `spring.cloud.propertiesFile` specifically. If the system properties are not readable (the security manager denies `checkPropertiesAccess`), then they will be treated as empty. @@ -45,7 +52,7 @@ still read the stream, but the properties will have no effect on the connector service configuration. Calling this method multiple times will load the supplied streams onto the same `Properties` object, overwriting duplicates. -###Property order +###Property precedence To provide the maximum configuration flexibility, the connector will scan the available property sources in this order: @@ -56,25 +63,32 @@ property sources in this order: The last definition of a specific service ID wins. The connector will log a message at `WARN` if you override a service ID. -Activating the connector ------------------------- -The Spring Cloud core expects exactly one cloud connector to return `true` for -`isInMatchingCloud()`. This connector identifies the "local cloud" by the presence of -a property named `spring.cloud.appId`, which will be used in the `ApplicationInstanceInfo`. +##Activating the connector + +The Spring Cloud core expects exactly one cloud connector match the runtime environment. +This connector identifies the "local cloud" by the presence of a property named +`spring.cloud.appId`, which will be used in the `ApplicationInstanceInfo`. + +##Service definitions -Service definitions -------------------- If the connector is activated, it will iterate through all the available properties for keys matching the pattern `spring.cloud.{serviceId}`. Each value is interpreted as a URI to the services, and the type of service is determined from the scheme. All of the standard `UriBasedServiceInfo`s are supported. -Supporting additional services ------------------------------- -Please see the documentation for [cloudfoundry-connector](../spring-cloud-cloudfoundry-connector), since the same -mechanism applies to any cloud connector. +##Supporting additional services + +Extend [`LocalConfigServiceInfoCreator`](src/main/java/org/springframework/cloud/localconfig/LocalConfigServiceInfoCreator.java) +with a creator for [your service's `ServiceInfo` class](../spring-cloud-core/#adding-service-discovery). + +Add the fully-qualified class name for your creator to + +```` +META-INF/service/org.springframework.cloud.localconfig.LocalConfigServiceInfoCreator +```` + + +##Instance ID -Instance ID ------------ This connector will create a UUID for use as the instance ID, as Java does not provide any portable mechanism for reliably determining hostnames or PIDs. \ No newline at end of file