Friday, September 30, 2011

Weavers in Spring

When we use AOP in spring then it apply advises on join point cuts. Spring uses proxy objects to apply the advices on point cuts. Weavers in Spring decide when the advices will be applied to point cuts. There are three types of weaving 
1. Run Time weaving - Spring uses Run time weaving for its interceptors.
2. Load Time weaving - Spring supports load time weaving using aop namespace.
3. Compile Time Weaving -- which Spring does not support. AspectJ supports compile time weaving.


1. Run time weaving - Spring uses run time weaving and apply the advices/interceptors on proxy objects of target bean. The problem with this approach is that if one method is being called from other method inside the target bean then the advice will only be applied to main method which is being called by client.


Example --
Below is out target bean interface and implementation



package org.paandav.springblog;
public interface TargetBeanIfc {
public void methodOne();
public void methodTwo();
}



package org.paandav.springblog;
public class TargetBean implements TargetBeanIfc {
public void methodOne() {
System.out.println("Method One Called");
}
public void methodTwo() {
methodOne();
System.out.println("Method Two Called");
}
}



Below is the before advice



package org.paandav.springblog;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
public class BeforeMethodAdvice implements MethodBeforeAdvice {


@Override
public void before(Method arg0, Object[] arg1, Object arg2)
throws Throwable {
System.out.println("Before Method Advice is called for method :"
+ arg0.getName());
}
}


Spring Config XML file:



<bean
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames" value="*Bean*" />
<property name="interceptorNames">
<list>
<value>beforeMethodAdvice</value>
</list>
</property>
</bean>
<bean id="targetBean" class="org.paandav.springblog.TargetBean"></bean>
<bean id="beforeMethodAdvice" class="org.paandav.springblog.BeforeMethodAdvice"></bean>


Test File :



package org.paandav.springblog;


import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;


public class Test {


public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"springBlogApplicationContext.xml");
TargetBeanIfc tb = (TargetBeanIfc) ctx.getBean("targetBean");
tb.methodTwo();


}
}


Result: When we run the Test.java file we get the following output



Before Method Advice is called for method :methodTwo
Method One Called
Method Two Called


So at looking at the above result we can see that Before advice has been called only one time i.e. on method which is being called from Test.java.
Since the method one is being called from inside the target bean so Spring did not apply the before advice because it apply advices on proxy which in turn call the target bean.


2. Load Time weaving: If we want to apply the advice on both method calls on TargetBean.java file then we will have to use the Load Time Weaver. It weaves the code at time of class loading. To use the Spring load time weaving we will have to configure the below XML and will have to write the pointcut and advices in java.


Below is the new LoadtimeAspect.java file



package org.paandav.springblog.loadtime;


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


@Aspect
public class LoadtimeAspect {


@Before(value="execution( * org.paandav.springblog.*.*(..))", argNames="jp")
public void beforeAdvice(JoinPoint jp)
{
System.out.println("Before Advice is called " + jp.toString());
}
}


create a new folder META-INF in classpath and create a new xml file named aop.xml with following contents



<!DOCTYPE aspectj PUBLIC
"-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>
<weaver>
<include within="org.paandav.springblog.*" />
</weaver>
<aspects>
<aspect name="org.paandav.springblog.loadtime.LoadtimeAspect" />
</aspects>
</aspectj>


Below is the Spring configuration file



<context:load-time-weaver />
<bean id="targetBean" class="org.paandav.springblog.TargetBean">      
        </bean>


Below is the LoadTimeWaverTest.java file



package org.paandav.springblog.loadtime;


import org.paandav.springblog.TargetBeanIfc;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;


public class LoadTimeWaverTest {


public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"loadTimeSpringBlogApplicationContext.xml");
TargetBeanIfc tb = (TargetBeanIfc) ctx.getBean("targetBean");
tb.methodTwo();
}


}

Result: To run the LoadTimeWaverTest.java file please pass jvm argument as 


-javaagent:C:\WorkSp\OpenOnlineExam\WebContent\WEB-INF\lib\org.springframework.instrument-3.0.5.RELEASE.jar

When we run the LoadTimeWaverTest.java file we get the following output.

Before Advice is called execution(void org.paandav.springblog.TargetBean.methodTwo())
Before Advice is called execution(void org.paandav.springblog.TargetBean.methodOne())
Method One Called
Method Two Called

So we can see that this time advice has been applied on both of the methods because the advice code has been weaved at class load time.

3. Compile Time Weaving : Spring does not support compile time weaving but we can use AsectJ for compile time weaving. 










1 comment:

  1. This post is very simple to read and appreciate without leaving any details out. Great work! asterisk dialer

    ReplyDelete