views:

304

answers:

3

Using Spring I've had some issues with doing a dependency injection on an annotated Aspect class. CacheService is injected upon the Spring context's startup, but when the weaving takes place, it says that the cacheService is null. So I am forced to relook up the spring context manually and get the bean from there. Is there another way of going about it?

Here is an example of my Aspect:

import org.apache.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import com.mzgubin.application.cache.CacheService;

@Aspect
public class CachingAdvice {

  private static Logger log = Logger.getLogger(CachingAdvice.class);

  private CacheService cacheService;

  @Around("execution(public *com.mzgubin.application.callMethod(..)) &&"
      + "args(params)")
    public Object addCachingToCreateXMLFromSite(ProceedingJoinPoint pjp, InterestingParams params) throws Throwable {
    log.debug("Weaving a method call to see if we should return something from the cache or create it from scratch by letting control flow move on");

    Object result = null;
    if (getCacheService().objectExists(params))}{
      result = getCacheService().getObject(params);
    } else {
      result = pjp.proceed(pjp.getArgs());
      getCacheService().storeObject(params, result);
    }
    return result;
  }

  public CacheService getCacheService(){
    return cacheService;
  }

  public void setCacheService(CacheService cacheService){
    this.cacheService = cacheService;
  }
}
+1  A: 

The problem, as I understand it, is that Spring is creating a bean of this type for you, but the AspectJ framework is also creating an instantiation of this type because it doesn't know Spring has done so.

I believe you want to give Spring a factory-method to use to instantiate the bean that also lets AspectJ know the Aspect is created:

<!-- An @Aspect-annotated class -->
<bean id="bar" class="com.foo.bar" factory-method="aspectOf">
    <property name="meaning" value="42" />
</bean>

To give due credit, I came across this question earlier today and then found an answer elsewhere later, so I'm coming back to close the loop.

I'm not crystal clear on the magic happening here, but I do see that there is an Aspects class that provides some static constructors of this flavor. Presumably AspectJ is weaving static methods of the same name onto each Aspect as well to facilitate this kind of construction.

RonU
A: 

hi there,

I also faced with such problem.

This is how it was fixed:

@Aspect
public class MyAspect {
  @Resource // telling spring that at first look up bean by name;
  Session session; // resource that won't of being setup;

  private static class MyAspectHolder {
    static final MyAspect instance = new MyAspect();
  }

  ...

  // special purpose method w/o it - stuff doesnt work;
  public static MyAspect aspectOf() {
    return MyAspectHolder.instance;
  }
}

And of course dont forget <aop:aspectj-autoproxy /> in your config along with aspect bean definition.

artemv
+2  A: 

Since the aspect is created before the Spring container, you have to retrieve the aspect from the Aspect's factory method aspectOf(ExampleClass.class).

From the Spring XML configuration, you can retrieve the aspect (object) like this:

<bean id="traceAspect" class="aspects.trace.TraceAspect"
    factory-method="aspectOf" />

Factory methods are the normal way to retrieve objects created outside the Spring container like an Enum.

Espen