Showing posts with label spring-boot. Show all posts
Showing posts with label spring-boot. Show all posts

Thursday, January 7, 2016

Tutorial: connecting to Cassandra using Spring Boot and spring-data-cassandra.

Starting version 1.3, Spring Boot supports Cassandra auto configuration. That made using spring-cassandra-data even easier.

Prerequisites:
  •    Configured Spring Boot project version 1.3 or higher.
  •    Cassandra instance. On this instance, create a keyspace movies and in it table movie: 
       Create table movie:

CREATE TABLE movie (
  movieid text,
  name text,
  PRIMARY KEY ((movieid))
)
     and insert a couple of rows:

   insert into movie(movieid, name) values('id1', 'Star Wars');
   insert into movie(movieid, name) values('id2', 'Casablanca');

1. Add spring-data-cassandra dependency for Spring Boot:

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

2. Create a Java Bean with mapping to cassandra table:


@Table
public class Movie {
    @PrimaryKey
    private String movieid;

    @Column
    private String name;
        // add getters, setters, equals, hashCode

}

3.  Create Repository Interface for your bean:

 public interface MovieRepository extends TypedIdCassandraRepository<Movie,String> {
}


4.  Add basic  RestController which can be expanded on later:

@RestController
public class MovieController {
    @Autowired
    MovieRepository movieRepository;

    @RequestMapping(value="/movies")
    public Iterable<Movie> getTable1(){
        return movieRepository.findAll();
    }

}
5.  Update resources/application.properties with Cassandra connection details:

spring.data.cassandra.keyspace-name=...
spring.data.cassandra.contact-points=...
spring.data.cassandra.port=...
6.  Add mappingContext bean to your configuration with the package with mapped beans:


    @Bean
    public CassandraMappingContext mappingContext() throws Exception {
        BasicCassandraMappingContext bean = new BasicCassandraMappingContext();
        bean.setInitialEntitySet(CassandraEntityClassScanner.scan(("yourpackage")));

        return bean;
    }

7. Run your app. You should see the following at localhost:8080/movies:

[
  {
    "movieid": "id1",
    "name": "Star Wars"
  },
  {
    "movieid": "id2",
    "name": "Casablanca"
  }
]

Monday, December 7, 2015

Adding Custom metrics in Spring Boot

spring-boot-actuator makes it easy to add custom metrics to the Spring Boot application. For example, we would like to know, how many times a particular method was executed in a service.
What we would need to do is just autowire CounterService and add the call to counterService in the method:

    @Autowired
    private CounterService counterService;


    ...
    public void sampleMethod() {
        counterService.increment
             ("sampleservice.samplemethod.counter");
        ....

    }

If we start the application and access /metrics endpoint, we should see


 "counter.sampleservice.samplemethod.counter":...,


But what if we want to do something more sofisticated, for example, how many times the method was called in the last 5 minutes. Codahale metrics library gives us that functionality and it is integrated with Spring Boot.

You need to add dependency to your pom.xml:

    <dependency>
            <groupId>com.codahale.metrics</groupId>
            <artifactId>metrics-core</artifactId>
    </dependency> 

Then you autowire  MetricRegistry where you want to use metrics:

    @Autowired
    private MetricRegistry metricRegistry;

Now just register the metrics and start using it:
   private Meter meter;

    @PostConstruct
    public void init() {
        meter=metricRegistry.meter("example");
    }


The metrics will show up in the /metrics endpoint:

  "example.fiveMinuteRate": 0,
  "example.oneMinuteRate": 0,
  "example.count": 0,
  "example.fifteenMinuteRate": 0,

Wednesday, September 2, 2015

Migrating Spring Rest Service Application to Spring Boot (Part III)

You can read Part I and Part II here and here.

Spring Boot provides a good support for unit and integration testing.  I wanted to take an advantage of that.

First I added dependency for spring-boot-starter-test in my pom.xml,   removed dependencies for jUnit, Mockito and Hamcrest and ran the tests.

Things were not going as smooth as I hoped.

I was using mockMVC which was wired to my WebConfig class (via ContextConfiguration). But that class is no longer needed as Spring Boot takes care of everything. After some digging, adding @SpringApplicationConfiguration(classes = MockApp.class)  worked.

Running unit tests was very useful: it turned out that when removing WebConfig I removed important configuration: useRegisteredSuffixPatternMatch was set to true, which allowed rest requests with domain names in them to be processed correctly and prevented Spring from incorrectly interpreting .com as file extension.

However simply adding this configuration back did not work.  I found several blogs regarding the same issue. In the end the solution was simple, I added back WebConfig which extends WebMvcConfigurerAdapter with overridden configurePathMatch method, but removed @ComponentScan from it.

Tuesday, August 18, 2015

Migrating Spring Rest Service Application to Spring Boot (Part II)

As I mentioned in my previous post, things were not going smoothly. I got a weird java.lang.reflect.InvocationTargetException which was hard to explain. After some Googling I found an explanation.  Turns out the culprit was @Repository annotation in the Repository interfaces which is not needed there. Removing the annotation fixed the issue.

I ran the application and I was able to make REST calls  at localhost:8080/resturl. VICTORY!!!

Wait... Not so fast. I need to add v1/ in front resturl for versioning so the call would be like localhost:8080/v1/resturl .

Hmm. For that I needed to register DispatcherServlet and define the mapping:

I also needed to add a custom filter for Dispatcher Servlet. That was easy: Now I am ready to deploy. But how do I that?

Monday, August 17, 2015

Migrating Spring Rest Service Application to Spring Boot

I have a relatively  simple Spring-based REST Service application. I wanted to see how difficult it will be to migrate to Spring Boot.
Some of the details of the application I have:
  • Simple REST Service which uses cassandra-data in the backend
  • Configuration in web.xml which includes filters and listeners
  • Spring Configuration in Java 
  • Logback logging 
  • Maven configuration
I had an older version of maven installed. I had to install the latest version because Spring Boot supports maven 3.3 and higher.

With  this out of the way I added the new dependencies to pom.xml:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.2.5.RELEASE</version>
</parent>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
   .....
</dependencies>
I also commented out all spring dependencies I had execpt for spring-data-cassandra, which is not yet suppported directly by Spring Boot.

Then I created Application.java in the root package with the following code:
 
package basepackage;
import .....
 
@Configuration@EnableAutoConfiguration@ComponentScan@EnableCassandraRepositories(basePackages = { "basepackage" })
public class Application  extends SpringBootServletInitializer{


    @Override    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Application.class);
    }

    public static void main(String[] args) throws Exception {
        SpringApplication.run(Application.class, args);
    }
.... 
}

and removed @Configuration and @ComponentScan annotations from WebConfig, which did not have anything else in it.

After that I ran:

 mvn spring-boot:run

and application compiled, started and then spit out a nice big stack trace:

java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:483)
        at org.springframework.boot.maven.RunMojo$LaunchRunner.run(RunMojo.java:418)
        at java.lang.Thread.run(Thread.java:745)
Caused by: org.springframework.beans.factory.BeanCreationException: 
To be continued ....