Sunday 31 January 2016

Compile time weaving using aspectj

I have been working with a spring boot application(X), having aspects. In my project I am using a common library which have the common aspects and filters, which are common to all others modules. I notice that my app is taking much time,and analyse that it is because of aspects which spring by default weave at runtime. So I come up with a solution of compile time weaving with aspectj.
we can weaved dependencies at compile time & loadtime as well. I did't find a complete solution to CTW(compile time weaving) at one place, post multiple queries , get help from different forks as well.


So might be my blog can save someone else valuable time.

I opt for CTW, CTW can be of different types, we can take compiled jar and weave aspects at compile time, or we can take a completely weaved jar as apsect library.
So again I choose to weave dependency on a compiles jar(common-lib).

So if you have two module of a maven project and you want to use a common-lib to another module.So we need to do following changes.

  • In your common-lib

  1. Add annotation(@EnableSpringAnnotation) of aspectj in your config class. This annotation is Signals the current application context to apply dependency injection to non-managed classes that are instantiated outside of the Spring bean factory (typically classes annotated with the @Configurable annotation).
  2. Add annotation(@Configurable) to all Aspect/classes to tell that this object is need before the aspect comes in picture.This annotation Marks a class as being eligible for Spring-driven configuration.
  3. Add in dependency
<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.8.6</version>
  </dependency>

Once the jar is compiled and you are ready to use this jar in any other module In my case it is X,
 you need to add following in your pom.xml

  • In your module X


  1. Add dependency, you need to add common-lib in your dependency to make it available for compile time.
      <dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-aspects</artifactId>
 </dependency>
<!--my common lib jar -->
  <dependency>
   <groupId>com.demo</groupId>
   <artifactId>common-lib</artifactId>
   <version>1.0.0</version>
  </dependency>
  <dependency>
   <groupId>org.aspectj</groupId>
   <artifactId>aspectjrt</artifactId>
   <version>1.8.6</version>
  </dependency>
  <dependency>
   <groupId>javax.persistence</groupId>
   <artifactId>persistence-api</artifactId>
   <version>1.0</version>
  </dependency>
  <dependency>
   <groupId>javax.cache</groupId>
   <artifactId>cache-api</artifactId>
   <version>1.0.0</version>
  </dependency>

         2. Use aspectj-maven-plugin to compile the X application

          http://www.mojohaus.org/aspectj-maven-plugin/usage.html

<!-- aspectj plugin to weave common at compile time, excludes
tag is used to exclude the aspect which are excluded at compile time weaving,i:e
these are runtime aspects -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
    <artifactId>aspectj-maven-plugin</artifactId>
    <version>1.7</version>
     <configuration>
 <showWeaveInfo>true</showWeaveInfo>
 <encoding>UTF8</encoding>
 <complianceLevel>1.8</complianceLevel>
 <source>1.8</source>
 <target>1.8</target>
 <verbose>false</verbose>
 <excludes>
  <exclude>**/com/demo/AspectofX.java</exclude>
  <exclude>**/com/demo/AspectofX.java</exclude>
</excludes>
<outxml>true</outxml>
<aspectLibraries>
<aspectLibrary>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</aspectLibrary>
</aspectLibraries>
<weaveDependencies>
<weaveDependency>
<groupId>com.dmeo</groupId>
<artifactId>common-lib</artifactId>
</weaveDependency>
</weaveDependencies>
</configuration>
<executions>
 <execution>
  <phase>prepare-package</phase>
  <goals>
   <goal>compile</goal>
  </goals>
 </execution>
</executions>
  </plugin>

Now you can see after compilation the aspect has been weaved  with your .class files.
As I complete this the aspect in my common lib worked fine, but now a surprise... and what was that..??
That is the aspect which are in service X are not working. now what to do..??
Again after some more time investment, I came to know that I need to exclude that aspect at compile time, so <exclude> tag is used as mention above.

3. Add annotation(@EnableSpringAnnotation) of aspectj in your config class of service X as well, And @configurable for any needed object to execute the aspect

By any case if you face the multiple main class problem in while packaging of your jar, As it happen in my case ,so you need to mention it at repackage goal .
One more thing that need attention here, as we using common-lib as dependency now it is available in our lib as well. which is of no use after weavedependency. To solve this problem you can exclude the jar at the time of repackaging.

<!-- spring boot plugin to give main class and exclude common-lib
jar at the repackage goal -->
 <plugin>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-maven-plugin</artifactId>
     <version>1.2.5.RELEASE</version>
       <configuration>
         <mainClass>com.demo.X.Application</mainClass>
         <excludes>
            <exclude>
              <groupId>com.demo</groupId>
              <artifactId>common-lib</artifactId>
            </exclude>
         </excludes>
   </configuration>
 </plugin>

It also decreases my jar size .
YUPPI.. Now my compile time weaving is working fine, its simple and it reduce my application response time considerably.please feel free to share your experience and post comment in case you face any issue in implementing it.