Reputation: 4088
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:
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.
Upvotes: 0
Views: 1595
Reputation: 280168
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.
Upvotes: 1