9 changed files with 110 additions and 607 deletions
@ -1,177 +0,0 @@
@@ -1,177 +0,0 @@
|
||||
# Spring Bootstrap |
||||
|
||||
Spring Bootstrap is "Spring for Snowboarders". If you are kewl, or |
||||
just impatient, and you want to use Spring, then this is the place to |
||||
be. Spring Bootstrap is a toolkit and runtime platform that will get |
||||
you up and running with Spring-powered, production-grade applications |
||||
and services with absolute minimum fuss. It takes an opinionated view |
||||
of the Spring family so that new and existing users can quickly get to |
||||
the bits they need. Assumes no knowledge of the Java development |
||||
ecosystem. Absolutely no code generation and no XML (unless you really |
||||
want it). |
||||
|
||||
The goals are: |
||||
|
||||
* Radically faster and widely accessible getting started experience |
||||
for Spring development |
||||
* Be opinionated out of the box, but get out of the way quickly as |
||||
requirements start to diverge from the defaults |
||||
* Provide a range of non-functional features that are common to large |
||||
classes of projects (e.g. embedded servers, security, metrics, |
||||
health checks, externalized configuration) |
||||
* First class support for REST-ful services, modern web applications, |
||||
batch jobs, and enterprise integration |
||||
* Applications that adapt their behaviour or configuration to their |
||||
environment |
||||
* Optionally use Groovy features like DSLs and AST transformations to |
||||
accelerate the implementation of basic business requirements |
||||
|
||||
## Installing |
||||
You need to build from source for now, but when it's done instructions will look like this: |
||||
|
||||
1) Get Java. Download and install the Java SDK from www.java.com |
||||
|
||||
2) Get Spring |
||||
|
||||
$ curl -s try.spring.io | bash |
||||
|
||||
or use the Windows installer |
||||
|
||||
3) Get to Work! |
||||
|
||||
$ cat > app.groovy |
||||
@Controller |
||||
class ThisWillActuallyRun { |
||||
@RequestMapping("/") |
||||
@ResponseBody |
||||
String home() { |
||||
return "Hello World!" |
||||
} |
||||
} |
||||
$ spring run app.groovy |
||||
$ curl localhost:8080 |
||||
Hello World! |
||||
|
||||
|
||||
## What? It's Groovy then? or like Grails? or another Roo? |
||||
|
||||
There is a command line tool that uses Groovy underneath so that we |
||||
can present simple snippets that can just run just like the slimline |
||||
`app.groovy` example above. Groovy makes this really easy. |
||||
|
||||
If you don't want to use the command line tool, or you would rather |
||||
work using Java and an IDE you can. Just add a `main()` method that |
||||
calls `SpringApplication` and add `@EnableAutoConfiguration`: |
||||
|
||||
|
||||
import org.springframework.stereotype.*; |
||||
import org.springframework.web.bind.annotation.*; |
||||
import org.springframework.bootstrap.context.annotation.*; |
||||
|
||||
@Controller |
||||
@EnableAutoConfiguration |
||||
public class SampleController { |
||||
|
||||
@RequestMapping("/") |
||||
@ResponseBody |
||||
String home() { |
||||
return "Hello World!" |
||||
} |
||||
|
||||
public static void main(String[] args) throws Exception { |
||||
SpringApplication.run(SampleController.class, args); |
||||
} |
||||
|
||||
} |
||||
|
||||
## Spring Bootstrap Themes |
||||
|
||||
There are a number of themes in Bootstrap. Here are the important |
||||
ones: |
||||
|
||||
### The Spring CLI |
||||
|
||||
The 'spring' command line application compiles and runs Groovy source, |
||||
making it super easy to write the absolute minimum of code to get an |
||||
application running. Spring CLI can also watch files, automatically |
||||
recompiling and restarting when they change. |
||||
|
||||
### Bootstrap Core |
||||
|
||||
The main library providing features that support the other parts of |
||||
Spring Bootstrap. Features include: |
||||
|
||||
* `SpringApplication` - a class with static convenience methods that |
||||
make it really easy to write a standalone Spring Application. Its |
||||
sole job is to create and refresh an appropriate Spring |
||||
`ApplicationContext`. |
||||
* Embedded web applications with a choice of container (Tomcat or |
||||
Jetty for now) |
||||
* `@EnableAutoConfigure` is an annotation that triggers |
||||
auto-configuration of the Spring context. Auto-configuration |
||||
attempts to guess what beans a user might want based on their |
||||
classpath. For example, If a 'HSQLDB' is on the classpath the user |
||||
probably wants an in-memory database to be |
||||
defined. Auto-configuration will back away as the user starts to |
||||
define their own beans. |
||||
* `@Conditional` is an annotation in Spring 4.0 that allows you to |
||||
control which parts of an application are used at runtime. Spring |
||||
Bootstrap provides some concrete implementations of conditional |
||||
configuration, e.g. `@ConditionalOnBean`, |
||||
`@ConditionalOnMissingBean` and `@ConditionalOnClass`. |
||||
|
||||
### Spring Bootstrap Service |
||||
|
||||
<!-- FIXME: change the name --> |
||||
|
||||
Spring Bootstrap Service uses auto-configuration features to decorate |
||||
your application with features that make it instantly deployable and |
||||
supportable in production. For instance if you are writing a JSON web |
||||
service then it will provide a server, security, logging, externalized |
||||
configuration, management endpoints, an audit abstraction, and more. |
||||
If you want to switch off the built in features, or extend or replace |
||||
them, it makes that really easy as well. |
||||
|
||||
### Spring Bootstrap Applications |
||||
|
||||
<!-- FIXME: change the name --> |
||||
|
||||
Spring Bootstrap Applications are a set of convenient dependency |
||||
descriptors that you can include in your application. You get a |
||||
one-stop-shop for all the Spring and related technology that you need |
||||
without having to hunt through sample code and copy paste loads of |
||||
dependency descriptors. For example, if you want to get started using |
||||
Spring and JPA for database access just include one dependency in your |
||||
project, and you are good to go. |
||||
|
||||
## Building the code |
||||
Use maven to build the source code. |
||||
|
||||
$ mvn clean install |
||||
|
||||
## Importing into eclipse |
||||
You can use m2e or `maven eclipse:eclipse`. |
||||
|
||||
Project specific settings are configured for source formatting. If you |
||||
are using m2e you can follow these steps to install eclipse support |
||||
for formatting: |
||||
|
||||
* Select `Install new software` from the `help` menu |
||||
* Click `Add...` to add a new repository |
||||
* Click the `Archive...` button |
||||
* Select `org.eclipse.m2e.maveneclipse.site-0.0.1-SNAPSHOT-site.zip` |
||||
from the `eclipse` folder in this checkout |
||||
* Install "Maven Integration for the maven-eclipse-plugin" |
||||
|
||||
Or if you prefer you can import settings manually from the `/eclipse` folder. |
||||
|
||||
## Samples |
||||
The following samples are included. To run use `java -jar target/<archive>.jar` |
||||
|
||||
* spring-bootstrap-simple-sample - A simple command line application |
||||
* spring-bootstrap-jetty-sample - Embedded Jetty |
||||
* spring-bootstrap-tomcat-sample - Embedded Tomcat |
||||
* spring-bootstrap-service-sample - Simple REST service with production features |
||||
* spring-batch-sample - Define and run a Batch job in a few lines of code |
||||
* spring-bootstrap-data-sample - Spring Data JPA + Hibernate + HSQLDB |
||||
|
||||
@ -1,387 +0,0 @@
@@ -1,387 +0,0 @@
|
||||
<style> |
||||
table |
||||
{ |
||||
border-collapse:collapse; |
||||
} |
||||
table,th, td |
||||
{ |
||||
border: 1px solid black; |
||||
} |
||||
</style> |
||||
|
||||
# Spring Bootstrap Services |
||||
|
||||
Minimum fuss for getting RESTful services up and running in |
||||
production, and in other environments. |
||||
|
||||
|Feature |Implementation |Notes | |
||||
|---|---|---| |
||||
|Server |Tomcat or Jetty | Whatever is on the classpath | |
||||
|REST |Spring MVC | | |
||||
|Security |Spring Security | If on the classpath | |
||||
|Logging |Logback, Log4j or JDK | Whatever is on the classpath. Sensible defaults. | |
||||
|Database |HSQLDB or H2 | Per classpath, or define a DataSource to override | |
||||
|Externalized configuration | Properties or YAML | Support for Spring profiles. Bind automatically to @Bean. | |
||||
|Audit | Spring Security and Spring ApplicationEvent |Flexible abstraction with sensible defaults for security events | |
||||
|Validation | JSR-303 |If on the classpath | |
||||
|Management endpoints | Spring MVC | Health, basic metrics, request tracing, shutdown, thread dumps | |
||||
|Error pages | Spring MVC | Sensible defaults based on exception and status code | |
||||
|JSON |Jackson 2 | | |
||||
|ORM |Spring Data JPA | If on the classpath | |
||||
|Batch |Spring Batch | If enabled and on the classpath | |
||||
|Integration Patterns |Spring Integration | If on the classpath | |
||||
|
||||
# Getting Started |
||||
|
||||
You will need Java (6 at least) and a build tool (Maven is what we use |
||||
below, but you are more than welcome to use gradle). These can be |
||||
downloaded or installed easily in most operating systems. For Ubuntu: |
||||
|
||||
$ sudo apt-get install openjdk-6-jdk maven |
||||
|
||||
<!--FIXME: short instructions for Mac.--> |
||||
|
||||
## A basic project |
||||
|
||||
If you are using Maven create a really simple `pom.xml` with 2 dependencies: |
||||
|
||||
<project> |
||||
<modelVersion>4.0.0</modelVersion> |
||||
<groupId>com.mycompany</groupId> |
||||
<artifactId>myproject</artifactId> |
||||
<version>1.0.0-SNAPSHOT</version> |
||||
<packaging>jar</packaging> |
||||
<parent> |
||||
<groupId>org.springframework.bootstrap</groupId> |
||||
<artifactId>spring-bootstrap-applications</artifactId> |
||||
<version>0.0.1-SNAPSHOT</version> |
||||
</parent> |
||||
<dependencies> |
||||
<dependency> |
||||
<groupId>org.springframework.bootstrap</groupId> |
||||
<artifactId>spring-bootstrap-web-application</artifactId> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.springframework.bootstrap</groupId> |
||||
<artifactId>spring-bootstrap-service</artifactId> |
||||
</dependency> |
||||
</dependencies> |
||||
<build> |
||||
<plugins> |
||||
<plugin> |
||||
<groupId>org.apache.maven.plugins</groupId> |
||||
<artifactId>maven-shade-plugin</artifactId> |
||||
</plugin> |
||||
</plugins> |
||||
</build> |
||||
</project> |
||||
|
||||
If you like Gradle, that's fine, and you will know what to do with |
||||
those dependencies. The first dependency adds Spring Bootstrap auto |
||||
configuration and the Jetty container to your application, and the |
||||
second one adds some more opinionated stuff like the default |
||||
management endpoints. If you prefer Tomcat you can just add the |
||||
embedded Tomcat jars to your classpath instead of Jetty. |
||||
|
||||
You should be able to run it already: |
||||
|
||||
$ mvn package |
||||
$ java -jar target/myproject-1.0.0-SNAPSHOT.jar |
||||
|
||||
Then in another terminal |
||||
|
||||
$ curl localhost:8080/healthz |
||||
ok |
||||
$ curl localhost:8080/varz |
||||
{"counter.status.200.healthz":1.0,"gauge.response.healthz":10.0,"mem":120768.0,"mem.free":105012.0,"processors":4.0} |
||||
|
||||
`/healthz` is the default location for the health endpoint - it tells |
||||
you if the application is running and healthy. `/varz` is the default |
||||
location for the metrics endpoint - it gives you basic counts and |
||||
response timing data by default but there are plenty of ways to |
||||
customize it. You can also try `/trace` and `/dump` to get some |
||||
interesting information about how and what your app is doing. |
||||
|
||||
What about the home page? |
||||
|
||||
$ curl localhost:8080/ |
||||
{"status": 404, "error": "Not Found", "message": "Not Found"} |
||||
|
||||
That's OK, we haven't added any business content yet. But it shows |
||||
that there are sensible defaults built in for rendering HTTP and |
||||
server-side errors. |
||||
|
||||
## Adding a business endpoint |
||||
|
||||
To do something useful to your business you need to add at least one |
||||
endpoint. An endpoint can be implemented as a Spring MVC |
||||
`@Controller`, e.g. |
||||
|
||||
@Controller |
||||
@EnableAutoConfiguration |
||||
public class SampleController { |
||||
|
||||
@RequestMapping("/") |
||||
@ResponseBody |
||||
public Map<String, String> helloWorld() { |
||||
return Collections.singletonMap("message", "Hello World"); |
||||
} |
||||
|
||||
public static void main(String[] args) throws Exception { |
||||
SpringApplication.run(SampleController.class, args); |
||||
} |
||||
|
||||
} |
||||
|
||||
You can launch that straight away using the Spring Bootstrap CLI |
||||
(without the `@EnableAutoConfiguration` and even without the import |
||||
statements that your IDE will add if you are using one), or you can |
||||
use the main method to launch it from your project jar. Just add a |
||||
`start-class` in the properties section of the `pom` above pointing to |
||||
the fully qualified name of your `SampleController`, e.g. |
||||
|
||||
<properties> |
||||
<start-class>com.mycompany.sample.SampleController</start-class> |
||||
</properties> |
||||
|
||||
and re-package: |
||||
|
||||
$ mvn package |
||||
$ java -jar target/myproject-1.0.0-SNAPSHOT.jar |
||||
$ curl localhost:8080/ |
||||
{"message": "Hello World"} |
||||
|
||||
## Running the application |
||||
|
||||
You can package the app and run it as a jar (as above) and that's very |
||||
convenient for production usage. Or there are other options, many of |
||||
which are more convenient at development time. Here are a few: |
||||
|
||||
1. Use the Maven exec plugin, e.g. |
||||
|
||||
$ mvn exec:java |
||||
|
||||
2. Run directly in your IDE, e.g. Eclipse or IDEA let you right click |
||||
on a class and run it. |
||||
|
||||
3. Use a different Maven plugin. |
||||
|
||||
4. Find feature in Gradle that does the same thing. |
||||
|
||||
5. Use the Spring executable. <!--FIXME: document this maybe.--> |
||||
|
||||
## Externalizing configuration |
||||
|
||||
Spring Bootstrap likes you to externalize your configuration so you |
||||
can work with the same application code in different environments. To |
||||
get started with this you create a file in the root of your classpath |
||||
(`src/main/resources` if using Maven) - if you like YAML you can call |
||||
it `application.yml`, e.g.: |
||||
|
||||
server: |
||||
port: 9000 |
||||
management: |
||||
port: 9001 |
||||
logging: |
||||
file: target/log.out |
||||
|
||||
or if you like Java `Properties` files, you can call it |
||||
`application.properties`, e.g.: |
||||
|
||||
server.port: 9000 |
||||
management.port: 9001 |
||||
logging.file: target/log.out |
||||
|
||||
Those examples are properties that Spring Bootstrap itself binds to |
||||
out of the box, so if you make that change and run the app again, you |
||||
will find the home page on port 9000 instead of 8080: |
||||
|
||||
$ curl localhost:9000/ |
||||
{"message": "Hello World"} |
||||
|
||||
and the management endpoints on port 9001 instead of 8080: |
||||
|
||||
$ curl localhost:9001/healthz |
||||
ok |
||||
|
||||
To externalize business configuration you can simply add a default |
||||
value to your configuration file, e.g. |
||||
|
||||
server: |
||||
port: 9000 |
||||
management: |
||||
port: 9001 |
||||
logging: |
||||
file: target/log.out |
||||
service: |
||||
message: Awesome Message |
||||
|
||||
and then bind to it in the application code. The simplest way to do |
||||
that is to simply refer to it in an `@Value` annotation, e.g. |
||||
|
||||
@Controller |
||||
@EnableAutoConfiguration |
||||
public class SampleController { |
||||
|
||||
@Value("${service.message:Hello World}") |
||||
private String value = "Goodbye Everypone" |
||||
|
||||
@RequestMapping("/") |
||||
@ResponseBody |
||||
public Map<String, String> helloWorld() { |
||||
return Collections.singletonMap("message", message); |
||||
} |
||||
|
||||
... |
||||
} |
||||
|
||||
That's a little bit confusing because we have provided a message value |
||||
in three different places - in the external configuration ("Awesome |
||||
Message"), in the `@Value` annotation after the colon ("Hello World"), |
||||
and in the filed initializer ("Goodbye Everyone"). That was only to |
||||
show you how and you only need it once, so it's your choice (it's |
||||
useful for unit testing to have the Java initializer as well as the |
||||
external value). Note that the YAML object is flattened using period |
||||
separators. |
||||
|
||||
For simple Strings where you have sensible defaults `@Value` is |
||||
perfect, but if you want more and you like everything strongly typed |
||||
then you can have Spring bind the properties and validate them |
||||
automatically in a separate value object. For instance: |
||||
|
||||
// ServiceProperties.java |
||||
@ConfigurationProperties(name="service") |
||||
public class ServiceProperties { |
||||
private String message; |
||||
private int value = 0; |
||||
... getters and setters |
||||
} |
||||
|
||||
// SampleController.java |
||||
@Controller |
||||
@EnableAutoConfiguration |
||||
@EnableConfigurationProperties(ServiceProperties.class) |
||||
public class SampleController { |
||||
|
||||
@Autowired |
||||
private ServiceProperties properties; |
||||
|
||||
@RequestMapping("/") |
||||
@ResponseBody |
||||
public Map<String, String> helloWorld() { |
||||
return Collections.singletonMap("message", properties.getMessage()); |
||||
} |
||||
|
||||
... |
||||
} |
||||
|
||||
When you ask to |
||||
`@EnableConfigurationProperties(ServiceProperties.class)` you are |
||||
saying you want a bean of type `ServiceProperties` and that you want |
||||
to bind it to the Spring Environment. The Spring Environment is a |
||||
collection of name-value pairs taken from (in order of decreasing |
||||
precedence) 1) the command line, 2) the external configuration file, |
||||
3) System properties, 4) the OS environment. Validation is done based |
||||
on JSR-303 annotations by default provided that library (and an |
||||
implementation) is on the classpath. |
||||
|
||||
## Adding security |
||||
|
||||
If you add Spring Security java config to your runtime classpath you |
||||
will enable HTTP basic authentication by default on all the endpoints. |
||||
In the `pom.xml` it would look like this: |
||||
|
||||
<dependency> |
||||
<groupId>org.springframework.security</groupId> |
||||
<artifactId>spring-security-javaconfig</artifactId> |
||||
<version>1.0.0.BUILD-SNAPSHOT</version> |
||||
</dependency> |
||||
|
||||
(Spring Security java config is still work in progress so we have used |
||||
a snapshot. Beware of sudden changes.) |
||||
|
||||
<!--FIXME: update Spring Security to full release --> |
||||
|
||||
Try it out: |
||||
|
||||
$ curl localhost:8080/ |
||||
{"status": 403, "error": "Forbidden", "message": "Access Denied"} |
||||
$ curl user:password@localhost:8080/ |
||||
{"message": "Hello World"} |
||||
|
||||
The default auto configuration has an in-memory user database with one |
||||
entry. If you want to extend or expand that, or point to a database |
||||
or directory server, you only need to provide a `@Bean` definition for |
||||
an `AuthenticationManager`, e.g. in your `SampleController`: |
||||
|
||||
@Bean |
||||
public AuthenticationManager authenticationManager() throws Exception { |
||||
return new AuthenticationBuilder().inMemoryAuthentication().withUser("client") |
||||
.password("secret").roles("USER").and().and().build(); |
||||
} |
||||
|
||||
Try it out: |
||||
|
||||
$ curl user:password@localhost:8080/ |
||||
{"status": 403, "error": "Forbidden", "message": "Access Denied"} |
||||
$ curl client:secret@localhost:8080/ |
||||
{"message": "Hello World"} |
||||
|
||||
## Adding a database |
||||
|
||||
Just add `spring-jdbc` and an embedded database to your dependencies: |
||||
|
||||
<dependency> |
||||
<groupId>org.springframework</groupId> |
||||
<artifactId>spring-jdbc</artifactId> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.hsqldb</groupId> |
||||
<artifactId>hsqldb</artifactId> |
||||
</dependency> |
||||
|
||||
Then you will be able to inject a `DataSource` into your controller: |
||||
|
||||
@Controller |
||||
@EnableAutoConfiguration |
||||
@EnableConfigurationProperties(ServiceProperties.class) |
||||
public class SampleController { |
||||
|
||||
private JdbcTemplate jdbcTemplate; |
||||
|
||||
@Autowired |
||||
public SampleController(DataSource dataSource) { |
||||
this.jdbcTemplate = new JdbcTemplate(dataSource); |
||||
} |
||||
|
||||
@RequestMapping("/") |
||||
@ResponseBody |
||||
public Map<String, String> helloWorld() { |
||||
return jdbcTemplate.queryForMap("SELECT * FROM MESSAGES WHERE ID=?", 0); |
||||
} |
||||
|
||||
... |
||||
} |
||||
|
||||
The app will run (going back to the default security configuration): |
||||
|
||||
$ curl user:password@localhost:8080/ |
||||
{"error":"Internal Server Error", "status":500, "exception":...} |
||||
|
||||
but there's no data in the database yet and the `MESSAGES` table |
||||
doesn't even exist, so there's an error. One easy way to fix it is |
||||
to provide a `schema.sql` script in the root of the classpath, e.g. |
||||
|
||||
create table MESSAGES ( |
||||
ID BIGINT NOT NULL PRIMARY KEY, |
||||
MESSAGE VARCHAR(255) |
||||
); |
||||
INSERT INTO MESSAGES (ID, MESSAGE) VALUES (0, 'Hello Phil'); |
||||
|
||||
Now when you run the app you get a sensible response: |
||||
|
||||
$ curl user:password@localhost:8080/ |
||||
{"ID":0, "MESSAGE":"Hello Phil"} |
||||
|
||||
Obviously, this is only the start, but hopefully you have a good grasp |
||||
of the basics and are ready to try it out yourself. |
||||
@ -0,0 +1,54 @@
@@ -0,0 +1,54 @@
|
||||
/* |
||||
* Copyright 2012-2013 the original author or authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package org.springframework.bootstrap.actuate.properties; |
||||
|
||||
import java.net.InetAddress; |
||||
import java.util.Collections; |
||||
|
||||
import org.junit.Test; |
||||
import org.springframework.beans.MutablePropertyValues; |
||||
import org.springframework.bootstrap.bind.RelaxedDataBinder; |
||||
|
||||
import static org.junit.Assert.assertEquals; |
||||
import static org.junit.Assert.assertFalse; |
||||
|
||||
/** |
||||
* Externalized configuration for server properties |
||||
* |
||||
* @author Dave Syer |
||||
* |
||||
*/ |
||||
public class ServerPropertiesTests { |
||||
|
||||
private ServerProperties properties = new ServerProperties(); |
||||
|
||||
@Test |
||||
public void testAddressBinding() throws Exception { |
||||
RelaxedDataBinder binder = new RelaxedDataBinder(this.properties, "server"); |
||||
binder.bind(new MutablePropertyValues(Collections.singletonMap("server.address", |
||||
"127.0.0.1"))); |
||||
assertFalse(binder.getBindingResult().hasErrors()); |
||||
assertEquals(InetAddress.getLocalHost(), this.properties.getAddress()); |
||||
} |
||||
|
||||
@Test |
||||
public void testPortBinding() throws Exception { |
||||
new RelaxedDataBinder(this.properties, "server").bind(new MutablePropertyValues( |
||||
Collections.singletonMap("server.port", "9000"))); |
||||
assertEquals(9000, this.properties.getPort()); |
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue