Wednesday, January 22, 2014

How to inject dependencies into an Aspectj class using Spring

I've an aspect written using Aspectj at the location onramp\src\main\aspects\metrics\com\hp\cloudprint\api\onramp\reliability\metrics\MonitoringAspect.aj

When compiled, Aspectj genereates onramp\target\classes\com\hp\cloudprint\api\onramp\metrics\MonitoringAspect.class (For details about how to compile, look at the post "Compiling aspectj files declared under maven java project").

I've made my aspectj compilation optional during build time by using Maven profile to override the default aspectj plugin configuration in the onramp\pom.xml. Default plugin configuration doesn't compile aspects at the location src/main/aspects/metrics.
To compile aspects at the location src/main/aspects/metrics enter onramp>mvn clean install -Donramp.metrics=true command, which generates compiled file at the location onramp\target\classes\com\hp\cloudprint\api\onramp\metrics\MonitoringAspect.class.  

I want to inject metricsManager dependency into the MonitoringAspect.aj through Spring dependency injection.

If the MonitoringAspect.aj gets compiled always the I could have declared the below definition in the onramp\src\main\resources\applicationContext-onramp.xml


       

 
As the MonitoringAspect.aj is optionally compiled, in the default build
MonitoringAspect.class would be missing and Spring container start up fails with BeanClassNotFoundException. The alternative is to use Spring auto detection feature. This feature is available from Spring2.5. 

To enable Spring auto detection feature add to the
onramp\src\main\resources\applicationContext-onramp.xml. Add @Component annotation to
MonitoringAspect.aj. Add @Autowired annotation to each dependency to be injected in the
MonitoringAspect.aj. These annotations allow Spring to auto detect classes with the @Component annotation and register those as Spring beans and dependency inject those attributes with
@Autowired annotation. For more details about @Component refer http://www.mkyong.com/spring/spring-auto-scanning-components/

As Aspectj instantiates the MonitoringAspect.class, Spring won't get a chance to inject the dependencies. To make Spring aware of when the
MonitoringAspect.class gets instantiated, we also need to add
to the
onramp\src\main\resources\applicationContext-onramp.xml,  and @Configurable("monitoringAspect") annotation to
MonitoringAspect.aj.




pom.xml
-----------


<build>
    <finalName>onramp</finalName>
    <plugins>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>aspectj-maven-plugin</artifactId>
            <version>1.2</version>
            <configuration>
                <!-- <outxml>true</outxml>
                <showWeaveInfo>true</showWeaveInfo>
                <Xlint>warning</Xlint>
                <verbose>true</verbose> -->
            </configuration>
            <executions>
                <execution>
                    <phase>process-sources</phase>
                    <goals>
                        <goal>compile</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>
<dependencies>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.6.5</version>
        <scope>runtime</scope>
    </dependency>
</dependencies>

<profiles>
   
<profile>
       
<id>metrics</id>
       
<activation>
           
<property>
               
<name>onramp.metrics</name>
               
<value>true</value>
           
</property>
       
</activation
>
       
<build>
           
<plugins>
               
<plugin>
                   
<groupId>org.codehaus.mojo</groupId>
                   
<artifactId>aspectj-maven-plugin</artifactId>
                   
<version>1.2</version>
                   
<configuration>
                       
<aspectDirectory>src/main/aspects/metrics
>
                       
<source>1.6</source>
                       
<target>1.6</target>
                       
<!-- <outxml>true</outxml>
                       
<showWeaveInfo>true</showWeaveInfo>
                       
<Xlint>warning</Xlint>
                       
<verbose>true</verbose> -->
                   
</configuration>
                   
<executions>
                       
<execution>
                           
<phase>process-sources</phase>
                           
<goals>
                               
<goal>compile</goal>
                           
</goals>
                       
</execution>
                   
</executions>
               
</plugin>
           
</plugins>
       
</build>
   
</profile></profiles>

 applicationContext-onramp.xml
----------------------------------------

<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"
       default-autowire="byName">   
               
   
<context:annotation-config />     
  <context:component-scan base-package="com.hp.cloudprint" />
   
<context:spring-configured/>
</beans>             
   
   

   




 MonitoringAspect.aj
----------------------------
package com.hp.cloudprint.api.onramp.reliability.metrics;

import org.springframework.beans.factory.annotation.Configurable;
import com.hp.cloudprint.util.logging.EPrintLoggerFactory;
import com.hp.cloudprint.util.logging.EPrintLogger;
import com.hp.cloudprint.metrics.MetricsManager;
import com.hp.cloudprint.metrics.MetricsManagerException;
import org.springframework.security.AccessDecisionManager;
import org.springframework.security.AccessDeniedException;
import org.springframework.security.AuthenticationManager;
import org.springframework.security.AuthenticationException;
import org.springframework.security.oauth.provider.OAuthProviderProcessingFilter;
import org.springframework.stereotype.Component;
import org.springframework.beans.factory.annotation.Autowired;

@Component
@Configurable("monitoringAspect")
public aspect MonitoringAspect {
    protected static final EPrintLogger LOG = EPrintLoggerFactory.getLogger();
   
    @Autowired
    private MetricsManager metricsManager;
   
    pointcut accessDeniedException() : execution(* AccessDecisionManager.decide(..));
    pointcut authenticationException() : execution(* AuthenticationManager.authenticate(..)) || execution(* OAuthProviderProcessingFilter.validateSignature(..));
   
   
    after() throwing(AccessDeniedException ex):accessDeniedException() {
       
            LOG.debug("------------------------------------#######################authorization begin############################----------------------------------");
            try{
                metricsManager.incrementIntegerAttribute("authorizationFailures");
            }catch(MetricsManagerException x){
                LOG.debug("MonitoringMetricsException", null);
            }
            LOG.debug("------------------------------------#######################authorization end############################----------------------------------");
          
    }
   
   public void setMetricsManager(MetricsManager metricsManager){
        this.metricsManager = metricsManager;
    }
}

Followers