Showing posts with label Spring. Show all posts
Showing posts with label Spring. Show all posts

Saturday, March 11, 2017

Spring RestTemplate useful hints

RestTemplate a widely used client tool from Spring framework. Here are some useful hints when using Spring RestTemplate.

  • How to use basic authentication with RestTemplate?
  • How to add arbitrary Http header, e.g.”Content-Type”, “Accept”, with RestTemplate?
  • How to bypass(not solve) Https error “java.security.cert.CertificateException: No name matching <some url> found”?

1. Basic authentication for RestTemplate

  RestTemplate restTemplate = new RestTemplate();

  // set username/password for http basic authentication
  restTemplate.getInterceptors().add(new BasicAuthorizationInterceptor("myUserName","myPassword"));

  // use restTemplate to send requst
  // .....

2. Add  arbitrary http header for RestTemplate

Like above for adding basic authentication, this time need your own ClientHttpRequestInterceptor implementation. (BasicAuhorizationInterceptor for basic authentication is already predefined in spring). 

  RestTemplate restTemplate = new RestTemplate();

  // set content-type=application/json http header
  restTemplate.getInterceptors().add(new ClientHttpRequestInterceptor() {
    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
      request.getHeaders().add("Content-Type", MediaType.APPLICATION_FORM_URLENCODED.toString());
      return execution.execute(request, body);
    }
  });
		
  // use restTemplate to send requst
  // .....

For java8 +, using lamda can make it look more neat.  Functionally they are equivalent.

  RestTemplate restTemplate = new RestTemplate();

  // set content-type=application/json http header, use lamda 
  restTemplate.getInterceptors().add((request, body, execution) -> {
    request.getHeaders().add("Content-Type", MediaType.APPLICATION_FORM_URLENCODED.toString());
    return execution.execute(request, body);
  });
		
  // use restTemplate to send requst
  // .....

Above example add content-type to http header, it can be used to add anything you like to http header.

3. Bypass Https error “java.security.cert.CertificateException: No name matching <some url> found”

When use RestTemplate to access resource with protocol https, it may has the exception complain something like “java.security.cert.CertificateException: No name matching <some url> found”. This is because the java applicatoin doesn’t has the right certification in its keystore.  As a developer you probably don’t want to get blocked when someone is working on the CA procedure.  You can continue by ignore this SSL host verification like below.  But this is only a temporary solution, should not be used on any production environment.

@Configuration
public class ByPassSSLVerificationConfig {
  // This RestTemplate actually ignore the SSL hostname verification
  @Bean
  public RestTemplate getRestTemplate() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
    TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;
    HostnameVerifier allPassVerifier = (String s, SSLSession sslSession) -> true;  // ignore hostnaem checking

    SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom()
        .loadTrustMaterial(null, acceptingTrustStrategy).build(); // keystore is null, not keystore is used at all

    SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext, allPassVerifier);
    CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(csf).build();
    HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();

    requestFactory.setHttpClient(httpClient);
    return new RestTemplate(requestFactory);
  }
}

Then inject your own RestTemplate bean and send https requests, the Exception will gone. But again this is only a bypass, not a final solution for this Exception.

Thursday, March 3, 2016

Replace jpa persistence.xml with java based configuration in Spring

Jpa 's /META/INF/persistence.xml  with transaction-type set "RESOURCE_LOCAL"  can be replace in spring configuration.

The demo persistence.xml looks like below.

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1"
  xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
  <persistence-unit name="hibernate-persistence"  transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <class>com.shengwang.demo.security.model.UserEntity</class>
    <class>com.shengwang.demo.security.model.AuthorityEntity</class>
    <exclude-unlisted-classes>false</exclude-unlisted-classes>
    <properties>
      <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
      <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/spring" />
      <property name="javax.persistence.jdbc.user" value="root" />
      <property name="javax.persistence.jdbc.password" value="IHave1Dream!" />
      <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/>
      
      <!-- ================================== -->
      <!-- some optional hibernate properties -->
      <!-- ================================== -->
      <property name="hibernate.hbm2ddl.auto" value="create"/>
      <property name="hibernate.hbm2ddl.import_files" value="insert-data.sql"/>
      <property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy"/> 
    </properties>
  </persistence-unit>
</persistence>

This xml file can be replace with following spring config.

package com.shengwang.demo;

// omit import

@Configuration
@EnableJpaRepositories(basePackages = "com.shengwang.demo.model")
public class RootConfig {

  @Bean
  public BasicDataSource dataSource() {
    // org.apache.commons.dbcp.BasicDataSource
    BasicDataSource basicDataSource = new BasicDataSource();
    basicDataSource.setDriverClassName("com.mysql.jdbc.Driver");
    basicDataSource.setUrl("jdbc:mysql://localhost:3306/spring");
    basicDataSource.setUsername("root");
    basicDataSource.setPassword("IHave1Dream!");
    return basicDataSource;
  }

  @Bean
  public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) {
    LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
//    entityManagerFactory.setPersistenceUnitName("hibernate-persistence");
    entityManagerFactory.setDataSource(dataSource);
    entityManagerFactory.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
    entityManagerFactory.setJpaDialect(new HibernateJpaDialect());
    entityManagerFactory.setPackagesToScan("com.shengwang.demo.model");
    
    entityManagerFactory.setJpaPropertyMap(hibernateJpaProperties());
    return entityManagerFactory;
  }

  private Map<String, ?> hibernateJpaProperties() {
    HashMap<String, String> properties = new HashMap<>();
    properties.put("hibernate.hbm2ddl.auto", "create");
    properties.put("hibernate.show_sql", "false");
    properties.put("hibernate.format_sql", "false");
    properties.put("hibernate.hbm2ddl.import_files", "insert-data.sql");
    properties.put("hibernate.ejb.naming_strategy", "org.hibernate.cfg.ImprovedNamingStrategy");
    
    properties.put("hibernate.c3p0.min_size", "2");
    properties.put("hibernate.c3p0.max_size", "5");
    properties.put("hibernate.c3p0.timeout", "300"); // 5mins
    
    return properties;
  }

  @Bean
  public JpaTransactionManager transactionManager(EntityManagerFactory emf) {
    //org.springframework.orm.jpa.JpaTransactionManager
    JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
    jpaTransactionManager.setEntityManagerFactory(emf);
    return jpaTransactionManager;
  }

}

In the java-based config, first define a DataSource bean, then use this data source to create entityManagerFactory, finally use this entityManagerFactory bean to create a transactionManager bean.

Sunday, February 21, 2016

Exception handling in spring mvc/rest application

0. What you need

  • Spring framework 4.x

1. Goal of Exception handling

First let's clarify the goal for exception handling in Spring mvc/rest application:

Goal 1. Deprive exception handling code from business logic to make code cleaner. The fundamental try-catch mix the business code with exception handling code in methods of Controller, we want to separate them.

Goal 2. Fully cover all exception. Final user should not see any exception trace or  server default return page.  No pages like below should return to final user. Or in other words, there should be a default exception view for unhandled exceptions in spring application.

image

image

 

Goal 3. Different exceptions can result in different views.  e.g any **CustomerException  return /customerError page, any **OrderException return /orderError page. The web application can has more views for different exceptions

Goal 4. Mappings between exception and the output view should be configurable, not hard coded.

Goal 5. Modify mappings between exception and the output view doesn't need to change any business code.

2. Four common ways to handle exception in Sping MVC

2.1 @ResponseStatus + User defined Exceptions (Not recommend).

@ResponseStatus can be used at user defined exception class, which means if this exception is not handled by anyone else , the return code will be set to a specified value. It's not recommend because it only set the response http status code and then let the server to use its default page for that status code.  Usually it'a a ugly html page. For example if a ResourceNotFoundException defined as below, with @ResponseStatus before class definition.

@ResponseStatus(value=HttpStatus.NOT_FOUND,reason="some description text")
public class ResourceNotFoundException extends RuntimeException { }

Notice the application defined exception extends from RuntimeException, it's an unchecked exception. The controller BookController.java doesn't seem to have any exception related code.

package com.shengwang.demo.controller;

//... import ignored ...

@RestController
@RequestMapping("/book")
public class BookController {
 @Autowired
 private BookService bookService;

 @RequestMapping(value = "/{bookId}", method = RequestMethod.GET)
 public ResponseEntity findById(@PathVariable long bookId) {
  Book book = bookService.findById(bookId); // may throw ResourceNotFoundException  
  return ResponseEntity.ok(book);
 }
}

If the bookService.findById() throw a application defined exception ResourceNotFoundException, The final result looks like below.

image

This page is ugly to final user. Furthurmore, this html error page is unsuitable for REST web service. For such case, it's preferable to use ResponseEntity as a return type and avoid the use of @ResponseStatus altogether. The 'not recommend' isn't for using your own exceptions, but for @ResponseStatus.

2.2 @ExceptionHandler in Controller

@ExceptionHandler is the key annotation to separate exception handling code from the normal business logic.  @ExceptionHandler in a controller class only works for that controller.

package com.shengwang.demo.controller;

//... import ignored ....

@RestController
@RequestMapping("/book")
public class BookController {
 @Autowired
 private BookService bookService;

 @RequestMapping(value = "/{bookId}", method = RequestMethod.GET)
 public ResponseEntity<Book> findById(@PathVariable long bookId) {
  Book book = bookService.findById(bookId); // throw ResourceNotFoundException here  
  return ResponseEntity.ok(book);
 }
 
 // handle any ResourceNotFoundException thrown from all methods of this controller
 @ExceptionHandler(ResourceNotFoundException.class)
 private ResponseEntity<Void> handleResourceNotFoundException(ResourceNotFoundException e) {
  return ResponseEntity.notFound().build();
 }
}

By using @ExceptionHandler, we extract exception handling to another method. make the code cleaner, especially when there are more methods may throw this ResourceNotFoundException exception. The exception handler method can return ResponseEntity<Void or YourErrorInfoClass> for REST APIs or ModelAndView / String as view name for other kind of Web applications to display error page. 

2.3 @ControllerAdvice + @ExceptionHandler

@ExceptionHandler in a controller class only works for that controller. What if more controllers all need to handle the same exception?   Annotation @ControllerAdvice can help to weaving exception handler method into more controller classes using the AOP way.  This is pretty much same as using @ExceptionHandler in controller, the only difference is extracting all @ExceptionHandler method originally located in controllers  in to an independent class with annotation @ControllerAdvice.

Another benefit of using @ControllerAdvice is making a default exception handler for all unhandled exceptions(handle Exception.class) easily.

package com.shengwang.demo.controller;

//... import ignored ....

@ControllerAdvice
public class GlobalDefaultExceptionHandler {
 @ExceptionHandler(Exception.class)
 private ResponseEntity<Void> defaultExceptionHandler(Exception e) {
  // usually will log the exception first
  return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
 }
}

This can make sure final user will not see the exception call trace.

2.4 Defined your own HandlerExceptionResolver

What does an excpetion resolver in spring mvc do? It decides which view to display when a certain exception is thrown and not unhandled in other place of your code.

What is a excetion resolver in spring mvc? Any bean implement interface org.springframework.web.servlet.HandlerExceptionResolver.

public interface HandlerExceptionResolver {

  //only one method in this interface, return ModelAndView
  ModelAndView resolveException(HttpServletRequest request,
                              HttpServletResponse response,
                              Object handler,
                              Exception ex);
}

Notice the return type is ModelAndView, so it may be used more in NON-REST web applications to display an error page.

How to define you own HandlerExceptionResolver? Usually by using spring's SimpleMappingExceptionResolver class directly, or extending from it. Class SimpleMappingExceptionResolver allows you to set a mapping between exception and view's name,  which can fulfill the goal 3,4, different excpetions can result in different error page.  It also allow you to set a default view for unhandled exceptions.  In xml styled spring configuration, add SimpleMappingExceptionResolver to context.

  <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
    
    <!-- set default view for unhandled exception -->
    <property name="defaultErrorView" value="/defaultError"/>
    
    <property name="exceptionMappings">
      <map>
        <entry key="ResourceNotFoundException" value="/resourceError" />
        <!-- another way to set default view for unhandled exception
        <entry key="Exception" value="/defaultError" />
        -->
      </map>
    </property>
    
    <!-- Name of logger to use to log exceptions. Unset by default, so logging disabled -->
    <property name="warnLogCategory" value="example.MvcLogger"/>
  </bean>

By using placeholder, you can move the hard-coded exception name and view name to a properties file to achieve goal 5.

3. When to use what?

There's no fixed rules in spring mvc. My preferable choices are:

  • Extend your own exceptions from RuntimeException.
  • @ExceptionHandler in controller class only for exceptions not common among controllers.
  • For REST APIs, use @ControllerAdvice + @ExceptionHandler (return ResponseEntity<Void or YourErrorInfoClass>)
  • For NON-REST web application,  choice1, @ControllerAdvice+@ExceptionHandler(return ModelAndView or just String as view name). Or choice 2,  your own HandlerExceptionResolver (for more flexible exception-view mapping configuration)

4. More

Besides the above ways, there are more ways in spring mvc for exception handling. e.g. extend the abstract class org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler to return a ResponseEntity. So it can also be used in RESTful applications. The ways to handle exception  in Spring mvc are so flexible, but in real use, don't mix them too much, keep it simple, keep it clean.

See also Spring blog Exception Handling in Spring MVC by PAUL and his demo code on github

Thursday, February 18, 2016

Response for GET/POST/PUT/DELETE in REST web service

Before talking about the details, one thing need to be clarified. HTTP status code is designed far before RESTful web service appears.  So when REST go popular, people just try to use the most reasonable http behaviour in everyone's understanding of REST.  Here in this article I put some summary in my own experience from a developer's view  as well as other web resources such as restapitutorial.com and RFC 7231. 

Also this article provide demo implementation for REST by Spring webmvc, focused not on how to build rest service itself but on what to return for Get/Post/Put/Delete request for REST service.

0. Brief for HTTP status code

  • 2xx, group for success
  • 3xx, group for redirection
  • 4xx, group for client error. Client side has make a incorrect request
  • 5xx, group for server error. Server failed to fulfile the request.

In a developer's view, rest client API should return normally if the response status code is 2xx. Rest client API should throw an Excpetion if the response status code is 4xx. For example Spring's rest client, org.springframework.web.client.RestTemplate, works in that way and rightly so. 

1. Summary of REST response

image

More explanation about the above table:

The above table assume all operation is allowed. If a operation, e.g. delete on /resource to perform a delete-all operation,  is not permitted, a 405 (Method Not Allowed) should be returned. In most case, developers don’t need to anything about this. Spring’s DispatcherServlet will do that by default if it can’t find a method for the incoming request.

Usually, response 404 (Not Found) doesn't need response body at all, but can also has a body with value set to null.  Whether adding a null body or not mainly depends on method return type. (See code below for GET and DELETE, they both may return 404, but 404 from GET has a null body, 404 from DELETE hasn't, depend on the return type of the method)

GET

204(No Content) doesn't has response body. It means success but no need to reply anything to client. (Since 204 belongs to 2xx, group of success, use it as "resource not found" for GET response is inappropriate).

In all the REST response, 204(No Content) should be treat as a no-body 200(OK).

POST

Post should only work on url like /resource, not on /resource/id. Because the id of newly created resource should be assigned by server, not by client. The request body of POST needn't has the resource id value. If it has, the value of resource id will be ignored by server.

If the resource already exists in database and can not insert due to any kind of unique constraint, 409(Conflict) should be returned.

The success post response will has a "Location" http header point to newly created resource. The response body can be empty, since the resouce location is set in http header. But sometimes  can also direct return the json for newly created resource for simplicity, client need not to send an extra GET to get the assigned ID for the resource. Spring's RestTemplate class provide methods for both senarios.  It provides methods to get the 'Location' header of Post response.

public URI postForLocation(...)

Also RestTemplate provide methods like below for response with response body.

public <T> T postForObject(...)

PUT

PUT should only work on url like /resource/id, not on /resource, since modify the whole resource seems a little bit weird. The request body of POST needn't has the resource id value. Because the resource id usually on the url path.

PUT is used to update resource, in theory can also be used to create new resource according to RFC7231. But in practical whether allow "createIfNotExist" is totally up to you. Furthurmore, in real project, resources will finally get stored in DBMS like Oracle or MySQL. Usually the resource id (primary key in DB's view) is created automatically either by a identity in your Java code by JPA provider or by a sequence in Database. Which means the resource id should not be determined by client, so I personally like to disable this 'createIfNotExist' feature for PUT, just return a 404 (Not Found) for non-exist resource is good enough.

PATCH

The request body of Patch is not resource itself, but a delta. See RFC 6902 for the Json patch format.  PATCH is also used to update reousrce. It can be more effecient and atomic than PUT, since PUT need the whole resource in the request body, PATCH request body only has the difference.

DELETE 

If the delete target doesn't exist, return 404(Not Found). In some special case, the server take the delete request, but will delete the resource in async way, which means return client a 202(Accept) before the resource really get deleted.

2. Examples for REST return

Here are examples implemented with Spring webmvc for all REST method. Spring version is 4.2.1.RELEASE. With ResponseEntity's help, it's very easy to set response header, body and status code. Again examples are only focused on what to return. Suppose we have a resource entity called User. We also has 2 application defined exceptions,  ResourceAlreadyExistException and ResourceNotFoundException.

GET return demo

 @RequestMapping(path="/user",method=RequestMethod.GET)
 public ResponseEntity<List<User>> findAll() {
  // read from database
   List<User> users = userService.findAll();
  return ResponseEntity.ok(users);  // return 200, with json body
 }
 
 @RequestMapping(path="/user/{userId}",method=RequestMethod.GET)
 public ResponseEntity<User> findById(@PathVariable long userId) {
  try {
   // read from database
   User user = userService.findById(userId);
   return ResponseEntity.ok(user);  // return 200, with json body
  } catch (ResourceNotFoundException e) {
   return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null); //return 404, with null body
  }
 }

The above 2 methods, first one return resource collection, second one return a specified single resource. If resource not found, return 404. Here need to set body to null to make the return type consistent as ResourceEntity<User>. (Of course, you can also use @ExceptionHandler or @ControllerAdvice to provide a more consistent return for all exceptions in real project)

POST return demo

 @RequestMapping(path="/user",method=RequestMethod.POST)
 public ResponseEntity<Void> create(@RequestBody User user) throws URISyntaxException {
  try {
   // save to database
   User newUser = userService.saveUser(user);
   return ResponseEntity.created(new URI("/user/"+newUser.getUserId())).build();
  } catch (ResourceAlreadyExistException e) {
   // log excpetion first, then return Conflict (409)
   return ResponseEntity.status(HttpStatus.CONFLICT).build();
  }
 }

The package capture for above method looks like below, you can find the response has 'Location' set in the header.

image

PUT return demo

Here we disable the 'createIfNotExist' feature for PUT, only allow it to update existing resources.

 @RequestMapping(path="/user/{userId}",method=RequestMethod.PUT)
 public ResponseEntity<Void> updateExist(@RequestBody User user,@PathVariable long userId)  {
  try {
   user.setUserId(userId);
   userService.update(user);
   return ResponseEntity.noContent().build();
  } catch (ResourceNotFoundException e) {
   return ResponseEntity.notFound().build();
  }
 }

DELETE return demo

Here the code snippet doesn't allow to  delete non-exists resource. But if you think in it'ok, you can change return to 204 or 200. 

 @RequestMapping(path="/user/{userId}",method=RequestMethod.DELETE)
 public ResponseEntity<Void> deleteById(@PathVariable long userId) {
  try {
   userService.deleteById(userId);
   return ResponseEntity.noContent().build();
  } catch (ResourceNotFoundException e) {
   return ResponseEntity.notFound().build();
  }
 }

REST client

By using RestTemplate class, It' really easy to make a REST client to consume the service. Here's an example to GET resource.

 RestTemplate restTemplate = new RestTemplate();
 String getUrl = "http://localhost:8080/spring-mvc-helloworld/user/1";
 ResponseEntity<User> entity = restTemplate.getForEntity(new URI(getUrl), User.class);
 HttpStatus statusCode = entity.getStatusCode();
 User user = entity.getBody();

3. Recap

This article mainly describes how to reponse to GET/POST/PUT/DELETE request in REST web service side.   But conventions  can be changed according to your bussiness requirement. But basic principle is always use 2xx for success and 4xx for failure. Spring also provides convenient classes like ResponseEntity and RestTemplate that you can utilize.

Tuesday, February 16, 2016

How to use H2 embeded database in spring application

H2, as a embeded memory database, is mainly used for development and test phase. H2 also has a web console which is very convenient.

image

1. Use H2 in Spring boot application

Spring boot has almost everything done for you. You need to do 2 steps, first inluce H2 in you pom.xml.

  <!-- H2 -->
  <dependency>
   <groupId>com.h2database</groupId>
   <artifactId>h2</artifactId>
   <scope>runtime</scope>
  </dependency>

The version of H2 is managed by spring boot and  scope can be set to runtime because you code should not have any APIs come from H2 itself. Then specify datasource url to use H2 in the application.properties file or in lieu of yaml styled configuration

# define DataSrouce properties 
# use h2 can have a buid in web console http://localhost:8080/h2-console
spring.datasource.url=jdbc:h2:mem:mydb

In spring boot application, there is no need to set username and password for using H2 memory database, because H2's default username is 'sa' (or SA, case insensitive), default password is empty. These default username/password will be auto configured by spring boot.  Also Spring boot will config the H2 web console for you automatcally at http://localhost:8080/h2-console

Use H2 in spring-mvc application (non-spring boot)

In non-spring boot application, which is normall just powered by spring-webmvc and other spring artifacts, using H2 need 3 steps. First is also to include H2 in pom.xml

  <!-- H2 -->
  <dependency>
   <groupId>com.h2database</groupId>
   <artifactId>h2</artifactId>
   <version>1.4.190</version>
  </dependency>

Secondly,  use H2 in any ORM configuration. For example if your project uses JPA as persistence and uses Hibernate as JPA service provider. The JPA's configuration file /META-INF/persistence.xml may looks like below.

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1"
 xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
 <persistence-unit name="spring-persistence-jpa-tx" transaction-type="RESOURCE_LOCAL">
  <provider>org.hibernate.ejb.HibernatePersistence</provider>
  <exclude-unlisted-classes>false</exclude-unlisted-classes>
  <properties>
   <property name="javax.persistence.jdbc.driver" value="org.h2.Driver" />
   <property name="javax.persistence.jdbc.url" value="jdbc:h2:mem:mydb" />
   <property name="javax.persistence.jdbc.user" value="sa" />
   <property name="javax.persistence.jdbc.password" value="" />
   
   <!-- Automatically drop then create table -->
   <property name="hibernate.hbm2ddl.auto" value="create" />
   <!-- print out sql  -->
   <property name="hibernate.show_sql" value="true"/>
  </properties>
 </persistence-unit>
</persistence>

Specify the jdbc driver, jdbc url and etc , just like other database.

Finally, and optionally, If you want the H2 web console, you need to add a bean into spring context. In xml-styled spring configuration file, it looks like below.

 <bean id="h2WebServer" class="org.h2.tools.Server" factory-method="createWebServer"
  init-method="start" destroy-method="stop">
  <constructor-arg value="-web,-webAllowOthers,-webDaemon,-webPort,8082" />
 </bean>
In java-styled spring configuration, it looks like below.
@Configuration
@ComponentScan
public class JavaConfiguration {
 //... other beans
 
 @Bean(initMethod="start",destroyMethod="stop")
 public org.h2.tools.Server h2WebConsonleServer () throws SQLException {
   return org.h2.tools.Server.createWebServer("-web","-webAllowOthers","-webDaemon","-webPort", "8082");
 }
}

The -webDaemon means run H2 web console in a daemon thread which will not block the application process termination. -webPort can set the web console service port, default is 8082. The web console url is http://localhost:8082 (Different from the web console url in spring boot application)

Use H2 in spring boot application

In a spring boot application, first add H2 to the dependency.

  <dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>1.4.182</version>
    <scope>runtime</scope>
  </dependency>

Choose a proper H2 version to use and also set scope to runtime become you should not expliity use any class from H2 in you application.

Then configure application.properties or application.yml file for spring boot datasource. Following is example in application.yml file.

spring:
  datasource:
    url: jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
    username: sa
    password:
    driver-class-name: org.h2.Driver
    platform: h2

  # enable H2 web console and set url for web console
  # http://localhost:8080/console
  h2:
    console:
      enabled: true
      path: /console
The default username for H2 is 'sa', default password is empty.

If you also use spring security in your application, which means spring security is in your pom.xml like below.

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

Then you need to add a line in your spring security configuration to make H2 web console working.

@EnableWebSecurity
 
public class SecurityConfig extends WebSecurityConfigurerAdapter {
  Logger logger = LoggerFactory.getLogger(SecurityConfig.class);
 
 //......
 
 
  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests().antMatchers("/").permitAll(); 
    http.authorizeRequests().antMatchers("/imgs/**").permitAll(); 
    http.authorizeRequests().antMatchers("/admin/**").hasRole("ADMIN");
    http.authorizeRequests().antMatchers("/**").hasRole("USER").and().formLogin();
  
    // add this line to use H2 web console
    http.headers().frameOptions().disable();
  }
}

Without this line to setup frame in spring security, you will see a empty page after you login the H2  web console.

Thursday, January 7, 2016

Why DAO or Respository bean can be singleton in Spring

This question based on one fact: instance of javax.persistence.EntityManager is NOT thread-safe. Then how does spring handle concurrency on singleton DAO object.

Suppose we have a simple DAO bean  looks like below, used in a concurrent scenario, such as in a web application.

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.transaction.Transactional;

import com.shengwang.demo.model.User;  // a trivial entity

@Transactional
public class UserDao {
  @PersistenceContext
  private EntityManager em;
  
  public void addUser (User user) {
    em.persist(user);
  }
}

Can you set the scope of this bean to singleton in JEE context?  (NO)

Can you set the scope of this bean to singleton in Spring context? (YES, but why? see below)

1. In JEE

Usually DAO bean is stateless. Our DAO bean above is just a stateless bean, so in JEE most common way is to mark it as @Stateless and create a instance pool of this DAO. JEE container will maintain this pool,  assign a  bean instance handle for every individual invocation, and bean will release back to the pool after invocation.

Because the EntityManager is non thread-safe, the solution for concurrency in JEE is creating a pool.  That sounds reasonable.

2. In Spring

The default scope of bean in spring is singleton, and offical document recommend you to set DAO bean singleton, which means just use the default scope config is fine.

But Why? When multiple threads access this single object, why the non thread-safe EntityManager instance does not complain? The reason is  that in Spring framework, the Entitymanager instance em in the Dao bean is not a real EntityManager, but a proxy.  Which mean very invocation on em, like em.persist(), is handled by a  proxy.

In case you are not familiar with Proxy in Java reflection, here are  some basic knowledge for quick understanding.

2.1 basic about proxy

In java reflection package java.lang.reflect , there is a Proxy class.  Java provide a mechenism to create a proxy for any class.  Suppose we want to create a proxy for class Foo. Code looks like :

Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(), new Class[] { Foo.class }, handler);

The instance f is a proxy. The last parameter handler is an implementation of interface java.lang.reflect.InvocationHandler. When any methods of instance f get called, the handler’s only method , invoke(Object proxy, Method method, Object[] args), get called. So in this method,  you have a chance to place some logic before/after the real invocation.

2.2 Spring use proxy to get real EntityManager on every invocation.

Since the em injected to DAO is just a proxy, every call on the em will first try to get the real EntityManager object in the handler.  This logic is located in org.springframework.org.jpa.SharedEntityManagerCreator. This class implements the InvocationHandler interface and has a invoke() method. In this method, there are codes like:

EntityManager target = EntityManagerFactoryUtils.doGetTransactionalEntityManager(...);

This doGetTransactionalEntityManager(…) will get EntityManager bound to current thread! If we follow the doGetTransactionalEntityManager(…) method, we will find following in method.

EntityManagerHolder emHolder = (EntityManagerHolder) TransactionSynchronizationManager.getResource(emf);

Keep tracking getResource(…), you will found the resource is a ThreadLocal map variable defined in class org.springframework.transaction.support.TransactionSynchronizationManager

Now you should understand why the Dao can (should) be a singleton bean in spring framework. Because spring internally use Proxy and ThreadLocal to eliminate the impact the non thread-safe EntityManager bring to stateless bean.  No need to create pool for concurrency anymore!

All code snippets above are based on Spring framework 4.1.0.RELEASE.

3. Recap

To some extends, you can think spring framework use a ThreadLocal variable as the stateless bean pool in JEE. You can also think this somehow way of a Flyweight design pattern, use a shared object to save overhead of create/destroy objects.

Tuesday, December 29, 2015

"Config method" in Spring framework

1. Concept

What is config method in Spring? Any method that is anotated by @autowired is config method.

What’s the difference between a normal method and a config method in spring? Config method will be automatically  invoked when the bean instance created, after constructor but before @PostConstruct. The parameters of config method will be autowired from the application context. 

The name of the method doen’t matter and parameter number doesn’t matter. In fact we often use @autowired before setter method, that’s  just a special case of spring config method.

2. Usage of config method

Genetic config method is not widely use as field injection, setter injection or constructor injection,  but config method is used  in spring security.  According to spring security official reference here, the first step to config spring security is to extend from WebSecurityConfigurerAdapter like below.

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.context.annotation.*;
import org.springframework.security.config.annotation.authentication.builders.*;
import org.springframework.security.config.annotation.web.configuration.*;

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

  @Autowired
  public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    auth.inMemoryAuthentication().withUser("user").password("password").roles("USER");
  }
}

This is a good example of using config method.  config method will be automatically invoked when bean instantiated, that’s why the document said

The name of the configureGlobal method is not important.

Because it just a config method, and will be automatically invoked with a AuthenticatonManagerBuilder bean from context. The purpose of this method is just to using AuthenticationManagerBuilder to setup authentication provider before real logic begins.

3. See also

spring framework javadoc of @Autowired

Wednesday, December 16, 2015

Use Spring Test without @RunWith(SpringJUnit4ClassRunner.class)

This is a new feature from Spring framework 4.2. Now you can use other JUnit's runners,like Parameterized or MockitoJUnitRunner but without losing spring test benefits. (with all the features you love with spring-test like spring  Dependency Injection , Auto-rollback Transaction for test and etc).

In this article, a simple hello world level JUnit test case is provided with JUnit Parameterized runner, with spring-test support enabled.

0. What you need

  • JDK 1.7 +
  • Spring framework 4.2 + ( 4.2.1.RELEASE is used in this demo)
  • Maven 3.2+ (This demo is a maven project, but maven is not necessary for enable Spring-test support in other JUnit runners)

1. Define pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
                      http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.shengwang.demo</groupId>
  <artifactId>spring-test-simple</artifactId>
  <version>1</version>
  <packaging>jar</packaging>

  <name>spring-test-simple</name>
  <url>http://maven.apache.org</url>

  <dependencies>
    <!-- Spring framework -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>4.2.1.RELEASE</version>
    </dependency>

    <!-- Spring test -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>4.2.1.RELEASE</version>
      <scope>test</scope>
    </dependency>
    
    <!-- JUnit test -->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>

  </dependencies>
  
  <build>
    <plugins>
      <!-- Use Java 1.7 -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>2.5.1</version>
        <configuration>
          <source>1.7</source>
          <target>1.7</target>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

The pom specifies 3 dependencies, spring-context, spring-test and junit. Also it specify the Java version to 1.7.

2. Define Java Class

There are 3 classes in this demo. First is HelloService.java, which is a Spring bean as test target. 

package com.shengwang.demo;

import org.springframework.stereotype.Service;

@Service
public class HelloService {

  public String sayHello(String name) {
    return "Hello " + name;
  }
}

The second is JavaConfig.java, as Spring context configuration.

package com.shengwang.demo;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan
public class JavaConfig {}

The Last is the JUnit test case HelloServiceTest.java use Parameterized as runner.

package com.shengwang.demo;

import java.util.Arrays;
import java.util.Collection;

import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.rules.SpringClassRule;
import org.springframework.test.context.junit4.rules.SpringMethodRule;

@RunWith(Parameterized.class)
@ContextConfiguration(classes=JavaConfig.class)  // specify context config
public class HelloServiceTest {
  
  // -------------------------------------------
  //  spring test support requirement from 4.2
  // -------------------------------------------
  @ClassRule
  public static final SpringClassRule SPRING_CLASS_RULE= new SpringClassRule();
  @Rule
  public final SpringMethodRule  springMethodRule = new SpringMethodRule();
  // -------------------------------------------
  //  spring test support requirement over
  // -------------------------------------------
  
  private String name;
  
  @Autowired
  HelloService service;

  public HelloServiceTest(String name) {
    this.name = name;
  }
  
  @Parameters
  public static Collection<String[]> data() {
    return Arrays.asList(new String[][] {
        {"Tom"},{"Jerry"}  
    });
  }
  
  @Test
  public void testSayHello() {
    service.sayHello(name);
  }
  
}

The test case enable spring-test support by 3 steps:

  1. 1. Use @ContextConfiguration to config Spring TestContext .
  2. 2. Add a SpringClassRule static variable
  3. 3. Add a SpringMethodRule field variable

The project's hierarchy looks like below:

image_thumb5

Now the test get all abilities from spring-test. The @Autowired dependency injection works perfectly.

image_thumb2

Thursday, August 6, 2015

Understand web.xml in Spring MVC project

The deployment descriptor file web.xml is the entry point to understand all configurations for a Spring MVC project.

In many cases, there are 2 type of  xml configuration files in a Spring MVC project:

  • web.xml – Describe how to deploy the web application to any Java Servlet container.
  • context configuration xml – Configuration file to create Spring Application context, one or more.  

1. What is web.xml

The /WEB-INF/web.xml file is used to define how to deploy the web module to a Servlet container like JBoss, Tomcat, Glassfish or any other servlet container. It’s defined by Sun since Java 1.4 ( or 1.2?  not  so sure) and part of the Java Servlet specification. The file name and locations can not be changed.

Basically web.xml tell container all servlets in the web application with <servlet> element , then tell container when to use which servlet by the url mapping  with <servlet-mapping> element.

Here is a reference of all elements in web.xml from Oracle WebLogic  document.

In Spring MVC project, for most cast, there is only one servlet org.springframework.web.servlet.DispatcherServlet. Let this DispatcherServlet handle all the requests. After container hands over the request to DispatcherServlet, the income http request formally enters the Spring world.  A controller will be chosen to handle the request according to @RequestMapping.

2. What is context configuration xml

In XML style configured Spring MVC project, there will be at least one xml to configure Spring MVC WebApplicatonContext. As Spring document says, there are 2 type of WebApplicationContext:

  • Root WebApplicationContext
  • Servlet WebApplicationContext

All servlets, althrough in most case only one DispatcherServlet, share root context. Each Servlet has its private context. Spring tries to locate a bean first in Servlet context, if not found, then search root context. A Spring MVC project can use both or just any one of them. In practical there really isn’t much difference between which context(s) is used.

The default configuration file for root WebApplicatonContext is /WEB-INF/applicationContext.xml

The default configuration file for servlet WebApplicatonContext is /WEB-INF/[servletName]-servlet.xml

The files’ name and location can be changed in web.xml.

3. More details with demo project

This is the directory hierarchy of the demo project.

image

It’s created in Eclipse as maven project with simple “maven-archetype-webapp” archetype.

image

In this demo, both root context and servlet private context are used just for demo. Service/Repository beans are registered in root context. Controller beans are registered in servlet private context. Define all beans in just one context is fine also.

The root context configuration file applicationContext.xml list below:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">

<!-- register service/persistence beans in root context -->
<context:component-scan base-package="com.shengwang.demo.service" />

</beans>

The servlet private context configuration file dispatcher-servlet.xml list below:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">

<!-- register controller in servlet private context -->
<context:component-scan base-package="com.shengwang.demo.controller"/>

</beans>
These 2 spring configuration are just for demo. In real use you need more configuration in them like persistence, security, etc.

The web.xml list below:

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<display-name>Demo for understanding web.xml of spring mvc project</display-name>

<!-- ===================================================== -->
<!-- 1. Create root context with spring listener -->
<!-- Remove this means only use servlet contxt -->
<!-- ===================================================== -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<!-- ===================================================== -->
<!-- Can modify default root context config file -->
<!-- ===================================================== -->
<!--
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/root-context.xml</param-value>
</context-param>
-->


<!-- ===================================================== -->
<!-- 2. Define servlet with private context -->
<!-- ===================================================== -->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- ================================================= -->
<!-- Set contextConfigLocation to empty -->
<!-- means only use root context -->
<!-- ================================================= -->
<!--
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</init-param>
-->
<load-on-startup>1</load-on-startup>
</servlet>
<!-- ===================================================== -->
<!-- One servlet, the dispatcher, to rule it all -->
<!-- ===================================================== -->
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

</web-app>

The listener ContextLoaderListener is used to create root WebApplicationContext, <context-param>can be used to change config file location. 

<servlet> and <servlet-mapping>  work in pairs. The only servlet in this demo is named dispatcher, so the default servlet private context file is /WEB-INF/dispatcher-servlet.xml, it will handle all income request because its url-pattern is “/”, which means it’s the default servlet for all request not handled by other servlets. Since there is only one  servlet dispatcher, so in fact it will handle all requests.

Sunday, June 14, 2015

Build a spring project into an executable standalone jar in maven

To create an executable standalone jar, which can be run by command  like java –jar myExecutable.jar, there are 2 conditions need to be fulfilled:

  • Specify the entry main class in META-INFO/MANIFEST.MF file
  • Include all dependences  in the final jar file

The second condition is not needed theoretically, but in practical will always be necessary.

If the project uses Spring with xml configuration, then there’s one more condition to fulfill.

  • Handle spring schemas for different spring packages. (see below for explanation)

The best maven plugin to handle all there three requirements are maven-shade-plugin. (some other plugin such as maven-assembly-plugin can deal with the first two requirements, but not the third one).

In this article, a hello world spring project will be package to an executable standalone jar file using maven. The way used in this article can also perfectly create executable standalone jar package, even if the project don’t use spring.

0. What you need

  • JDK
  • Spring
  • Maven 3.2.1

1. Define the class

There are 2 classes. The first one the a spring bean.

package com.shengwang.demo;

import org.springframework.stereotype.Component;

@Component
public class HelloWorldBean {
public void sayHello(String name) {
System.out.println("Hello "+name);
}
}

The second one is the main class, which get the hello world bean and call its sayHello method.

package com.shengwang.demo;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class DemoMain {

public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("application-context.xml");
HelloWorldBean bean = ctx.getBean(HelloWorldBean.class);

bean.sayHello("Spring");

((ClassPathXmlApplicationContext) (ctx)).close();
}
}

2. Spring configuration


The spring xml configuration file application-context.xml is also very simple.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.1.xsd">

<context:component-scan base-package="com.shengwang.demo" />

</beans>

3. Maven pom


Plugin maven-shade-plugin in the pom file is the key of this demo.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.shengwang.demo</groupId>
<artifactId>spring-executable-standalone</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>spring-executable-standalone</name>
<url>http://maven.apache.org</url>

<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.1.0.RELEASE</version>
</dependency>
</dependencies>

<build>

<plugins>
<!-- Use JDK 7 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.5.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>

<!-- =============================================================== -->
<!-- use shade plugin to package spring project into executable jar -->
<!-- =============================================================== -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<!-- =================================================== -->
<!-- define the main entry for the output jar file -->
<!-- =================================================== -->
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.shengwang.demo.DemoMain</mainClass>
</transformer>
<!-- =================================================== -->
<!-- append all spring.handlers instead of overwriting -->
<!-- =================================================== -->
<transformer
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.handlers</resource>
</transformer>
<!-- =================================================== -->
<!-- append all spring.schemas instead of overwriting -->
<!-- =================================================== -->
<transformer
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.schemas</resource>
</transformer>
</transformers>
<!-- ============================================================ -->
<!-- exclude any digital signiture file from third party jar file -->
<!-- ============================================================ -->
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>

</plugins>
</build>
</project>

In the plugin, 3 transformers and 1 filter are used. Let’s explain them one by one.


The first transformer is ManifestResourceTransformer, which will modify the META-INFO/MANIFEST.MF file in the final  output jar file. This transformer is used to add Main-Class entry in the MANIFEST.MF file. If unzip the output jar, open the META-INFO/MANIFEST.MF file, we can see the added line.


image


The second and third transformers are AppendingTransformer. Why these two transformers are needed? Because every Spring package store xsd mapping file in the same direcotry hierarchy, /META-INF/spring.schemas and /META-INF/spring.handlers, see example below.


image image


For example two spring artifacts, spring-aop and spring-beans, have the exactly same files in the same directory. When using maven to package jar, these files from different dependency packages are combined in to one file by the transformers.


The filters are used to exclude the digital signature files out of the final output jar file. Some of the third party dependency may be digitally signed. These signature files must be screened out to prevent signature verification exceptions.


For most cases, the main-class entry is the only thing need to change.


4. Package


Run maven to package the project into one jar file.

mvn clean package

5. Run the output jar


Run the output jar file

java -jar spring-executable-standalone-0.0.1-SNAPSHOT.jar

The output looks like:


image

Tuesday, June 9, 2015

Use JMX to monitor Hibernate 4.3 statistics (with Spring)

To find out hibernate cache’s performance, like cache hit/miss ratio, JMX can be convenient. Before Hibernate 4.3, there is a StatisticsService class can be used. But Hibernate 4.3 removed this class.  If the project also uses Spring framework, it can still be done. 

The original solution came from Marcel Stor from here. This article try to compliment it with details.

0. What you need

  • JDK1.7 +
  • Maven 3.2.1+
  • Spring 4.1.0.RELEASE
  • Hibernate 4.3.4.Final

1. Define Java class

One Jave class is needed. Add the following class to the project.  The class is defined as a normal Spring bean with @Component annotation.

package com.shengwang.demo.statistics;

import org.hibernate.SessionFactory;
import org.hibernate.stat.Statistics;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class HibernateStatisticsFactoryBean implements FactoryBean<Statistics> {

@Autowired
private SessionFactory sessionFactory;

@Override
public Statistics getObject() throws Exception {
return sessionFactory.getStatistics();
}

@Override
public Class<?> getObjectType() {
return Statistics.class;
}

@Override
public boolean isSingleton() {
return true;
}
}

2. Configure Spring


Configure Spring, add following to the spring configuration xml file.

<!-- ==================================== -->
<!-- Hibernate 4.3 Statistics for JMX -->
<!-- ==================================== -->
<bean id="jmxExporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="beans">
<map>
<entry key="Hibernate:type=statistics">
<ref bean="hibernateStatisticsFactoryBean"/>
</entry>
</map>
</property>
</bean>

The bean hibernateStatisticsFactoryBean used is the Class defined above. 


All done!


3. Check from JConsole


Run JConsole, the JMX tool shipped with JDK, connect to the running project. Now hibernate statistics can be monitored!


Connect to the Java application process.

image

Now the Hibernate performance can be monitored by JMX, for example the 2nd level cache hit ratio in the following snapshot.


image

Monday, May 25, 2015

Spring Scheduler hello world example - run task in the future

Spring framework now support scheduler, so for most usage there is no need to involve other library, such as Quartz to do this.  The usage is very simple: add annotation @Scheduled(...) to any bean's method that need to be run in the future. The Spring context will create a thread to run it at the right time you specified in the future.

0. What you need

  • JDK 1.7
  • Maven 3.2.1
  • Spring 4.1.0.RELEASE

1. Configure the maven pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>
<modelversion>4.0.0</modelversion>
<groupid>com.shengwang.demo</groupid>
<artifactid>spring-scheduler-hello-world</artifactid>
<version>0.0.1-SNAPSHOT</version>

<dependencies>

<!-- Spring Context aritifact-->
<dependency>
<groupid>org.springframework</groupid>
<artifactid>spring-context</artifactid>
<version>4.1.0.RELEASE</version>
</dependency>

</dependencies>

<!-- Using JDK 1.7 for compiling -->
<build>
<plugins>
<plugin>
<groupid>org.apache.maven.plugins</groupid>
<artifactid>maven-compiler-plugin</artifactid>
<version>2.5.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
</project>


2. Define the Java Class



In the example there are 2 classes. The first one is a simple spring bean, but with annotation @Scheduled for method.

package com.shengwang.demo;

import java.util.Date;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class Task {
/*
* The method will run on 13:40:00 everyday.
* cron format: sec min hour day mon week
*/
@Scheduled(cron="0 40 13 * * *")
public void runTask() {
System.out.println("Runing at " + new Date());
}
}


The second class is the main class.

package com.shengwang.demo;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class DemoMain {

public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("app-context.xml");
}
}
The only line in the main is used to create the spring application context. If you run the main function, the program will not never finish since the spring context is not closed. so it will wait for the scheduled task to run in the future. The app-context.xml is the spring configuration file.

 



3. Spring configuration



The spring configuration file is named "app-context.xml" here. It stays in the main resources path /src/main/resources.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task.xsd">

<!-- enable scheduling annotations -->
<task:annotation-driven scheduler="scheduler"/>
<task:scheduler id="scheduler" pool-size="15"/>

<!-- register spring beans -->
<context:component-scan base-package="com.shengwang.demo" />

</beans>


There are 2 lines start with <task:... /> used to configure spring scheduling. One thing need to mention is that (from spring official document):  If you do not provide a pool-size attribute, the default thread pool will only have a single thread. So in real practical, the pool-size is should always be set  to a number bigger than one to prevent any long task delaying all other scheduled tasks.

Thursday, January 29, 2015

Using Netty Component in Apache Camel - Hello World Example

This tutorial will demo how to use Netty Component in Apache Camel. By using netty component with camel in the example, this article is going to achieve these goals:

  • Create a TCP Socket server as camel endpoint with netty component, waiting for TCP client.
  • Utilize camel to route the received TCP message from Netty endpoint to other process logic
  • Send the processed result back to the TCP client.

In this example, every time server get a string, it will reply with a prefix "Hello" to form a greeting. If "Tom" is received from client, "Hello Tom" will be send back to the client.

This example also shows there features:

  • Use Camel and Netty component with Spring framework.
  • Use POJO class for business logic, which does not depend on any Camel or Netty componenent APIs.

1. What you need

  • JDK 1.7+
  • Maven 3.2.1

The dependencies will be managed by Maven.

2. Configure the maven pom.xml

The key artifacts are camel-core, camel-spring, camel-netty. The camel-spring artifact is needed for using Spring framework. The camel-netty artifact is needed for using netty component in camel.

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.shengwang.example</groupId>
<artifactId>spring-camel-netty3</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>spring-camel-netty</name>
<url>http://maven.apache.org</url>

<properties>
<!-- Generic properties -->
<java.version>1.7</java.version>

<!-- Camel -->
<camel.version>2.14.1</camel.version>
</properties>

<dependencies>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-core</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-spring</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-netty</artifactId>
<version>${camel.version}</version>
</dependency>
</dependencies>


<build>
<plugins>
<!-- Use JDK 1.7 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.5.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<compilerArgument>-Xlint:all</compilerArgument>
<showWarnings>true</showWarnings>
<showDeprecation>true</showDeprecation>
</configuration>
</plugin>

<!-- Allows the routes to be run via 'mvn camel:run' -->
<plugin>
<groupId>org.apache.camel</groupId>
<artifactId>camel-maven-plugin</artifactId>
<version>${camel.version}</version>
</plugin>

</plugins>
</build>
</project>

In the POM file, Jave version and Camel version are defined in properties, followed by 3 dependencies. Then there are 2 plugins, the first one is to specify the Java version for building the project, the second plugin is needed to allow the camel route to be run without explicitly defined main function. It's very handy for demo and test.


3. Define a Java class to process the received message


This class is the process logic in this demo. This class is a POJO which means the business code is completely decoupled with camel or camel-netty component.

package com.shengwang.example.server;

import org.springframework.stereotype.Service;

@Service
public class EchoService {
public String sayHello(String guestName) {
System.out.println("Input guestName : "+ guestName);
return "Hello " + guestName;
}
}

The EchoService.java is very short and simple. Annotation @Service means it's will be registered in Spring context as a bean. How to use this bean will be explained later.


4. Define Camel route


Now Let's define another Java class for Camel route. This class extends RouteBuilder from Camel package and override the configure() method. In configure(), route is defined.

package com.shengwang.example.server;

import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.spring.Main;

public class ServerRoute extends RouteBuilder {
public static void main(String[] args) throws Exception {
new Main().run(args);
}

@Override
public void configure() throws Exception {
from("netty:tcp://localhost:7000?sync=true&allowDefaultCodec=false&encoder=#stringEncoder&decoder=#stringDecoder")
.to("bean:echoService");
}
}

There are two methods in the ServerRoute class. The first one is a main, so we can run the route directly with the helper class Main from camel-spring package.


The second method has the route defined. It means somehow like "from to ". In this tutorial we get message from netty endpoint and send to a Spring bean which defined in previous section. The is how the EchoService class is used in this demo. The interesting part is the long from URI:"netty:tcp://localhost:7000?sync=true&allowDefaultCodec=false&encoder=#stringEncoder&decoder=#stringDecoder". It can be break down bit by bit.


"netty:tcp://localhost:7000" means netty component is needed to setup a tcp server on localhost port 7000.


"sync=true" means exchange pattern is InOut, the server will send back the response to client.


"allowDefaultCodec=false" means we don't use default encoder and decoder for netty component. Because in reality, the message come in netty endpoint is most unlikely formed in that message format, so it need to be set to false against its default value true.


"encoder=#stringEncoder&decoder=#stringDecoder" means message comes into netty will be decoded before transferring to the business logic EchoService, and response from EchoService will be encoded before sending back to the client. In this tutorial, server receive and send back Java string, so the StringEncoder and StringDecoder from camel-netty package will be used. The hash tag "#" refer to beans in Spring context which will be defined in Spring configuration file later.


5. Spring configuration


The Spring configuration file app-context.xml is located in directory src/main/resources/META-INF/spring.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:camel="http://camel.apache.org/schema/spring"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://camel.apache.org/schema/spring
http://camel.apache.org/schema/spring/camel-spring.xsd">

<context:component-scan base-package="com.shengwang.example" />

<!-- ================================== -->
<!-- Define camel context -->
<!-- ================================== -->
<camel:camelContext id="camel">
<!-- Location for route scan -->
<camel:package>com.shengwang.example.server</camel:package>
</camel:camelContext>

<!-- ================================== -->
<!-- Define netty codecs -->
<!-- ================================== -->
<!-- ChannelBuffer/ByteBuf to String -->
<bean id="stringDecoder" class="org.jboss.netty.handler.codec.string.StringDecoder"/>

<!-- String to ChannelBuffer/ByteBuf -->
<bean id="stringEncoder" class="org.jboss.netty.handler.codec.string.StringEncoder"/>

</beans>

<context:component-scan> scan for normal Spring beans of a package. Here is the EchoServer. Then,<camel:camelContext>, Camel context is defined so does the location of the route. Finally, encoder and decoder beans are defined.


Now all 4 files of the project have been defined. The directory structure looks like this.


Snap_2015.01.27 13.29.23_001


6. Run the server


There are 2 options to run this demo. The first one is to run the main in ServerRouter.java class. The Second is run via command line "mvn camel:run".  The latter way, which needs a maven plugin list at the bottom of the pom file,  is very convenient for test and development.


7. Test with a TCP client


Use telnet command as test client, connect to port 7000 with command "telnet localhost 7000". Anytime a key is pressed, a TCP message will send out to the demo server  and a reply will come back immediately.


Appendix


The netty component camel-netty is based on netty 3.x version. If a netty component based on netty 4.x is preferred, use camel-netty4 component instead.

Monday, December 1, 2014

How to inject a logger variable by using annotation in Spring

In development, we need logger almost everywhere. you can inject a bean with annotation like inject other beans
package com.shengwangi.demo;
@Component
public class MyClass {
  @Loggable
  Logger logger;
  public void myMethod() {
    // do some thing
    logger.info("use the logger as usual"); 
  }
}
As you can see, annotation @Loggable is used to inject the logger. @Loggable is an annotation that we defined ourselves. Here is how to do it. (It's not my original idea, borrowed from stackoverflow Q&A here by Redder)

1. Define the annotation

Define the loggable annotation.
package com.shengwangi.demo;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
 
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

@Retention(RUNTIME)
@Target(FIELD)
@Documented
public @interface Loggable {}
Besides the package and import lines there are 3 annotations before the one-line definition of Loggable. @Retention(RUNTIME) means the Annotation will be retained by the compiler and can be used by VM at run time. @Target(FIELD) means it will be used to annotate fields of class. @Documented it will be documented when you run javadoc to create documents.

2. Define LoggableInjector Class

Let's see the code first.
package com.shengwangi.demo;

import java.lang.reflect.Field;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Service;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.ReflectionUtils.FieldCallback;

@Service
public class LoggableInjector implements BeanPostProcessor {

  @Override
  public Object postProcessAfterInitialization(Object bean, String beanName)
      throws BeansException {
    return bean;
  }

  @Override
  public Object postProcessBeforeInitialization(final Object bean,
      String beanName) throws BeansException {
    ReflectionUtils.doWithFields(bean.getClass(), new FieldCallback() {
      public void doWith(Field field) throws IllegalArgumentException,
          IllegalAccessException {
        // make the field accessible if defined private
        ReflectionUtils.makeAccessible(field);
        if (field.getAnnotation(Loggable.class) != null) {
          Logger log = LoggerFactory.getLogger(bean.getClass());
          field.set(bean, log);
        }
      }
    });
    return bean;
  }
}
The LoggableInjector implements Spring's BeanPostProcessor interface, which give you the chance to do something just before/after creation of beans. What the LoggableInjector class actually do is after creation of a bean object, find the field annotated by @Loggable, which we defined in step 1, then set the field value to a real logger.

3. Use annotation @Loggable to inject logger

Like we already did in the beginning of this article, using the annotation to inject logger to your beans.
@Loggable Logger logger
One thing need to notice is that the real logger is created after the bean object has been initialized, which means you can NOT use logger in the constructor of the bean. Because at that time, the logger field has not be defined, you'll get NullPointerException Error.
Powered by Blogger.

About The Author

My Photo
Has been a senior software developer, project manager for 10+ years. Dedicate himself to Alcatel-Lucent and China Telecom for delivering software solutions.

Pages

Unordered List