Question

I have a simple spring bean (that of an S2 action class) which uses autowiring to get injected with dependencies working as per usual. However when I subject one of this bean's methods to spring aop, say a @Before advice using JDK/cglib proxy, the dependency injection is skipped leaving my variables unset.

I understand this has something to do with the way spring aop accomplishes join points through proxying, but I can't find anything from the docs about this particular issue. What am I missing?

I can post the context xml too if someone needs to take a look, but it's really very simple in that, all it contains is a couple of beans for the action class, a bean for the aspect and a <aop:aspectj-autoproxy> setting.

Answer:

Here's the mistake:

<action name="sampleAction" class="com.example.s2.SampleAction" method="actionMethod">

The class attribute must have been referring to the spring bean in the spring's app context instead.

Update 1:

  1. I've tried both the JDK proxying and CGLib, and the same issue occurs in both the cases.
  2. Using bean properties to inject dependecies (instead of autowiring) didn't help either.
  3. I use spring 4.0.0.RELEASE and struts2.1.3.

Update 2 (included the code):

<!-- ======================== Spring context annotation support======================== -->
    <context:annotation-config />
    <bean id="testAspect" class="com.example.s2.aop.TestAspect" />

    <!-- ======================== AspectJ configuration======================== --> 
    <!-- Proxy-target-class must be set true if the object being proxied does not implement even a single interface (or if the advised method
           does not come from an interface. Setting this to true tells spring to use cglib for proxying -->
    <aop:aspectj-autoproxy proxy-target-class="true" />

  <!-- ======================== Spring managed beans ======================== -->
    <bean id="sampleActionBean"
            class="com.example.s2.SampleAction"
            scope="prototype">
    </bean>

    <!-- use a single offer service manager instance throughout the course of the context -->
    <bean id="dependency1" class="com.example.s2.DependencyProviderFactory" factory-method="getDependency1Instance" />

TestAspect class:

@Aspect
public class TestAspect
{
  private static final Logger SLOGGER = Logger.getLogger(TestAspect.class);
  @Before ("actionAnnotatedPointCut() && (publicActionMethodPointCut() || protectedActionMethodPointCut())")
  public void checkUserAccess(JoinPoint pJoinPoint) throws Throwable
  {
    SLOGGER.smartError("Intercepted:", pJoinPoint.getSignature().getName());
  }

  @AfterThrowing (value = "actionAnnotatedPointCut() && (publicActionMethodPointCut() || protectedActionMethodPointCut())", throwing = "pException")
  public void handlePortletException(JoinPoint pJoinPoint, Exception pException)
  {
    SLOGGER.smartError("Method threw error:", pJoinPoint.getSignature().getName(), "| Exception:", pException);
  }

  @Pointcut ("@annotation(org.apache.struts2.convention.annotation.Action")
  public void actionAnnotatedPointCut() {}

  @Pointcut ("execution(public String *(..))")
  public void publicActionMethodPointCut() {}

  @Pointcut ("execution(protected String *(..))")
  public void protectedActionMethodPointCut() {}
}

Class being advised (SampleAction):

public class SampleAction
{
  @Autowired
  private Dependency1 dependency1;
  ...
}

struts.xml:

<constant name="struts.objectFactory" value="spring" />

<action name="sampleAction" class="com.example.s2.SampleAction" method="actionMethod">
  <result name="success">/pages/actionOutput.jsp</result>
</action>

Update 3:

I think I found the problem, the class of the action in the struts config must be sampleActionBean. I know I started off this way, not sure when I reverted, my apologies.

Was it helpful?

Solution

Spring will never leave an injection target, ie. @Autowired field or method, as null. It will always throw an exception if it can't find a bean to inject.

As such, the error must be somewhere else. Seeing as you have Struts, I'm going to assume you are possibly looking at objects managed by Struts and thinking they are also managed by Spring. This is only true if your Spring-Struts integration is done appropriately.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top