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

Tuesday, 19 April 2011

Introducing Cache support in Spring 3.1 M1

Spring 3.1 M1 is out with some very useful features. One of the coolest feature in the latest release is comprehensive Caching support!
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.
The cache is applied to Java methods, reducing the number of executions based on the information available. Spring checks if the given method is already executed for given set of parameters. If the method is already executed, Spring uses the cache value and returns it to caller instead of calling the method again. This is a write through cache. This way, expensive methods (whether CPU or IO bound) can be executed only once for a given set of parameters and the result reused without having to actually execute the method again. The caching logic is applied transparently without any interference to the invoker.

Adding Cache support to Spring project

In order to add Cache support to any Spring based project, one needs to declare the configuration using new Spring tag in the schema declaration.
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:cache="http://www.springframework.org/schema/cache"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd
">

<cache:annotation-driven />
...
</beans>

Note the cache:annotation-driven tag in above declaration enables the caching in given Spring project.

Using @Cacheable and @CacheEvict annotations

Spring 3.1 M1 provides two very useful Java annotations: @Cacheable and @CacheEvict which allow methods to trigger cache population or cache eviction. Let us take a closer look at each annotation:
@Cacheable("persons")
public Person profile(Long personId) { ... }

In the above code snippet, method profile is marked cacheable using @Cacheable annotation. Also the method is associated with a cache named “persons“. Whenever method profile is called, the Spring framework will check if cached entry is available in persons cache and returns the same without calling profile method.
It is also possible to provide multiple cache names if you have multiple caches declared in your application. For example:
@Cacheable({"persons", "profiles"})
public Person profile(Long personId) { ... }

In above code snippet, we provide two cache names persons and profiles. Spring framework will check in all the caches if entry is available for given method call with argument personId, if at least one cache is hit, then the associated value will be returned.

@CacheEvict annotation

Cache eviction is removing of any unused or stale data from the cache. Opposed to @Cacheable, annotation @CacheEvict demarcates methods that perform cache eviction, that is methods that act as triggers for removing data from the cache. Just like its sibling, @CacheEvict requires one to specify one (or multiple) caches that are affected by the action, allows a key or a condition to be specified but in addition, features an extra parameter allEntries which indicates whether a cache-wide eviction needs to be performed rather then just an entry one (based on the key):
@CacheEvict (value = "persons", allEntries=true)
public List<Person> listPersons()

This annotation is very useful when an entire cache region needs to be cleared out. The Spring framework will ignore any key specified in this scenario as it does not apply.

Using Default key

The cache is nothing but a key-value store which stores the data based on certain key. In Spring framework based caching, the method arguments of cached method acts as the source of Key generation. Every key is essentially the Hash-code of these arguments. This approach works well for objects with natural keys as long as the hashCode() reflects that. If that is not the case then for distributed or persistent environments, the strategy needs to be changed as the objects hashCode is not preserved. In fact, depending on the JVM implementation or running conditions, the same hashCode can be reused for different objects, in the same VM instance.
To provide a different default key generator, one needs to implement the org.springframework.cache.KeyGenerator interface. Once configured, the generator will be used for each declaration that does not specify its own key generation strategy.
By default, all the method arguments are used in Key generation logic. In practice not all methods have only one argument or, worse yet, the parameters are not suitable as cache keys – take for example a variation of the method above:
@Cacheable(value="persons", key="personId")
public Person profile(Long personId, Long groundId) { ... }

Here we are using just personId in key generation ignoring groupId altogether.

Understand Conditional caching

Spring framework also supports conditional caching letting user to cache certain methods based on some conditions. For example, in following code snippet we cache profiles only for those users who have profileId greater than 50:
@Cacheable(value="persons", condition="personId > 50")
public Person profile(Long personId) { ... }

Currently supported libraries

There are probably hundreds of cache libraries available which can be used in your JEE project. For now the Spring framework supports following implementations:
  1. JDK ConcurrentMap based Cache
  2. Ehcache based Cache

JDK ConcurrentMap based Cache

The JDK-based Cache implementation resides under org.springframework.cache.concurrent package. It allows one to use ConcurrentHashMap as a backing Cache store.

<!-- generic cache manager -->
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
<property name="caches">
<set>
<bean class="org.springframework.cache.concurrent.ConcurrentCacheFactoryBean" p:name="default"/>
<bean class="org.springframework.cache.concurrent.ConcurrentCacheFactoryBean" p:name="persons"/>
</set>
</property>
</bean>

In above code snippet, we use SimpleCacheManager class to create a CacheManager. Note that we have created two caches in our application, one is default and second is persons.

Ehcache based Cache

The Ehcache implementation is located under org.springframework.cache.ehcache package. Again, to use it, one simply needs to declare the appropriate CacheManager:
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhcacheCacheManager" p:cache-manager="ehcache"/>

<!-- Ehcache library setup -->
<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:config-location="ehcache.xml"/>

This setup bootstraps ehcache library inside Spring IoC (through bean ehcache) which is then wired into the dedicated CacheManager implementation. Note the entire ehcache-specific configuration is read from the resource ehcache.xml.

References

Friday, 25 March 2011

Spring 3.0 with EL

Spring 3.0 introduces support for expression language, which is similar to Unified EL support in jsp. The intention was to further provide different ways of setting bean properties.
The advantage of EL is that it can support different kinds of expressions like Boolean, literal ,regular , method invocation, etc.

It is also called spEL or spring EL.
Now again there are 2 methods of using EL notation - xml and annotations.

Example :
public class ErrorHandler {

private String defaultLocale;

public void setDefaultLocale(String defaultLocale) {
this.defaultLocale = defaultLocale;
}

public void handleError() {
//some error handling here which is locale specific
System.out.println(defaultLocale);
}
}

Using EL in xml  config :

<bean id="errorHandler" class="xxxx.ErrorHandler">
<property name="defaultLocate" value="#{systemProperties['user.region']}" />
</bean>

Annotation style config:

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

public class ErrorHandler {

@Value("#{ systemProperties['user.region'] }")
private String defaultLocale;

public void handleError() {
//some error handling here which is locale specific
System.out.println(defaultLocale);
}
}
Prior to Spring 3.0 , the only way to provide configuration metadata was XML.

Sunday, 20 March 2011

@Required annotation

BeanPostProcessor is used by the framework heavily. One of the best example is RequiredAnnotationBeanPostProcessor class. In spring we require @Required annotation to make it a mandatory dependency, that thas to be injected.

Just by using annotation in the code will not work, since someone has to check whether the requirement has been met or not and reposrt an error it not.

Example

//The service
public interface BankService {

public BillPaymentService getBillPaymentService();
public CustomerService getCustomerService();
}

//The impl class
public class BankServiceImpl implements BankService {

private CustomerService customerService;
private BillPaymentService billPaymentService;

@Required
public void setCustomerService(CustomerService customerService) {
this.customerService = customerService;
}

@Required
public void setBillPaymentService(BillPaymentService billPaymentService) {
this.billPaymentService = billPaymentService;
}

public BillPaymentService getBillPaymentService() {
return billPaymentService;
}

public CustomerService getCustomerService() {
return customerService;
}
}


Now here we have mentioned what is required, but we need RequiredAnnotationBeanPostProcessor to check whether these required dependency are injected or not.


The configuration


<!--  According the code, we need to set both the dependencies.
Comment out one or both the property tag and see the error -->
<bean id="bankService" class="com.xxxx.BankServiceImpl">
<property name="billPaymentService" ref="billPaymentService" />
<property name="customerService" ref="customerService" />
</bean>

<!-- Just by using @Required will not work. Someone has to parse it
and that's the role of this class -->
<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor" />


Saturday, 19 March 2011

Using annotation for configuring advices

We again take example of before advice.

Now we add @Aspect at the bean level. But on the method of the Aspect class, we can have annotations depending on what type of method or better advice they are. For before type advice we have @Before annotation.

Creating the aspect class


import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class LoggingAspect {

//TODO: Try other pointcut expressions also as mentioned in slide no. 203-207
@Before("execution(public * apply*(..))")
public void log(JoinPoint joinPoint) {
System.out.println("common logging code executed for : "+joinPoint);
}
}


Now the bean class is quite cleaner, as we are annotation:


<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
>

<aop:aspectj-autoproxy />

<bean id="customerService" class="service.CustomerServiceImpl" />

<bean id="loggingAspect" class="ex2.LoggingAspect" />

</beans>


Here we are simply logging a simple text before entering the methods. Consider the case when we want to print about arguments.


This is where JoinPoint object comes into picture.


More about JoinPoint Object


Changing the before advice to take care of arguments , etc of the methods.


import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class LoggingAspect2 {

@Before("execution(public * apply*(..))")
public void log(JoinPoint joinPoint) {
Object proxyObject = joinPoint.getThis();
Object targetBean = joinPoint.getTarget();
Object[] args = joinPoint.getArgs();
Signature signature = joinPoint.getSignature();
//some logging code here
}
}



In the above xml file just change the class name of LoggingAspect to LoggingAspect2.


As the names of the method suggest :



  • this : The current executing object that has been intercepted

  • target : The target of the execution (typically our object)

  • args -  method args

  • signature - method signation of the joinpoint

One of the reason why aspectJ was adopted by the spring was because of v.powerful and easy to learn pointcut expression, which define where our aspects will execute.

Defining scope by annotation in spring

Scope has been discussed here.
We use @Scope annotation for this.
@Repository
@Scope("singleton")
public class FlightRepositoryImpl implements FlightRepository {

Friday, 18 March 2011

Annotation approach for DI

Till now we have been seeing the xml approach. This approach was good but now a days, right from spring 2.5 annotations are more preferred. Because now it is felt, that rather than writing so much of xml, its better to put everything in java file as annotations.

Too see more on annotations, please refer this article.

It is argued that somewhere between xml approach and annotation approach, the middle approach is best, where you have some part of both.

Approach 1 : Adding beans to xml file, but getting properties bean by annotation

So @Resource annotation is used for this.

Now consider the FlightRepository class again :

package annotations;

public class FlightRepositoryImpl {

private DataSource dataSource;

@Resource (name="ds")
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
}


Once putting the annotation on the setter of the method, we have to activate this annotation in the descriptor file using  <context :  annotation-config>.


<import resource="db-config.xml" />
<!--just define that we are using annotation, and flightrepository can refer to this -->
<context:annotation-config />
<bean id="flightRepo" class="annotations.FlightRepositoryImpl" />


Approach 2 : Avoid configuring beans to xml file, doing everything by annotation


Here @Component annotation is used.


Any bean marked by @Component annotation is marked by the IoC container on startup and will be loaded automatically.


To make it more clear spring introduced @Service, @Repository and @Controller stereotypes to distinguish between the same.


Now consider our repository :


package annotations;

@Repository
public class FlightRepositoryImpl {

private DataSource dataSource;
@Resource (name="ds")
public FlightRepositoryImpl2(DataSource dataSource) {
this.dataSource = dataSource;
}
}




Now in the config file we simply add <context:component-scan>.


<import resource="db-config.xml" />
<!-- Needed in the xml file to tell the container about fully annotated components, so it will search in whole package specified, to find all annotations and act accordingly -->
<context:component-scan base-package="annotations" />

 

 





Note that @Resource annotation can be used to inject dependencies by setter or fields.

Annotation approach for constructor injection

To do this we simply have to use @Autowired at the constructor, and @Repository as usual over the bean.

package annotations;
@Repository
public class FlightRepositoryImpl {


private DataSource dataSource;

@Autowired
public void FlightRepositoryImpl (DataSource dataSource) {
this.dataSource = dataSource;
}
}