Blog Archives

Execute before or after a spring transactional method

Spring provides a mechanism through which you can plugin some code which gets executed after the transaction is complete. We need to provide an implementation of the org.springframework.transaction.support.TransactionSynchronization interface which can be registered using TransactionSynchronizationManager. This could be useful in scenario where your code does not have a control over when the transaction starts and ends. For e.g. Your service code always joins an existing transaction started by the calling method (using REQUIRED PROPAGATION LEVEL).

Read the rest of this entry

Advertisement

Static Field Injection In Spring

Injecting static fields in a spring bean doesn’t work by simply adding @Autowired annotation as below.

@Component
public class MessageHelper {
    @Autowired
    private static MessageBean messageBean;

    public static void msg() {
        messageBean.display();
    }
}

It works either by having constructor or setter based injection.

@Component
public class MessageHelper {
    private static MessageBean messageBean;

    @Autowired
    private void setMessageBean(MessageBean messageBean) {
        MessageHelper.messageBean = messageBean;
    }

    public static void msg() {
        messageBean.display();
    }

}

Spring ignores CGLib subclasses when detecting @Transactional

Starting with spring version 3.0.4, cglib sub-classes are ignored when the spring code analyzes a class for @Transactional annotations.

Below is the method from AbstractFallbackTransactionAttributeSource class which determines if the transaction attribute is present on the method invocation. If the transaction attribute is present spring wraps the class around a proxy.

private TransactionAttribute computeTransactionAttribute(Method method, Class<?> targetClass) {
		// Don't allow no-public methods as required.
		if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
			return null;
		}

		// Ignore CGLIB subclasses - introspect the actual user class.
               Class<?> userClass = ClassUtils.getUserClass(targetClass);

		// The method may be on an interface, but we need attributes from the target class.
		// If the target class is null, the method will be unchanged.
		Method specificMethod = ClassUtils.getMostSpecificMethod(method, userClass);
		// If we are dealing with method with generic parameters, find the original method.
		specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);

		// First try is the method in the target class.
		TransactionAttribute txAtt = findTransactionAttribute(specificMethod);
		if (txAtt != null) {
			return txAtt;
		}

		// Second try is the transaction attribute on the target class.
		txAtt = findTransactionAttribute(specificMethod.getDeclaringClass());
		if (txAtt != null) {
			return txAtt;
		}

		if (specificMethod != method) {
			// Fallback is to look at the original method.
			txAtt = findTransactionAttribute(method);
			if (txAtt != null) {
				return txAtt;
			}
			// Last fallback is the class of the original method.
			return findTransactionAttribute(method.getDeclaringClass());
		}
		return null;
	}

I traced this out after I found that creation of the application context for my junit test cases failed with spring 3.0.4 jars but passed when spring 3.0.3 jars were used. My spring context xml file for the junit test cases looked similar to

    <context:component-scan base-package="sample">
        <context:exclude-filter type="regex" expression="sample.SomeService" />
    </context:component-scan>

    <bean id = "entityBasePackages" class = "java.lang.String">
        <constructor-arg value = "sample"/>
    </bean>

The junit testcase wanted to mock the class SomeService which contained @Transactional annotations hence it was excluded from the component scan.

@Service
public class SomeService {

    @Transactional
    public void transactionalMethod() {
        System.out.println("Transactional Method");
        //perform some database operations
    }
}

When the test case was executed with spring 3.0.4 jars it failed with the below error

Caused by: java.lang.IllegalArgumentException: Can not set sample.SomeService field sample.MyService.someService to $Proxy26
	at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:146)
	at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:150)
	at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:63)
	at java.lang.reflect.Field.set(Field.java:657)
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:503)
	... 43 more

The application context creation failed because spring ignored the cglib subclass which was created by EasyMock for SomeService class. Hence a JDK proxy over a CGlib proxy was created which lead to type cast failure as indicated from the error above.

The resolution to the above failure could be any of the two options below
1. Creating an interface for SomeService and replacing the class reference variable in MyService class. This would make the type cast succeed because the JDK proxy created by spring would now include the new interface in the list of proxy interfaces.

2. Remove the @Transactional annotations from the SomeService class so that spring does not create any proxies.

Self Injection in Spring

Since Spring AOP is proxy based, only ‘external’ method calls coming in through the proxy will be intercepted. i.e. This means that ‘self-invocation’, i.e. a method within the target object calling some other method of the target object, won’t lead to an actual transaction at runtime even if the invoked method is marked with @Transactional.

Why @Autowired does not work


@Service
public class UserService implements Service{
   @Autowired
   private Service self;
}

The above code throws a NoSuchBeanDefinitionException. Logically speaking @Autowired doesn’t work because the bean can’t be injected until it has been fully constructed. This means that Spring has to have injected all properties of the bean. Effectively the above code creates a circular dependency because Spring tries to instantiate the bean and when it does, it discovers that it needs to Autowire another bean. When it tries to find that bean it can’t because the bean hasn’t been added to the list of initialized beans (because it’s currently being initialized).

Alternatives

Below are couple of approaches which work.

@Service(value = "someService")
public class UserService implements Service{
   @Resource(name = "someService")
   private Service self;
}

or

@Service
public class UserService implements Service {

    @Autowired
    private ApplicationContext applicationContext;

    private Service self;

    @PostConstruct
    private void init() {
        self = applicationContext.getBean(UserService);
    }
}

Spring transaction behavior in private & internal methods

This post is to detail on the spring behavior when @Transactional annotations are applied on private methods or when transactional methods are called from within a method in the same class.

Transactional Private Methods

public class Bean {
  public void doStuff() {
     doPrivateStuff();
  }
  @Transactional
  private void doPrivateStuff() {

  }
}

...

Bean bean = (Bean)appContext.getBean("bean");
bean.doStuff();

@Transactional will have no effect if used to annotate private methods. The proxy generator will ignore them.
As per the Spring manual

Method visibility and @Transactional
When using proxies, you should apply the @Transactional annotation only to methods with public visibility. If you do annotate protected, private or package-visible methods with the @Transactional annotation, no error is raised, but the annotated method does not exhibit the configured transactional settings. Consider the use of AspectJ if you need to annotate non-public methods.

Calling internal transactional methods

public class Bean {
   public void doStuff() {
     doTransactionStuff();
   }

   @Transactional
   public void doTransactionStuff() {

   }
}

This will open a transaction:

Bean bean = (Bean)appContext.getBean("bean");
bean.doTransactionStuff();

This will not:

Bean bean = (Bean)appContext.getBean("bean");
bean.doStuff();

As per the Spring manual
Note: In proxy mode (which is the default), only ‘external’ method calls coming in through the proxy will be intercepted. This means that ‘self-invocation’, i.e. a method within the target object calling some other method of the target object, won’t lead to an actual transaction at runtime even if the invoked method is marked with @Transactional!

Consider the use of AspectJ mode if you expect self-invocations to be wrapped with transactions as well. In this case, there won’t be a proxy in the first place; instead, the target class will be ‘weaved’ (i.e. its byte code will be modified) in order to turn @Transactional into runtime behavior on any kind of method.

Summary

The @Transactional annotation defines a transaction boundary, and Spring will start/rollback/commit the transaction every time a @Transactional-annotated method is entered or exited.
If you execute a @Transactional-annotated method, and that method then calls another method in another class, and that one calls another one, which eventually does some database work, then you’re still inside the transaction.

Spring Singletons and Lifecycle Annotations

A small snippet of code to help me present the topic


@Service(name="singletonServiceBean")
@Scope(value = "singleton") //this is the default value. Explicitly setting it just for readability.
public class SingletonServiceBean {

      private Logger logger = LoggerFactory.getLogger(SingletonServiceBean.class);

      public SingletonServiceBean() {
         logger.debug("Constructor called for the service bean");
      }

      @PostConstruct
      public void initialize() {
         logger.debug("Initialize the bean in PostConstruct");
      }
}

About Singleton Beans –
After you create an application context you will notice the constructor getting called twice sometimes even if the bean is declared as singleton. The reason is – spring aop is proxy-based, i.e. the container creates ‘raw’ bean instance and proxy for it if the bean is affected by AOP rules. If you use cglib-based proxies than the proxy class is created at runtime via subclassing original bean class. So, when proxy object is created, it calls superclass constructor and it looks as two instances are created

@PostConstruct and @Predestroy- Some introduction on this

The @PostConstruct and @PreDestroy annotations(introduced with Spring 2.5) can be used to trigger Spring initialization and destruction callbacks respectively. This feature extends but does not replace the two options –  i. implementing Spring’s InitializingBean and DisposableBean interfaces
ii. explicitly declaring “init-method” and “destroy-method” attributes of the ‘bean’ element in xml. This explicit configuration is sometimes necessary, such as when the callbacks need to be invoked on code that is outside of the developer’s control. For e.g. – when a third party DataSource is used, a ‘‘destroy-method’ is declared explicitly.

To enable these lifecycle annotations we need to just add the below tag in the spring xml

<context:annotation-config/>

There are two reasons of using the @PostConstruct annotation instead of using a constructor
1. because when the constructor is called, the bean is not yet initialized – i.e. no dependencies are injected. In the @PostConstruct method the bean is fully initialized and you can use the dependencies.

2. because this is the contract that guarantees that this method will be invoked only once in the bean lifecycle. It may happen (like in the singletonServiceBean example above) that a bean is instantiated multiple times by the container in its internal working, but it guarantees that @PostConstruct will be invoked only once.

One interesting point of the annotation-based lifecycle callbacks is that more than one method may carry either annotation, and all annotated methods will be invoked

Different Singleton instances with JUnit tests

Spring provides a test annotation called @DirtiesContext which is very helpful when testing singleton beans. When added at the class level with the class mode set to AFTER_EACH_TEST_METHOD, spring creates a new application context for every test case (method). This annotation comes to your rescue when you have some state in your singleton class.