From e1c3dae8a1ea6bcca065c1f6093e5475c90bac94 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Thu, 9 May 2013 09:06:12 +0100 Subject: [PATCH] Restore README for Actuator --- spring-bootstrap-actuator/README.md | 382 ++++++++++++++++++++++++++++ 1 file changed, 382 insertions(+) create mode 100644 spring-bootstrap-actuator/README.md diff --git a/spring-bootstrap-actuator/README.md b/spring-bootstrap-actuator/README.md new file mode 100644 index 0000000000..e666934301 --- /dev/null +++ b/spring-bootstrap-actuator/README.md @@ -0,0 +1,382 @@ +# Spring Bootstrap Actuator + +Minimum fuss for getting applications up and running in production, +and in other environments. There is a strong emphasis on implementing +RESTful web services but many features are more generic than that. + +|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 | + +For a quick introduction and to get started quickly with a new +project, carry on reading. For more in depth coverage of the features +of Spring Bootstrap Actuator, go to the +[Feature Guide](https://github.com/SpringSource/spring-bootstrap/tree/master/spring-bootstrap-actuator/docs/Features.md). + +# 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 + + + +## A basic project + +If you are using Maven create a really simple `pom.xml` with 2 dependencies: + + + 4.0.0 + com.mycompany + myproject + 1.0.0-SNAPSHOT + jar + + org.springframework.bootstrap + spring-bootstrap-applications + 0.0.1-SNAPSHOT + + + + org.springframework.bootstrap + spring-bootstrap-web-application + + + org.springframework.bootstrap + spring-bootstrap-service + + + + + + org.apache.maven.plugins + maven-shade-plugin + + + + + +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 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. + + + com.mycompany.sample.SampleController + + +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. + +## 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 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 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: + + + org.springframework.security + spring-security-javaconfig + 1.0.0.BUILD-SNAPSHOT + + +(Spring Security java config is still work in progress so we have used +a snapshot. Beware of sudden changes.) + + + +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: + + + org.springframework + spring-jdbc + + + org.hsqldb + hsqldb + + +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 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.