I've always said that Spring, Maven, and IntelliJ are my weapons of choice. People's response on more than one occasion has been that I'm far too old fashioned and conservative. I don't care, they might be right, but to de-risk any project it's always a good idea to not bring on more than 10% new technology:
Stick to what you know and only experiment with one or two new components.
Two years ago, when I was building the backend for a doorbell app, I thought it might be a good idea to try out Docker. I quickly realised that building a traditional WAR application deployed in Tomcat or Jetty made less sense and I started by looking at what Spring Boot had to offer.
Turns out, a lot!
So here are my 7 favourite features that fit perfectly in a modern microservices environment.
Externalised configuration
This isn't a particularly big thing, but it's a feature that tends to be overlooked by newcomers and it can be very useful. Spring Boot is flexible and well documented on this one. For instance, you can choose to either use ENVIRONMENT_VARIABLES
, --command-line-arguments
or -Dsystem.properties
, which you'll finally inject on your fields like this:
@Value("${cassandra.password}")
private String password;
For more details take a look at https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html.
Actuator
In the quest for giving you production readiness, Spring created Actuator. For a truly production ready application you need to be able to look into the application beyond whatever user faced interface your application is serving.
One of those things are health checks, which are pretty easy to create yourself.
public class MyService extends AbstractHealthIndicator {
// …
@Override
protected void doHealthCheck(Health.Builder builder) throws Exception {
final String echo = pushNotifier.echo("Abcd");
if (!echo.equals("\"dcbA\"")) {
throw new RuntimeException("Response mismatch. Was " + echo);
}
builder.up();
}
}
A builder.up()
will tell that everythings fine, while throwing an Exception or builder.down()
will tell that something isn't right. Add .withDetail("…")
to give some more information. Finally, the health of the application can be accessed at http://localhost:8080/health
.
Also, things like configuration can be exposed over an HTTP endpoint. Yes, keys that include common words for things that are protected are blanked out.
For more information about Actuator, take a look at https://spring.io/guides/gs/actuator-service/
Fat jars
Fat jars aren't a new thing. The reason why I mention them here though, is that they are a very good alternative to using Docker images.
Excuse me? Did you just say an alternative to Docker?!
Yes, I did. It has nothing to do with Docker itself, but as LinkedIn revealed some time ago, cgroups can cause unusually long pauses during garbage collection. And also, sometimes distributing simple files can be a lot easier than the alternative. Who said a shared NFS volume containing all jar files across all hosts? Or some modern peer to peer files sharing is a bad thing?
Spring offers a nice Maven plugin that does everything for you. It's all set up for you if you use the Spring Initializr.
Auto configuration
Or convention over configuration. This is one of the criticisms of Spring Boot:
Too much magic going on.
But fear not. Java is a static and old-fashioned language, where you can click your way around (assuming that you aren't stuck with something like Emacs). Just take a look at the org.springframework.boot.autoconfigure.SpringBootApplication
annotation. Amongst others it imports two other annotations
@EnableAutoConfiguration
@ComponentScan(excludeFilters = @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class))
public @interface SpringBootApplication {
// …
}
First of all, @ComponentScan
enables scanning for beans in the current package and all sub packages as long as you give them the usual @Component
annotation.
@EnableAutoConfiguration
is slightly more complicated, but basically it will make sure that Spring is scanning the classpath for all spring.factories
property files, which in turn points to Spring configuration annotated classes. Again, if this is too much magic for you, give your application a DEBUG=true
environment variable to get a report on what's actually going on.
For more details on this subject, I recommend watching this Spring Tips video.
Feign Integration
You might have heard about Netflix. It's a video streaming company, but it turns out they're also doing a lot of nice tech, and even better, they're open sourcing it. One of these components is Feign. Feign is basically an HTTP client. Nothing fancy about that, we have plenty of those around for Java already and I'm not really opinionated about the library itself, but it is nicely integrated into Spring. So basically, you start by adding the org.springframework.cloud:spring-cloud-starter-feign
dependency from Maven Central. But why they haven't added auto configuration is beyond me. Anyway, just add an EnableFeignClients
to your configuration class. The HTTP client itself looks something like this:
interface GitHub {
@RequestLine("GET /repos/{owner}/{repo}/contributors")
List contributors(@Param("owner") String owner, @Param("repo") String repo);
}
Spring does the rest for you, just inject the GitHub
interface wherever you need it. Oh and since it's a part of the Spring Cloud project, it'll also give you a circuit breaker, retry and eventual metrics.
Git commit id
Being able to see what revision of your application you're actually running is of really great value. If you add the git-commit-id-plugin
maven plugin and Spring Actuator, the exact git commit id will be expose through the /info
actuator endpoint.
pl.project13.maven
git-commit-id-plugin
Josh Long
Finally there's the whole community of people using Spring and contributing to it. In particular, I want to point out the work of Josh Long. With weekly updates about what's going on in the community and small videos with Spring Tips, he is a great resource for keeping up with all the new stuff.