Disabling Transaction Management in Spring JMS listener - spring-boot

I have a spring boot application as a Spring JMS listener. i have configured multiple datasource manager one for Oracle and another one for DB2 .
whenever i am starting app ,jms listener container is looking for a transaction manager bean and giving below error as it find two bean.
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.boot.autoconfigure.jms.JmsAnnotationDrivenConfiguration': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.springframework.transaction.PlatformTransactionManager org.springframework.boot.autoconfigure.jms.JmsAnnotationDrivenConfiguration.transactionManager; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [org.springframework.transaction.PlatformTransactionManager] is defined: expected single matching bean but found 2: db2TransactionManager,oracleTransactionManager
i dont want to maintain JMS transaction. how could i achieve it or how can we disable jms transaction feature?
below are the annotation i have added on my main spring boot class. also i am using Spring Data repository
#SpringBootApplication(exclude = { DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class})
#ComponentScan(basePackages = "com.deere.oracledataupdate.*")
//#EnableJpaRepositories(basePackages ="com.deere.oracledataupdate.dao.springdata")
#EntityScan(basePackages = "com.deere.oracledataupdate.*")
#PropertySource({ "classpath:application-${IafConfigSuffix}.properties" })
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

Looking to the current Spring Boot code we have (JmsAnnotationDrivenConfiguration):
#Autowired(required = false)
private JtaTransactionManager transactionManager;
So, right now it requires only the bean which is exactly JtaTransactionManager by type. I guess both yours are DataSourceTransactionManager.
I'm sure that was correct fix to worry only about the XA tx-manager for auto-config.
Seems for me you can fix your issue with something like #Primary on one of your tx-manager beans.
But... Do you need a JMS Annotation support in your application at all?
Maybe it would be just enough to exclude JmsAnnotationDrivenConfiguration as well?
If need it anyway, I see only one way to fix it: disable JmsAnnotationDrivenConfiguration and configure #EnableJms manually, bypassing the tx-manager issue and just don't configure it for the DefaultJmsListenerContainerFactory as you request.
See JmsAnnotationDrivenConfiguration source code for more information.

Related

#EnableAutoConfiguration(exclude =...) on tests failed in Spring Boot 2.6.0

I tried to upgrade my data-mongo example project to Spring Boot 2.6.0. There is a test designed to run against Testcontainers, I also included the embedded mongo dep for other tests, so I have to exclude the AutoConfiguration for embedded mongo to make sure this test working on Docker/testcontainers.
The following configuration worked well with Spring Boot 2.5.6.
#DataMongoTest
#ContextConfiguration(initializers = {MongodbContainerInitializer.class})
#EnableAutoConfiguration(exclude = EmbeddedMongoAutoConfiguration.class)
#Slf4j
#ActiveProfiles("test")
public class PostRepositoryTest {}
But after upgrading to Spring Boot 2.6.0 and running the application, I got the exception like this.
[ main] s.c.a.AnnotationConfigApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: o
rg.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'embeddedMongoServer' defined in class path resource [org/springframework/boot/autoconfig
ure/mongo/embedded/EmbeddedMongoAutoConfiguration.class]: Unsatisfied dependency expressed through method 'embeddedMongoServer' parameter 0; nested exception is org.springframework.bea
ns.factory.BeanCreationException: Error creating bean with name 'embeddedMongoConfiguration' defined in class path resource [org/springframework/boot/autoconfigure/mongo/embedded/Embed
dedMongoAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [de.flap
doodle.embed.mongo.config.MongodConfig]: Factory method 'embeddedMongoConfiguration' threw exception; nested exception is java.lang.IllegalStateException: Set the spring.mongodb.embedd
ed.version property or define your own MongodConfig bean to use embedded MongoDB
Obviously, #EnableAutoConfiguration(exclude =...) did not affect the context in tests when upgrading to Spring Boot 2.6.0.
Update: Temporarily resolved it, see my answer below.
Just add:
#TestPropertySource(properties = "spring.mongodb.embedded.version=3.5.5")
annotation before your Unit Test and it will start working.
#Henning's answer has a good explanation of why you need this.
As of Spring Boot 2.6, the property spring.mongodb.embedded.version must be set to use the auto-configured embedded MongoDB. It's mentioned in the release notes: https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.6-Release-Notes#embedded-mongo
This is also what the error message you posted, advises to do: Set the spring.mongodb.embedd ed.version property or define your own MongodConfig bean to use embedded MongoDB
The annotation #DataMongoTest is meta-annotated with #ImportAutoConfiguration and #AutoConfigureDataMongo, and is designed to trigger auto-configuration of MongoDB unless explicitly disabled as you do in the working configuration examples.
In your first configuration example, the annotation #EnableAutoConfiguration(exclude = EmbeddedMongoAutoConfiguration.class) does not override this effect of #DataMongoTest.
With Spring Boot 2.5.6, the auto-configured MongodConfig bean is most likely also part of the application context but not effectively used. But this depends on the rest of the code and in particular on the MongodbContainerInitializer.
Use #ImportAutoConfiguration(exclude = ...) or #DataMongoTest(excludeAutoConfiguration = ...) on test classes to overcome this barrier when upgrading to Spring Boot 2.6.0.
#DataMongoTest
#ImportAutoConfiguration(exclude = EmbeddedMongoAutoConfiguration.class)
//other config are ommitted
public class PostRepositoryTest {}
//or
#DataMongoTest(excludeAutoConfiguration = EmbeddedMongoAutoConfiguration.class)
public class PostRepositoryTest {}

Flyway 6 JavaMigrations with Native Dependency Injection for Spring Beans

I have seen many great workarounds to create Flyway JavaMigrations and injecting Spring Beans using #DependsOn and ApplicationContextAware (e.g. https://stackoverflow.com/a/48242865/5244937).
However a part of the Flyway 6 documentation claims Dependency Injection would be possible natively for Spring Beans:
https://flywaydb.org/documentation/api/hooks#java-based-migrations-as-spring-beans
https://github.com/flyway/flyway/issues/1062
Is is true? How would this work?
Mark your migrations as #Component and put them in a folder that is scanned by spring (e.g. within your application package and not in db.migrations). This will ensure #Autowired can be used because the bean is instantiated by spring. (The migrations in db.migrations will be scanned by flyway automatically and are not instantiated by spring.)
Then implement a FlywayConfigurationCustomizer to add the migrations by loading them from the spring context:
#Configuration
class FlywayConfiguration implements FlywayConfigurationCustomizer {
#Autowired
private ApplicationContext applicationContext;
#Override
public void customize(FluentConfiguration configuration) {
JavaMigration[] migrationBeans = applicationContext
.getBeansOfType(JavaMigration.class)
.values().toArray(new JavaMigration[0]);
configuration.javaMigrations(migrationBeans);
}
}

Spring Boot - Autowiring a DataSource Bean

I have a basic Spring Boot application annotated like this:
#SpringBootApplication
public class ApiApplication {
public static void main(String[] args) {
SpringApplication.run(ApiApplication.class, args);
}
}
I have the following entries in my application.properties file:
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost:5432/db
spring.datasource.username=dbuser
spring.datasource.password=dbpassword
From my understanding Spring Boot should be able to automatically autowire a DataSource Bean from these properties.
However if I try:
#Autowired
DataSource dataSource;
anywhere in my application (f.i. in #Configuration files), I get the following error in IntelliJ:
"Could not autowire. No beans of 'DataSource' type found."
Is there something obvious that I'm missing for this to work?
I have a single DataSource.
The bean actually does get initialized correctly. This is possibly just an IntelliJ tooltip bug.
Adding #SuppressWarnings to hide the message will work without further issues.
Intelij apparently even in the 2016.2 still does not support the #SpringBootApplication annotation. You either have to remove the #SpringBootApplication annotation and replace it with the #Configuration, #EnableAutoConfiguration and #ComponentScan annotations or just ignore the errors.

Implicit dependency between BeanNameAutoProxyCreator and imported configuration

At my company, we're working on an aspect-oriented trace interceptor, similar to DebugInterceptor. We're configuring a CustomizableTraceInterceptor and using a BeanNameAutoProxyCreator to auto-proxy beans for AOP.
The problem we're facing is that, when we introduce the BeanNameAutoProxyCreator in the configuration:
#Configuration
#Import(BConfig.class)
#EnableAspectJAutoProxy
public class AConfig {
#Bean
public static BeanNameAutoProxyCreator beanNameAutoProxyCreator() {
BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();
beanNameAutoProxyCreator.setInterceptorNames(new String[] {DEBUG_INTERCEPTOR_NAME});
beanNameAutoProxyCreator.setBeanNames(new String[] {BEANS_NAMES_EXPRESSION});
return beanNameAutoProxyCreator;
}
}
We get a org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [X], where X is a Resteasy Proxy. This Resteasy Proxy is declared in BConfig.
Now, if I move the Resteasy Proxy bean configuration up to AConfig, this issue is solved, and #DependsOn solves the issue too.
My questions are 3: when is Spring able to resolve dependencies between beans? Why using a BeanNameAutoProxyCreator changes this behavior? What is the recommended way of solving this issue (BeanPostProcessor, #DependsOn, etc.).
The static BeanNameAutoProxyCreator depends on a normal bean (probably due to the BEANS_NAMES_EXPRESSION). Because it is static it is loaded/bootstrapped before any other beans and especially before the bean processing #Import. So basically when analyzing which beans to process, BConfig hasn't yet been loaded. That is why it works when you move the bean to AConfig or at a depends-on for this bean.
I would probably revert the use of a BeanNameAutoProxyCreator and rely on the #EnableAspectJAutoProxy together with an aspect using the bean pointcut to attach the desired interceptor.
There is also another risk in introducing the BeanNameAutoProxyCreator next to #EnableAspectJAutoProxy it can lead to a proxy of a proxy being created, due to 2 different AOP strategies/mechanisms.

Why #Resource can't work in HttpServlet?

I am tiro to Spring, and want to use auto wire with annotation #Resource in my servlet.
In service layer and dao layer, this annotation works well, when I use it in my Servlet, the exception comes:
com.fruit.action.merchant.MerAdd.service name='merAddService' is an unknown #Resource
as you see, MerAdd is a servlet extends my own BaseServlet which extends HttpServlet, service is an object of MerAddServie, in MerAdd servlet:
#Resource(name="merAddService")
private MerAddBusiness service;
public MerAddBusiness getService() {
return service;
}
public void setService(MerAddBusiness service) {
this.service = service;
}
Is there anything I should do to fix this problem, mybe I misunderstand #Resource, can you help me , thanks ahead~
Unfortunately You cannot autowire using #Resource annotaion in Servlet.
Same Question is discussed in this spring forum link
Problem:-"The problem here is that some J2EE components have dependencies injected into them by the web container. Which means that #Resource() annotations won't work -- the container will try to resolve those dependencies to JNDI (or somewhere else)."
Possible Workaround:-
As you can use #Autowired annotation in your servlet
So You can delegate request processing to the dedicated bean which will have #Resource Bean autowired in it , i.e. make your servlet to be just an entry point that conforms to the API supported by servlet container. Hence, you can configure that actual business logic holder bean as necessary via spring and just retrieve it from IoC container and call necessary method from the servlet

Resources