![](/img/trans.png)
[英]How can I access methods attributes with Spring AOP (AspectJ-style)?
[英]Null pointer exception for request scoped bean using AspectJ-style Spring AOP (@Around advising an @Transactional webservice method)
我正在使用Spring 3.1.0.RC1。 我有一个基于Apache CXF的Web服务。 我试图建议每个@Transactional带注释的服务方法。
我有一些“周围”建议的方面。 在方法内部,我将数据存储到请求范围内的事务有效负载bean中。 稍后,我在另一个单例作用域的bean中从此有效载荷中请求uuid。 结果是空指针异常。
Caused by: java.lang.RuntimeException: java.lang.NullPointerException
at com.spp.mui.jaxws.service.virtual._0_1.VirtualWebService.postOfferSet(VirtualWebService.java:209)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:309)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:80)
at com.spp.mui.aop.tx.NewAgeTransactionLoggingAspect.logTransaction(NewAgeTransactionLoggingAspect.java:85)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:621)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:610)
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:65)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:161)
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:80)
at com.spp.mui.aop.ws.TraceWebServiceMethodAspect.invoke(TraceWebServiceMethodAspect.java:68)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:621)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:610)
at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:65)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:90)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
at $Proxy95.postOfferSet(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.cxf.service.invoker.AbstractInvoker.performInvocation(AbstractInvoker.java:173)
at org.apache.cxf.service.invoker.AbstractInvoker.invoke(AbstractInvoker.java:89)
... 49 more
Caused by: java.lang.NullPointerException
at com.spp.mui.jaxws.agent.WSResponseAgent.getResponse(WSResponseAgent.java:28)
at com.spp.mui.jaxws.agent.WSResponseAgent.getResponse(WSResponseAgent.java:18)
at com.spp.mui.jaxws.handler.offer.PostVirtualOffersHandler.handle(PostVirtualOffersHandler.java:58)
at com.spp.mui.jaxws.service.virtual._0_1.VirtualWebService.postOfferSet(VirtualWebService.java:205)
... 88 more
那么,此堆栈跟踪中发生了什么?
调用了Web服务方法(即postOfferSet)。 该方法是由具有@Around切入点的方面建议的。 该方法也带有@Transactional注释。
更新自此以来,我已将原始配置更新为基于Java的配置。 使用XML配置或Java配置时,都会遇到相同的问题。 我的Java配置是当前正在使用的配置,也是我想要帮助诊断的配置。 请向下滚动(向前跳)以查看下面的Java配置。 (对于其他新手,请继续阅读)。
我的方面配置看起来像
<aop:aspectj-autoproxy />
<bean id="newAgeTxLoggingAspect" class="com.spp.mui.aop.tx.NewAgeTransactionLoggingAspect">
<property name="transactionLogService" ref="txLogServiceEngine" />
<property name="securable" ref="securityAgent" />
<property name="loggableTransactionToken" ref="loggableTransactionToken" />
<property name="logQuery" value="${newAgeTxLoggingAspect.logQuery}" />
<property name="logReply" value="${newAgeTxLoggingAspect.logReply}" />
<property name="logSubmit" value="${newAgeTxLoggingAspect.logSubmit}" />
<property name="maxReplySize" value="${newAgeTxLoggingAspect.maxReplySize}" />
<property name="maxRequestSize" value="${newAgeTxLoggingAspect.maxRequestSize}" />
<property name="order" value="5" />
</bean>
如前所述,loggableTransactionToken是请求范围的。
这是它的bean定义
<!--
Request scoped bean that allows LoggableTransaction instances to be created and accessed on a single-thread of execution
Consult http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/beans.html#beans-factory-scopes-other-injection
-->
<bean id="loggableTransactionToken" class="com.spp.mui.commons.spring.LoggableTransactionToken" scope="request">
<aop:scoped-proxy proxy-target-class="false"/>
</bean>
前面提到的Web服务方法委托给Handler
这是处理程序的摘录
@Override
public ConfirmationType handle(OfferSetType request) {
// step 1: convert from JAXB type to domain objects
List<MktVirtualOffer> candidateOffers = codecService.convert(request, List.class);
...
// step 4: get response -- response encapsulates transaction id
return responder.getResponse();
}
注意处理程序使用响应程序吗?
这是响应者(又名WSResponseAgent)的摘录
@Override
public ConfirmationType getResponse() {
ConfirmationType response = new ConfirmationType();
LoggableTransaction lt = token.getToken();
response.setTransactionID(lt.getUuid());
logger.debug(ReflectUtil.toString(lt));
return response;
}
希望我已经提供了足够的帮助您帮助我了解为什么要获得NPE?
更新这是Java配置和其他暗示
AOP配置
@Configuration
@EnableAspectJAutoProxy
@Import(value = { LoggingConfig.class, AuthConfig.class })
public class AopConfig {
@Resource
private Environment env;
@Resource
private LoggingConfig loggingConfig;
@Resource
private AuthConfig authConfig;
/* Consult
* static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/transaction.html#transaction-declarative-applying-more-than-just-tx-advice
* and http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/aop.html#aop-ataspectj-advice-ordering
*/
@Bean
public NewAgeTransactionLoggingAspect txLoggingAspect() {
NewAgeTransactionLoggingAspect aspect = new NewAgeTransactionLoggingAspect();
aspect.setEnvironment(env);
aspect.setLoggableTransactionToken(loggingConfig.loggableTxToken());
aspect.setSecurable(authConfig.securable());
aspect.setTransactionLogService(loggingConfig.txLogService());
aspect.setLogQuery(Boolean.valueOf(env.getProperty("newAgeTxLoggingAspect.logQuery", Boolean.toString(true))));
aspect.setLogReply(Boolean.valueOf(env.getProperty("newAgeTxLoggingAspect.logReply", Boolean.toString(true))));
aspect.setLogSubmit(Boolean.valueOf(env.getProperty("newAgeTxLoggingAspect.logSubmit", Boolean.toString(true))));
aspect.setMaxRequestSize(Integer.valueOf(env.getProperty("newAgeTxLoggingAspect.maxRequestSize", "100000000")));
aspect.setMaxReplySize(Integer.valueOf(env.getProperty("newAgeTxLoggingAspect.maxReplySize", "100000000")));
aspect.setOrder(Integer.valueOf(env.getProperty("newAgeTxLoggingAspect.order", "5")));
return aspect;
}
}
这是配置文件中的片段,负责设置NewAgeTransactionLoggingService和LoggableTransactionToken
@Bean
public TransactionLogService txLogService() {
HibernateTransactionLogService service = new HibernateTransactionLogService();
service.setLogParameters(Boolean.valueOf(Boolean.toString(true)));
service.setTimeDispatcher(timeConfig.timeDispatcher());
service.setSessionFactory(sessionFactory);
return service;
}
/**
* @return <p>Request scoped bean that allows LoggableTransaction instances to be created and accessed on a request.<br/>
* Consult <a href="http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/beans.html#beans-factory-scopes-other-injection">Bean Factory Scopes</a></p>
*/
@Bean
@Scope(value="request", proxyMode=ScopedProxyMode.INTERFACES)
public Token<LoggableTransaction> loggableTxToken() {
// XXX Is this is the correct way to specify a request-scoped bean?
LoggableTransactionToken token = new LoggableTransactionToken();
return token;
}
这是带有@Around建议的方面的方法。
@Around("com.spp.mui.aop.Advisables.transactionLoggable()")
public Object logTransaction(ProceedingJoinPoint pjp) throws Throwable {
// Prepare to log the execution time of the method call..
long t0 = 0;
t0 = System.currentTimeMillis();
Object resultObject = null;
try {
resultObject = pjp.proceed();
} catch (Throwable t) {
logFailedTransactionAndRethrow(pjp, t0, t);
}
logSuccessfulTransaction(pjp, t0, resultObject);
return resultObject;
}
所以,我不得不自己解决这个问题。
基础:
1)创建一个自定义ServletFilter,创建LoggableTransaction并在那里设置令牌。 我扩展了Spring的OncePerRequestFilter并使用WebApplicationContextUtils在doFilterInternal方法中获取请求范围的bean。
2)在web.xml中注册此过滤器。 另外,请确保注册Spring的RequestContextListener和ContextLoaderListener。
3)上面的方面实现,保持不变,除了切入点参考。 现在,切入点引用了一种服务方法(Web服务委托给它)。
4)这是最关键的...如果令牌未实现接口,则应使用@Scope(value =“ request”,proxyMode = ScopedProxyMode.TARGET_CLASS)装饰Bean定义。 您将在类路径上需要CGLib。 无论如何,我都需要Hibernate。
之后,事情进行得很顺利。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.