One of the frequent patterns I make use of for Java backend systems are transactional code blocks, and not transactional in the sense of JPA, Hibernate, Databases, etc. I mean generic transactional blocks in which you have to wrap a piece of code with a begin and end block. For example, JPA is just one style in which you invoke:
try { em.getTransaction().begin(); // invoke code } finally { em.getTransaction().end(); }
Another common example is using pools in which you must borrow and return objects such as:
Object data = null; try { data = pool.borrowObject(); // do something } finally { pool.returnObject(data); }
These are just common examples. Often times, I have my own type of transactional block that references some other type of system that must maintain a begin and end state. However, even as simple as
try { begin(); } finally { end(); }
is, it can easily be screwed up. For example, a common mistake is forgetting to put the end() in a finally block to ensure it runs. Further, it violates the DRY (don’t repeat yourself) principle such that if you need to change the processing a bit, you would need to change every invocation of begin/end. That creates a possible maintenance issue.
So, how do we avoid using transactional blocks? The easiest solution is something that most modern libraries such as Spring or Java EE already do, which is creating proxy classes to invoke the blocks automatically. If you are already using Spring or Java EE, you prolly already do this with the @Transactional annotation. However, this post will help demonstrate a simple and easy method of achieving this same behavior for custom transactional blocks.
The first step is creating a marker annotation that will be used on classes and methods to denote a transactional block of code. For example:
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD}) public static @interface Transactional { // annotation specific values }
This annotation allows us to mark either a class or a method. This is basically what the Spring/Java EE Transactional annotation does. The next thing we need to do is actually mark methods as transactional. We can do this either at the class level meaning every method in the class will be transactional or at the method level. The choice is completely a personal preference. However, if you mark the class, then you can ensure that every method will be transactional even if you add a new method. That will help reduce the accidental likelihood of adding a new method but forgetting the transaction annotation. However, if you do not want certain methods to be wrapped in a transactional block, then you will need to annotate at the method level one by one. Here is an example:
@Transactional public class Test1 { public void method1() { // this will be invoked in transactional block } public void method2() { // so will this } } public class Test2 { public void method3() { // this will not be transactional } @Transactional public void method4() { // but this will } }
Now that we have our transactional code we need to create proxy classes to automatically wrap the code. My preferred way of achieving this and the purpose of this blog is to use CGLIB proxy classes. There are several other ways to achieve such as AspectJ. I will leave learning those ways to the reader. Anyways, back to CGLIB. CGLIB provides a proxy creation class called Enhancer. It is very similar to the Proxy class in the standard Java reflection package. However, there is one major difference. The standard Java Proxy class may only use and proxy interfaces, not concrete classes. Enhancer and CGLIB can proxy concrete classes. It is concrete classes that are essential so that we can proxy our existing classes and wrap the methods in transactional code block. Before we can use CGLIB, we must add it to our classpath. The version I am actively using is 2.1_3. You can either download the JARs directly or use the following Maven dependency:
<![CDATA[ <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>2.1_3</version> </dependency> ]]>
Once you have added CGLIB, here is the basic way of creating those blocks:
public class Transactions { @SuppressWarnings("unchecked") public static <T> T proxy(final T object) { // check if transactional specified at class level of class or // any parent classes or interfaces boolean isTransactional = false; Class<?> parent = object.getClass(); while (!isTransactional && parent != null) { if (parent.getAnnotation(Transactional.class) != null) { isTransactional = true; } for (Class<?> ifclass : parent.getInterfaces()) { Class<?> ifparent = ifclass; while (!isTransactional && ifparent != null) { if (ifparent.getAnnotation(Transactional.class) != null) { isTransactional = true; } ifparent = ifparent.getSuperclass(); } } parent = parent.getSuperclass(); } // create proxy class from concrete class final boolean transactional = isTransactional; return (T) Enhancer.create(object.getClass(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // check if transactional at class level or if current method // is transactional. Note that this ignore overrides. You // may want to extend this to search for all subclasses and // interfaces defining the method and check those annotatations // as well if (transactional || method.getAnnotation(Transactional.class) != null) { try { // start transaction block // this could be anything you needed to do such as borrow // from a pool, etc Transactions.begin(); // invoke method and return its value if provided return method.invoke(object, args); } finally { // finalize the block // this should be the corresponding end block to the begin block Transactions.end(); } } // not transactional, so invoke as normal else { return method.invoke(object, args); } } }); } }
Now that we have that code in place, we can create proxy classes and invoke the methods without worrying about the transactional blocks. Going back to our initial test class, we could invoke via:
Test1 test = Transactions.proxy(new Test1()); test.method2(); // this will be invoked in a transactional block
That’s all there is to it.
