Я использую Spring 3.1.0.RC1. У меня есть веб-сервис на основе Apache CXF. Я пытаюсь рекомендовать каждый аннотированный метод обслуживания @Transactional.
У меня есть аспект с некоторыми советами. Внутри метода я сжимаю данные в бин полезных данных транзакции в области запроса. Позже я прошу 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
Так что же происходит в этой трассировке стека?
Был вызван метод веб-службы (то есть postOfferSet). Этот метод был рекомендован аспектом с @Around pointcut. Этот метод также аннотирован @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 является областью запроса.
Вот бобовое определение для него
<!--
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>
Упомянутый выше метод веб-службы делегирует Обработчику
Вот фрагмент из обработчика
@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();
}
Заметили, что обработчик использует ответчик?
Вот фрагмент из ответчика, a.k.a. 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 config
@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 advice.
@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;
}