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:
- I've tried both the JDK proxying and CGLib, and the same issue occurs in both the cases.
- Using bean properties to inject dependecies (instead of autowiring) didn't help either.
- 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.