28 November, 2013

Spring-boot JPA sample with auto-configured repository

Spring-boot allows to create a completely minimalistic applications.
For example, its auto-configuration ability raises and configures JPA and Hibernate-related stuff:
DataSource, Entity and Transaction Managers, Repositories.
With no manual configuration in your code or in xml files.

And the application code is getting smaller and smaller...

User.java
package sb; 
 
import javax.persistence.*; 
 
@Entity 
@Table(name = "sb_user") 
public class User { 
 
    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    public long id; 
    public String name; 
    public String alias; 
 
    public User() { 
    } 
 
    public User(long id, String name) {
        this.id = id; 
        this.name = name; 
    } 
} 
UserRepository.java
package sb;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

import java.util.List;

public interface UserRepository extends JpaRepository<User, Long> {

    @Query("SELECT u FROM User u WHERE u.alias IS NOT NULL")
    List<User> findAliased();
} 
UserController.java
package sb;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("user")
public class UserController {
    protected final Logger log = LoggerFactory.getLogger(getClass());

    @Autowired
    private UserRepository users;

    @RequestMapping("test")
    public String test() {
        log.info("Test");
        return "OK";
    }

    @RequestMapping("user")
    public User getUser(@RequestParam("id") long id) {
        log.info("Get user");
        return users.findOne(id);
    }

    @RequestMapping("users")
    public List<User> getUsers(@RequestParam("ids") List<Long> ids) {
    log.info("Get users");
        return users.findAll(ids);
    }

    @RequestMapping("aliased")
    public List<User> getAliasedUsers() {
    log.info("Get aliased users");
        return users.findAliased();
    }
} 
Application.java
package sb;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@EnableAutoConfiguration
@Configuration
@ComponentScan
public class Application {

    public static void main(String[] args) throws Throwable {
        new SpringApplication(Application.class).run(args);
    }
} 
application.properties
spring.datasource.driverClassName=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://srv0/test
spring.datasource.username=test
spring.datasource.password=test 
schema.sql
-- DROP TABLE sb_user;

CREATE TABLE sb_user
(
  id   SERIAL PRIMARY KEY    NOT NULL,
  name CHARACTER VARYING(65) NOT NULL,
  alias CHARACTER VARYING(20)
);

INSERT INTO sb_user (name) VALUES ('Ben Linus');
INSERT INTO sb_user (name) VALUES ('Claire Littleton');
INSERT INTO sb_user (name) VALUES ('Desmond Hume');
INSERT INTO sb_user (name) VALUES ('Frank Lapidus');
INSERT INTO sb_user (name, alias) VALUES ('Hugo Reyes', 'Hurley');
INSERT INTO sb_user (name) VALUES ('Jack Shephard');
INSERT INTO sb_user (name, alias) VALUES ('James Ford', 'Sawyer');
INSERT INTO sb_user (name) VALUES ('Jin-Soo Kwon');
INSERT INTO sb_user (name) VALUES ('Miles Straume');
INSERT INTO sb_user (name) VALUES ('Richard Alpert');
INSERT INTO sb_user (name) VALUES ('Sayid Jarrah');
INSERT INTO sb_user (name) VALUES ('Sun-Hwa Kwon');



Build and run command: gradle clean build runJar

Test urls:
http://localhost:8080/user/user?id=2
http://localhost:8080/user/users?ids=1,3,5,7
http://localhost:8080/user/aliased

26 November, 2013

Spring-boot memory usage

Typical spring-boot application - single jar file.
Size of the file is about 10+ megabytes (it contains another jars, classes and resources inside).
What about memory usage for this app?
I created sample with only one web @Controller and two webmethods: first - reports memory usage, second - runs Java Garbage Collector.

Memory usage after start (http://localhost:8080/test/mem):
max: 1,875,378,176 bytes
total: 355,729,408 bytes
free:  178,138,976 bytes
used:  177,590,432 bytes
and after GC (http://localhost:8080/test/rungc):
max: 1,875,378,176 bytes
total: 355,729,408 bytes
free:  331,821,496 bytes
used:   23,907,912 bytes
With spring-boot we have a lot of available memory)

Controller.java
package sb; 
 
import org.springframework.web.bind.annotation.RequestMapping; 
import org.springframework.web.bind.annotation.RestController; 
 
@RestController 
@RequestMapping("test") 
public class Controller { 
 
    @RequestMapping(value = "mem", produces = "text/plain")
    public String mem() { 
        long max = Runtime.getRuntime().maxMemory(); 
        long total = Runtime.getRuntime().totalMemory(); 
        long free = Runtime.getRuntime().freeMemory(); 
        long used = total - free; 
        return String.format("Memory:\n" +
                "max: %,d bytes\n" +
                "total: %,d bytes\n" +
                "free: %,d bytes\n" +
                "used: %,d bytes\n",
                max, total, free, used); 
    } 
 
    @RequestMapping("rungc") 
    public String rungc() { 
        Runtime.getRuntime().gc(); 
        return "Run GC";
    } 
} 


Application.java
package sb; 
 
import org.springframework.boot.SpringApplication; 
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 
import org.springframework.context.annotation.ComponentScan; 
import org.springframework.context.annotation.Configuration; 
 
@EnableAutoConfiguration 
@Configuration 
@ComponentScan 
public class Application { 
 
    public static void main(String[] args) throws Throwable {
        new SpringApplication(Application.class).run();
    } 
} 

build.gradle
buildscript { 
    repositories { 
        maven { url "http://repo.spring.io/libs-snapshot" }
    } 
    dependencies { 
        classpath("org.springframework.boot:spring-boot-gradle-plugin:0.5.0.M6")
    } 
} 
 
apply plugin: "java" 
apply plugin: "spring-boot" 
 
buildDir = "out" 
 
jar { 
    baseName = "sb-mem" 
    version = "0.1" 
} 
 
repositories { 
    mavenCentral() 
    maven { url "http://repo.spring.io/libs-snapshot" }
} 
 
dependencies { 
    def springBootVersion = '0.5.0.M6'
    compile("org.springframework.boot:spring-boot-starter-web:$springBootVersion")
} 

25 November, 2013

Spring-boot change log-file location

By default spring-boot writes logs to the /tmp/spring.log file.
But if you need another location - just set LOG_FILE variable in logback.xml configuration.

logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
 
    <property name="LOG_FILE" value="tmp/application.log"/>
 
    <include resource="org/springframework/boot/logging/logback/base.xml"/>
 
    <logger name="sb" level="DEBUG"/>
 
</configuration> 

Application.java
package sb;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Service;
 
@Configuration 
public class Application {
 
    @Service 
    static class TestBean {
        protected final Logger log = LoggerFactory.getLogger(getClass());
 
        void test() {
            log.debug("TestBean.test");
        } 
    } 
 
 
    public static void main(String[] args) throws Throwable {
        SpringApplication app = new SpringApplication(Application.class);
        ConfigurableApplicationContext ctx = app.run(args); 
 
        TestBean bean = ctx.getBean(TestBean.class);
        bean.test(); 
    } 
} 

build.gradle
buildscript {
    repositories { 
        maven { url "http://repo.spring.io/libs-snapshot" }
    } 
    dependencies { 
        classpath("org.springframework.boot:spring-boot-gradle-plugin:0.5.0.M6")
    } 
} 
 
apply plugin: "java"
apply plugin: "spring-boot"
 
buildDir = "out"
 
jar { 
    baseName = "sb-log-file"
    version = "0.1"
} 
 
repositories { 
    mavenCentral() 
    maven { url "http://repo.spring.io/libs-snapshot" }
} 
 
dependencies { 
    def springBootVersion = '0.5.0.M6'
    compile("org.springframework.boot:spring-boot-starter:$springBootVersion")
}