-
Notifications
You must be signed in to change notification settings - Fork 785
Description
Hi!
Describe the bug
After upgrading to Spring Cloud 2021.0.0 (congratulations on the new release btw :)) in one of our projects (which uses sleuth 3.1.0 if I'm not mistaken), we run into an issue due to an incompatible TransactionManager:
org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'mongoTransactionManager' is expected to be of type 'org.springframework.data.mongodb.MongoTransactionManager' but was actually of type 'org.springframework.cloud.sleuth.instrument.tx.TracePlatformTransactionManager'Here's the full stracktrace:
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'occurrentEventStoreConfig' defined in class path resource [org/occurrent/springboot/mongo/blocking/OccurrentMongoAutoConfiguration.class]: Unsatisfied dependency expressed through method 'occurrentEventStoreConfig' parameter 0; nested exception is org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'mongoTransactionManager' is expected to be of type 'org.springframework.data.mongodb.MongoTransactionManager' but was actually of type 'org.springframework.cloud.sleuth.instrument.tx.TracePlatformTransactionManager'
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:800)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:541)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1352)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1195)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1380)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1300)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:887)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:791)
... 115 more
Caused by: org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'mongoTransactionManager' is expected to be of type 'org.springframework.data.mongodb.MongoTransactionManager' but was actually of type 'org.springframework.cloud.sleuth.instrument.tx.TracePlatformTransactionManager'
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1390)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1300)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:887)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:791)
... 129 moreSample
I'm developing an open-source project called Occurrent and it has a spring starter module that is defined like this (here's the code on github):
@Configuration
@ConditionalOnClass({SpringMongoEventStore.class, SpringMongoSubscriptionModel.class})
@EnableConfigurationProperties(OccurrentProperties.class)
@AutoConfigureAfter(MongoAutoConfiguration.class)
@Import(MongoDataAutoConfiguration.class)
public class OccurrentMongoAutoConfiguration {
@Bean
@ConditionalOnMissingBean(MongoTransactionManager.class)
public MongoTransactionManager mongoTransactionManager(MongoDatabaseFactory dbFactory) {
return new MongoTransactionManager(dbFactory, TransactionOptions.builder().readConcern(ReadConcern.MAJORITY).writeConcern(WriteConcern.MAJORITY).build());
}
@Bean
@ConditionalOnMissingBean(EventStoreConfig.class)
public EventStoreConfig occurrentEventStoreConfig(MongoTransactionManager transactionManager, OccurrentProperties occurrentProperties) {
EventStoreProperties eventStoreProperties = occurrentProperties.getEventStore();
return new EventStoreConfig.Builder().eventStoreCollectionName(eventStoreProperties.getCollection()).transactionConfig(transactionManager).timeRepresentation(eventStoreProperties.getTimeRepresentation()).build();
}
@Bean
@ConditionalOnMissingBean(SpringMongoEventStore.class)
public SpringMongoEventStore occurrentSpringMongoEventStore(MongoTemplate template, EventStoreConfig eventStoreConfig) {
return new SpringMongoEventStore(template, eventStoreConfig);
}
@Bean
@ConditionalOnMissingBean(SubscriptionPositionStorage.class)
public SubscriptionPositionStorage occurrentSubscriptionPositionStorage(MongoTemplate mongoTemplate, OccurrentProperties occurrentProperties) {
return new SpringMongoSubscriptionPositionStorage(mongoTemplate, occurrentProperties.getSubscription().getCollection());
}
@Bean
@ConditionalOnMissingBean(SpringMongoLeaseCompetingConsumerStrategy.class)
public SpringMongoLeaseCompetingConsumerStrategy occurrentCompetingConsumerStrategy(MongoTemplate mongoTemplate, List<CompetingConsumerListener> competingConsumerListeners) {
SpringMongoLeaseCompetingConsumerStrategy strategy = SpringMongoLeaseCompetingConsumerStrategy.withDefaults(mongoTemplate);
competingConsumerListeners.forEach(strategy::addListener);
return strategy;
}
@Bean
@ConditionalOnMissingBean(SubscriptionModel.class)
public SubscriptionModel occurrentCompetingDurableSubscriptionModel(MongoTemplate mongoTemplate, SpringMongoLeaseCompetingConsumerStrategy competingConsumerStrategy, SubscriptionPositionStorage storage, OccurrentProperties occurrentProperties) {
EventStoreProperties eventStoreProperties = occurrentProperties.getEventStore();
SpringMongoSubscriptionModel mongoSubscriptionModel = new SpringMongoSubscriptionModel(mongoTemplate, withConfig(eventStoreProperties.getCollection(), eventStoreProperties.getTimeRepresentation())
.restartSubscriptionsOnChangeStreamHistoryLost(occurrentProperties.getSubscription().isRestartOnChangeStreamHistoryLost()));
DurableSubscriptionModel durableSubscriptionModel = new DurableSubscriptionModel(mongoSubscriptionModel, storage);
return new CompetingConsumerSubscriptionModel(durableSubscriptionModel, competingConsumerStrategy);
}
@Bean
@ConditionalOnMissingBean(CloudEventConverter.class)
public <T> CloudEventConverter<?> occurrentCloudEventConverter(Optional<ObjectMapper> objectMapper, OccurrentProperties occurrentProperties, CloudEventTypeMapper<T> cloudEventTypeMapper) {
ObjectMapper mapper = objectMapper.orElseGet(ObjectMapper::new);
return new JacksonCloudEventConverter.Builder<T>(mapper, occurrentProperties.getCloudEventConverter().getCloudEventSource())
.typeMapper(cloudEventTypeMapper)
.build();
}
@Bean
@ConditionalOnMissingBean(CloudEventTypeMapper.class)
public CloudEventTypeMapper<?> occurrentTypeMapper() {
return ReflectionCloudEventTypeMapper.qualified();
}
@Bean
@ConditionalOnMissingBean(Subscriptions.class)
public <T> Subscriptions<?> occurrentSubscriptionDsl(Subscribable subscribable, CloudEventConverter<T> cloudEventConverter) {
return new Subscriptions<>(subscribable, cloudEventConverter);
}
@Bean
@ConditionalOnMissingBean(DomainEventQueries.class)
public <T> DomainEventQueries<?> occurrentDomainEventQueries(EventStoreQueries eventStoreQueries, CloudEventConverter<T> cloudEventConverter) {
return new DomainEventQueries<>(eventStoreQueries, cloudEventConverter);
}
@Bean
@ConditionalOnMissingBean(ApplicationService.class)
public ApplicationService<?> occurrentApplicationService(EventStore eventStore, CloudEventConverter<?> cloudEventConverter, OccurrentProperties occurrentProperties) {
boolean enableDefaultRetryStrategy = occurrentProperties.getApplicationService().isEnableDefaultRetryStrategy();
return enableDefaultRetryStrategy ? new GenericApplicationService<>(eventStore, cloudEventConverter) : new GenericApplicationService<>(eventStore, cloudEventConverter, RetryStrategy.none());
}
}In our application, we depend on this starter module from Maven. When booting this service we get the error presented above. We didn't get this when using spring-cloud-dependencies 2020.0.4.
Maybe it's a bad practice to depend on a specific implementation of the transaction manager like occurrentEventStoreConfig does? But I want to make sure that this bean receives a MongoTransactionManager and not the wrong type of PlatformTransactionManager (such as JPA). If I'm not doing things correctly, I would be happy to be corrected :)
Thanks for a great project!