Monday, July 22, 2013

Using Logback with Spring

The mandatory logging dependency in Spring is the Jakarta Commons Logging API (JCL). The nice thing about commons-logging is that you don't need anything else to make your application work. It has a runtime discovery algorithm that looks for other logging frameworks in well known places on the classpath and uses one that it thinks is appropriate (or you can tell it which one if you need to). If nothing else is available you get pretty nice looking logs just from the JDK (java.util.logging or JUL for short).

Unfortunately, the runtime discovery algorithm in commons-logging, while convenient for the end-user, is problematic. Switching off commons-logging is easy: just make sure it isn't on the classpath at runtime.
<dependencies> 
  <dependency> 
    <groupId>org.springframework</groupId> 
    <artifactId>spring-context</artifactId> 
    <version>${spring.version}</version> 
    <exclusions> 
      <exclusion> 
        <groupId>commons-logging</groupId> 
        <artifactId>commons-logging</artifactId> 
      </exclusion> 
    </exclusions> 
  </dependency> 
</dependencies> 
Now this application is probably broken because there is no implementation of the JCL API on the classpath, so to fix it a new one has to be provided.Logback is very powerfull logging framework and is intended as a successor to the popular log4j project. Logback implements SLF4J api so we need slf4j-jcl brindge on classpath.
Final dependencies are:
<dependencies> 
  <dependency> 
    <groupId>org.springframework</groupId> 
    <artifactId>spring-context</artifactId> 
    <version>${spring.version}</version> 
    <exclusions> 
      <exclusion> 
        <groupId>commons-logging</groupId> 
        <artifactId>commons-logging</artifactId> 
      </exclusion> 
    </exclusions> 
  </dependency> 
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>jcl-over-slf4j</artifactId>
    <version>${jcl.over.slf4j.version}</version>  
  </dependency>
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>${logback.version}</version>
  </dependency>
</dependencies> 

Thursday, July 11, 2013

Cunning <mybatis:scan/> elemnt

In version 1.2.0 of Mybatis-Spring a possibility of scanning mapper interfaces via XML element <mybatis:scan/> has appeared. As a doc says  the <mybatis:scan/> XML element will search for mappers in a very similar way than the Spring built-in element <context:component-scan/>searches for beans. Here is an example:
<beans xmlns="http://www.springframework.org/schema/beans" 
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
       xmlns:mybatis="http://mybatis.org/schema/mybatis-spring" 
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
               http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
               http://mybatis.org/schema/mybatis-spring 
               http://mybatis.org/schema/mybatis-spring.xsd"> 
     <mybatis:scan base-package="org.mybatis.spring.sample.mapper" /> 
</beans>

The base-package attribute lets you set the base package for your mapper interface files. You can set more than one package by using a semicolon or comma as a separator. Mappers will be searched for recursively starting in the specified package(s). 
Also, if we have only either one sqlSessionFactory in application context or one sqlSessionTemplate(but not both) we may not specify them in <mybatis:scan/>, but if we have more than one of them - we should. Also attribute is factory-ref or template-ref, but actually it's not a ref. Mybatis-Spring treats to the value pointed in that attribute as to bean name. So, in my opinion the correct meanning of that attributes are factoryBeanName and templateBeanName as known properties in MapperScannerConfigurer.

<mybatis:scan/> element is handled by org.mybatis.spring.config.NamespaceHandler which is pointed as handler in spring.handlers file under META-INF directory of mybatis-spring.jar.This handler just overrides init method and registers the beanDefinitionParser MapperScannerBeanDefinitionParser. This parser scan the packages specified in base-package attribute and creates bean definitions for MapperFactoryBeans. The default behavior involves beans created using BeanDefinition to have autowire-candidate property to be set to true. Then, if we haven't specified sqlSessionFactory-ref or sqlTemplate-ref in <mybatis:scan/> tag, the subclass of ClasspathBeanDefinitionScanner which is used in MapperScannerBeanDefinitionParser sets autowireMode on created bean to be AUTOWIRE_BY_TYPE. Thus, it produces the behavior similiar to @Autowire annotation on setSqlSessionFactory method of MapperFactoryBean

Sunday, July 7, 2013

Issue with MapperScannerConfigurer in mybatis-spring module

    Recantly I have encountered with interesting feature in mybatis-spring module. I have been developing persistance module for one project and need to write tests for it. Ofcourse I decided to use spring-test and also tried dbUnit. I wrote a base class for persistance test case which simply utilize dbUnit functionality(applying datasets). Also I've annotated that class with standart spring-test annotation:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
@TransactionConfiguration(defaultRollback = true, transactionManager = "txManager")
@Transactional
which points to applicationContext and also uses transactionManager to roolback transactions(with dbUnit i clear the real table in test method, insert there test dataset, perform test and then rollback a transaction).
   All my persistance tests are focusing on testing mybatis mappers, so for that reason I used MapperScannerConfigurer to dynamically discover all mybatis mapper interfaces and create for each of them MapperFactoryBean instances which produce real instances of mapper interfaces. So, I configured a bean for MapperScannerConfigurer in applicationContext:
<bean id="mappeScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer"
  p:basePackage="com.mypackage"
  p:sqlSessionFactory-ref="sqlSessionFactory" />
As it needs sqlSessionFactory I declare it also. SqlSessionFactory needs a datasource to fetch connections from it, so i declare a datasource like this:
<bean id="datasource" class="org.apache.commons.dbcp.BasicDataSource"
   p:username="${jdbc.username}" 
   p:password="${jdbc.password}" 
   p:url="${jdbc.url}"
   p:driverClassName="${jdbc.driverclass}" p:validationQuery="SELECT sysdate FROM dual" />
Ofcourse I need some property-placeholder to resolve references to jdbc stuff and I declare it:
<context:property-placeholder location="classpath:props/datasource.properties" />
It seemed to me that it's enough, but when I try to run the test I got next error:
org.apache.commons.dbcp.SQLNestedException: Cannot load JDBC driver class '${jdbc.driverclass}'
It means that placeholder hasn't been resolved. but why?

Monday, July 1, 2013

Spring Caching Abstraction + Guava Cache

Intro

   Caches are tremendously useful in a wide variety of use cases. For example, you should consider using caches when a value is expensive to compute or retrieve, and you will need its value on a certain input more than once.
   A Cache is similar to ConcurrentMap, but not quite the same. The most fundamental difference is that a ConcurrentMap persists all elements that are added to it until they are explicitly removed. A Cache on the other hand is generally configured to evict entries automatically, in order to constrain its memory footprint.
   Since version 3.1, Spring Framework provides support for transparently adding caching into an existing
Spring application. Similar to the transaction support, the caching abstraction allows consistent use of
various caching solutions with minimal impact on the code.
   To use the cache abstraction, the developer needs to take care of two aspects:
  • caching declaration - identify the methods that need to be cached and their policy
  • cache configuration - the backing cache where the data is stored and read from

Note that just like other services in Spring Framework, the caching service is an abstraction (not a cache implementation) and requires the use of an actual storage to store the cache data - that is, the abstraction frees the developer from having to write the caching logic but does not provide the actual stores. There are two integrations available out of the box, for JDK java.util.concurrent.ConcurrentMap and Ehcache.

Declarative caching declaration

Threre are a few annotations in Spring which help us to configure our cache:
  • @Cacheable is used to demarcate methods that are cacheable - that is, methods for whom the result is stored into the cache so on subsequent invocations (with the same arguments), the value in the cache is returned without having to actually execute the method. It's useful to note that default cache key generation occurs depending on method arguments. So, 
  1. if method has no arguments, than 0 is used.
  2. if only one param is given, that instance is used as a key.
  3. if more than one afrgument is given, a key computed from hashes of all params is used
More info you can find in javavadoc of DefaultKeyGenerator class. There is an option to provide own implementation of key generator.
  • @CachePut as opposed to @Cacheable annotation this annotation doesn't cause the method to be skipped - rather it always causes the method to be invoked and its result to be placed into the cache.
  • @CacheEvict is useful to remove stale data from cache
But just  annotations are not enough to configure our cache. Also we have to enable annotation by specifying <cache:annotation-driven/> in the applicationContext.xml


Method visibility and caching annotations

   When using proxies, you should apply caching annotations only to public methods. If you put an annotation on private, protected or package visible method no error is raised, but caching simply will not apply.
   Also note that buy default Spring uses JDK proxying mechanism, so implemenation of a service has to be accessed through the service interface. If you access a service directly(without interface) Spring will generate the proxy class(at startup time) but in that case CGLIB 2 should be on classpath(NOTE: Spring 3.2 already has CGLIB2, so if you are the user of that version of Spring, you shouldn't additionally include this library). There is an option to change proxy mode, but be very careful, if you specify proxy-target-class="true on <cache:annotation-driven/>
Because(from Spring reference):
Multiple <aop:config/> sections are collapsed into a single unified auto-proxy creator at runtime, which applies the strongestproxy settings that any of the <aop:config/> sections (typically from different XML bean definition files) specified. This also applies to the <tx:annotation-driven/> and <aop:aspectj-autoproxy/> elements.
To be clear: using 'proxy-target-class="true"' on <tx:annotation-driven/><aop:aspectj-autoproxy/>, <cache:annotation-driven> or <aop:config/>elements will force the use of CGLIB proxies for all three of them.

 Configuring Guava Cache as Storage

    Out of the box, Spring provides integration with two storages - one on top of the JDK ConcurrentMap and one for ehcache library. To use them, one needs to simply declare an appropriate CacheManager - an entity that controls and manages Caches and can be used to retrieve these for storage. 
    In project I decided to use Guava's LoadingCache. For that purpose I've created GuavaCacheFactoryBean which helps to configure and create LoadingCache instance. Actually, I used Spring's SimpleCacheManger which uses ConcurrentMap. So, GuavaCacheFactoryBean also converts LoadingCache to ConcurrentMapCache through the Guava's  Cache#asMap() method.
 Xml configuration:

<cache:annotation-driven cache-manager="cacheManager">
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
 <property name="caches">
     <set>
         <bean parent="parentCacheFactoryBean" p:name="attributes"/>
         <bean parent="parentCacheFactoryBean" p:name="history"/>
         <bean parent="parentCacheFactoryBean" p:name="actions" p:maxSize="100"/>
            </set>
 </property>
    </bean>
<bean id="parentCacheFactoryBean" abstract="true" class="com.example.GuavaCacheFactoryBean"
      p:expirationAccessTime="120" 
      p:maxSize="200" />

NOTE: cache-manager="cacheManager" is a default attribute in <cache:annotation-driven/>
And the GuavaCacheFactoryBean code(getters and setters are omitted):
public class GuavaCacheFactoryBean implements FactoryBean<ConcurrentMapCache> {

    private String name;
    private int maxSize;
    private int expirationAccessTime;

    private ConcurrentMap<Object, Object> store;
    private ConcurrentMapCache cache;

    @Override
    public ConcurrentMapCache getObject() throws Exception {
        return cache;
    }

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

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

    @PostConstruct
    public void init() {
        this.store = CacheBuilder.newBuilder()
                .expireAfterAccess(expirationAccessTime, TimeUnit.MINUTES)
                .maximumSize(getMaxSize())
                .build().asMap();
        this.cache = new ConcurrentMapCache(this.getName(), this.store, true);
    }
   ...
}

There are many other options to configure LoadingCache via CacheBuilder, but for the purpose of the project I only need expireAfterAccess and maximumSize.

Here you can see examples of using caching annotations:

 @Caching(evict = {
            @CacheEvict(value = "attributes", key = CACHE_KEY_EXPR),
            @CacheEvict(value = "history", key = CACHE_KEY_EXPR),
            @CacheEvict(value = "actions", key = "#p0")
    })
    public void saveAction(long arg1, String arg2, long ar3) throws Exception{
              //here I make an access to db
  }

   In this example I use @Caching annotaion which is simply a grouping annotation for all cache annotations. It is used only if you have to specify a couple caching annotations on method. Also note how I access the method arguments(#p0). It's a preferred way; you can however use argument name, but it may not work since debugging info can not be included in your class files. With key attribute I specify the cache key.


Different storages

   To plug another cache back-end you have to provide CacheManager and Cache implementations. That classes tend to be simple adapters that map caching abstraction framework on top of the storage API as the ehcache classes can show.