Вот еще одна возможность решить эту проблему. Это относится к следующему вопросу переполнения стека: Перехватчики Spring WS с введенным @Transactional DAO не работают . Короче говоря, проблема заключается в том, что метод
@Override
public void addInterceptors(List<EndpointInterceptor> interceptors) {
вызывается до того, как внедрение зависимостей Spring успеет зарегистрировать bean-компоненты Spring AOP. В моем случае это был @Transactional, который был проигнорирован Spring-WS, но это могло быть что угодно.
К счастью для нас, Spring-WS использует изменяемые коллекции вместо неизменяемых. Когда метод addInterceptors()
вызывается, мы можем просто сохранить коллекцию, и, таким образом, у нас есть ссылка на тот же экземпляр коллекции, который используется Spring-WS. Позже вы можете правильно инициализировать ваш bean-объект-перехватчик и добавить его в коллекцию.
Вы также должны обойти тот факт, что если вы используете @Autowired
, бин готовится до того, как аннотации могут иметь место. Таким образом, вы должны создать его вручную, вызвав метод ApplicationContext.getBean()
.
@EnableWs
@Configuration
// The magic is to implement both ApplicationContextAware
// that injects the applicationContext for us
// and BeanPostProcessor that gives us postProcessBeforeInitialization()
// where we initialize our interceptor correctly
// and add it to the collection
public class WebServiceConfig extends WsConfigurerAdapter implements ApplicationContextAware, BeanPostProcessor {
// This is the interceptor that uses dependencies with @Transactional annotation.
// It will not work with @Autowired
private MyInterceptorThatHasTransactionalDependencies myInterceptorThatHasTransactionalDependencies;
// Fortunately Spring WS uses mutable collections so we can fill
// this list later on as long as we just initialize it with
private List<EndpointInterceptor> interceptors;
// This is our application context where all the beans are defined
private ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
// save application context for later use
this.context = applicationContext;
}
@Nullable
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// This method gets called multiple times so initialize interceptor just once
if(myInterceptorThatHasTransactionalDependencies == null){
myInterceptorThatHasTransactionalDependencies = context.getBean(MyInterceptorThatHasTransactionalDependencies.class);
interceptors.add(myInterceptorThatHasTransactionalDependencies);
}
return bean;
}
@Override
public void addInterceptors(List<EndpointInterceptor> interceptors) {
// Save the list of interceptors so we can modify it later on
this.interceptors = interceptors;
if (myInterceptorThatHasTransactionalDependencies == null) {
System.out.println("myInterceptorThatHasTransactionalDependencies was null like we expected");
} else {
interceptors.add(myInterceptorThatHasTransactionalDependencies);
}
}
}
Просто чтобы вы знали, что я не являюсь экспертом по жизненному циклу bean-компонента Spring, так что может быть лучшее место для инициализации перехватчика, чем postProcessBeforeInitialization()
. Тем не менее, это работает для меня.