A blog about software development and other software related matters

Blog Archive

Saturday, January 17, 2009

Demystifying Spring wiring process

Many Java applications these days make use of Spring IoC, taking the initialization management from the hand of the developer has many benefits but also has a couple of down sides like the lose of some control on the wiring process itself.

Most of the time its a none issue however there are times in which Spring fails to resolve a dependency and all that the developer is left with is a cryptic stack trace to follow.

Iv been thinking on how to make it possible to track down Spring weaving process and see at each stage what has been wired up, basically there are three approaches that iv considered:


  • The first is to hook into the injection process by some public API, iv decided to drop it since i didn't find any API which notifies me upon beans creation and wiring.

  • The second was to wire some Aspect into Spring injection process, iv started to read Spring source code and saw that pin point all the spots in code in which the wiring takes place is very tedious and error prone to start with.

  • The third option was to think on Spring as an isolated container that has to interact with the JVM in order to create and inject objects into each other, tracing this interaction sholud give us the log of the injection process itself!


A little more digging (see org.springframework.beans.BeanUtils) revealed that Spring uses Java reflection API (java.lang.reflect.Constructor.newInstance, java.lang.reflect.Field.set) in order to build/wire beans, armed with this knowledge we are only left to devise a method for tracing the calls to these methods.

A possible option is Btrace, Btrace is a Java agent modeled after DTrace which is capable of instrumenting running Java classes, using the following Btrace script would activate the tracing of the wiring process on all the classes under the com.jdftm package:

package jdftm;

import com.sun.btrace.annotations.*;
import com.sun.btrace.AnyType;
import static com.sun.btrace.BTraceUtils.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Field;


@BTrace public class ReflecTracer {
@OnMethod(
clazz="/java.lang.reflect.Constructor/",
method="/newInstance/"
)
public static void anyNewInstance(Constructor con,Object[] args) {
if(con!=null && matches("public\\scom\\.jdftm(\\.|\\w*)*\\(\\)",str(con))){
println(strcat(strcat("Object ",str(con))," got constructed"));
}
}

@OnMethod(
clazz="/java.lang.reflect.Field/",
method="/set/"
)
public static void anyFieldSet(Field field,Object obj,Object value) {
println(strcat("Set invoked on ",str(field)));
}
}


Using the script with Btrace involve two steps, compilation:
btracec ReflecTracer.java


Agent attaching (attach before context creation, debugging is an option):
btrace <process id, use jps> jdftm/ReflecTracer.class


The following beans wiring:

public class BeanA {
@Autowired
private BeanB b;
}

public class BeanB {
@Autowired
private BeanA a;
}


Produces the following traces:

Object public com.jdftm.spring.context.BeanA() got constructed
Object public com.jdftm.spring.context.BeanB() got constructed
Set invoked on private com.jdftm.spring.context.BeanA com.jdftm.spring.context.BeanB.a
Set invoked on private com.jdftm.spring.context.BeanB com.jdftm.spring.context.BeanA.b

An interesting idea that i had is to create a graph out of these traces and give the developer even better visualization on the process.

No comments: