Using Netflix Eureka with Spring Cloud / Spring Boot microservices

I’ve been taking a look at this article on using Spring Cloud‘s integration/support for Netflix Eureka. I’ve started to put together a simple example using Eureka as a service registry for a couple of Spring Boot services, and what this would look like if deployed in Docker containers.

So far I’ve created the initial service that uses Spring Cloud’s @EnableEurekaServer annotation to start up the Eureka service.

Jumping ahead of the instructions, by default if you run this app it will attempt to reach out and find a local running Eureka server and register with it, but since this app is the Eureka server, you need to add config to tell the app not to do this by default. Otherwise you’ll see errors like:

com.sun.jersey.api.client.ClientHandlerException: java.net.ConnectException: Connection refused
at com.sun.jersey.client.apache4.ApacheHttpClient4Handler.handle(ApacheHttpClient4Handler.java:187) ~[jersey-apache-client4-1.19.1.jar:1.19.1]
at com.sun.jersey.api.client.filter.GZIPContentEncodingFilter.handle(GZIPContentEncodingFilter.java:123) ~[jersey-client-1.19.1.jar:1.19.1]
at com.netflix.discovery.EurekaIdentityHeaderFilter.handle(EurekaIdentityHeaderFilter.java:27) ~[eureka-client-1.6.2.jar:1.6.2]

Adding the recommended config per the article:

server:

  port: ${PORT:8761}

eureka:

  client:

    registerWithEureka: false

    fetchRegistry: false

    server: waitTimeInMsWhenSyncEmpty: 0

Now when I start up I see this:

2017-04-11 22:23:17.040  INFO 37607 - o.s.c.n.eureka.InstanceInfoFactory       : Setting initial instance status as: STARTING
2017-04-11 22:23:17.100  INFO 37607 - com.netflix.discovery.DiscoveryClient    : Initializing Eureka in region us-east-1
2017-04-11 22:23:17.101  INFO 37607 - com.netflix.discovery.DiscoveryClient    : Client configured to neither register nor query for data.
2017-04-11 22:23:17.110  INFO 37607 -com.netflix.discovery.DiscoveryClient    : Discovery Client initialized at timestamp 1491974597110 with initial instances count: 0
2017-04-11 22:23:17.192  INFO 37607 - c.n.eureka.DefaultEurekaServerContext    : Initializing ...
2017-04-11 22:23:17.195  INFO 37607 - c.n.eureka.cluster.PeerEurekaNodes       : Adding new peer nodes [http://localhost:8761/eureka/]
2017-04-11 22:23:17.359  INFO 37607 - c.n.d.provider.DiscoveryJerseyProvider   : Using JSON encoding codec LegacyJacksonJson
2017-04-11 22:23:17.359  INFO 37607 - c.n.d.provider.DiscoveryJerseyProvider   : Using JSON decoding codec LegacyJacksonJson
2017-04-11 22:23:17.359  INFO 37607 - c.n.d.provider.DiscoveryJerseyProvider   : Using XML encoding codec XStreamXml
2017-04-11 22:23:17.359  INFO 37607 - c.n.d.provider.DiscoveryJerseyProvider   : Using XML decoding codec XStreamXml
2017-04-11 22:23:22.479  INFO 37607 - c.n.eureka.cluster.PeerEurekaNodes       : Replica node URL:  http://localhost:8761/eureka/
2017-04-11 22:23:22.486  INFO 37607 - c.n.e.registry.AbstractInstanceRegistry  : Finished initializing remote region registries. All known remote regions: []
2017-04-11 22:23:22.486  INFO 37607 - c.n.eureka.DefaultEurekaServerContext    : Initialized

Hitting http://localhost:8761 I get the fancy Eureka dashboard:

Looks good so far! More to come later.

Github repo for the code so far is here.

Spring Boot: cannot find classfile ConfigurableApplicationContext (invalid LOC header)

Spring Boot with it’s maven starter dependencies is incredibly helpful to get a simple Spring Boot app up and running in no time, but occasionally you run into weird errors in Eclipse like:

The project was not built since its build path is incomplete. 
Cannot find the class file for 
org.springframework.context.ConfigurableApplicationContext. 
Fix the build path then try building this project

Or doing a mvn compile from your shell, something like:

[INFO] -------------------------------------------------------------
[ERROR] COMPILATION ERROR : 
[INFO] -------------------------------------------------------------
[ERROR] error reading /Users/kev/.m2/repository/org/apache/tomcat/embed/tomcat-embed-core/8.5.11/tomcat-embed-core-8.5.11.jar; invalid LOC header (bad signature)

Assuming you’re already using the Spring Boot Starter Web dependency:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

.. errors about Classes not found or errors reading .jars (‘invalid LOC header’) could be related to jars in your local .m2 repo being corrupt.

This is pretty easy to correct if you go into your ~/.m2/repository/ and delete your downloaded dependencies. You can be more specific in what you delete if you have something that you can easily identify as coming from a specific dependency.

Spring Roo @RooEntity from 1.1.x replaced in 1.2.x

If you have an older Spring Roo project created from Spring Roo 1.1.x and you’re trying to imported it to a more recent STS version and/or trying to upgrade to a later 1.2.x version of Spring Roo, you may be seeing these errors:

RooEntity cannot be resolved to a type

@RooEntity was replaced in Spring Roo 1.2.x with @RooJpaActiveRecord. Replace this in all your Entity classes and you should be good to go.

This is discussed in this thread.

@RooJpaActiveRecord is covered in the docs here.

Using Spring 3.1 Profiles

Profiles in Spring 3.1+ give you the ability to define conditional bean configurations based on a profile name, where one of your defined profiles is selected at runtime based on a selected profile name.

For example, if you have certain beans that are needed for running in a certain deployment environment but not needed for others (dev, test or prod), or if certain beans need to be configured differently between different environments, Profiles give you the ability to do exactly this.

If you’re using XML configuration, you use the profile=”…” attribute on the
<beans> element. For example:

<beans>
    <beans profile="dev">
        ... bean defs for dev profile here
    </beans>

    <beans profile="prod">
        ... bean defs for prod profile here
    </beans>
</beans>

To select your profile at runtime you’ve got a couple of different options – the easiest approach is to declare a system property, or -D parameter to your JVM at startup:

-Dspring.profiles.active=dev

When you initialize your Application Context, Spring automatically checks for this property and then will initialize only the beans declared for that specific profile. Beans not within a profile will still get initialized, or alternatively a profile with the name ‘default’ will get initialized if no other profile is specified.

Another approach if you need more control over the logic to determine which profile is active on startup, you can programmatically select your profile like this:

GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();

if( ... some logic here)
{
    ctx.getEnvironment().setActiveProfiles("example_profile_1");
}
else
{
    ctx.getEnvironment().setActiveProfiles("example_profile_2");
}

ctx.load("classpath:applicationContext.xml");
ctx.refresh();

Notice with this approach, since we’re not using the spring.profiles.active property, we don’t want to load the context xml file until after we’re determined programmatically which profile is active (based on some logic), then we set the profile with setActiveProfiles(), then load the xml, and refresh the context to initialize our beans for the selected profile.