DataSource conflict in Spring Batch and Spring Batch admin integration - spring

I am using Spring Batch Framework in my application, in which I have successfully integrated Spring Batch Admin. When I am trying to Create bean for JdbcTemplate. it is giving me following error:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSourceInitializer': Invocation of init method failed; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [javax.sql.DataSource] is defined: expected single matching bean but found 2: dataSource,phoenixDataSource
where 'dataSource' is used by Spring Batch Admin, and 'phoenixDataSource' is created by me. how do I differentiate in both, is there any way to provide #Qualifier to BatchAdmin used dataSource.

My suggestion is that you rename phoenixDataSource to dataSource and load your application context first before the spring batch admin beans.

An addition to #Ashish, you may use a Qualifier for referencing the datasource that you want to use.
#Qualifier("phoenixDataSource")
private Datasource datasource;
#Qualifier("phoenixDataSource")
public class PhoenixDatasource{
}

Related

Unable to create retry-able datasource for spring boot jdbc

I would like to add the retry feature for database connection certain number of times until the app acquires it. For the I have used the spring-retry on the DataSource but it is not working. It is throwing the following error
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'jdbcTemplate' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/JdbcTemplateConfiguration.class]: Unsatisfied dependency expressed through method 'jdbcTemplate' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Hikari.class]: Initialization of bean failed; nested exception is java.lang.IllegalArgumentException: ExistingValue must be an instance of com.zaxxer.hikari.HikariDataSource
I have seen the debug logs but those are not helpful. Here is the sample source code . kindly help
Note: the dependencies mentioned in build.gradle is required for my app. I have only extracted the retry part.
Your use-case is delaying the start of Spring Boot until your database is up. Spring actually ships with a component that does that. The DatabaseStartupValidator is that component and has existed since about Spring 1.x.
You can add it as a bean and it will wait for further bootstrapping until the database is up.
#Bean
public DatabaseStartupValidator databaseStartupValidator(DataSource dataSource) {
var dsv = new DatabaseStartupValidator();
dsv.setDataSource(dataSource);
return dsv;
}
For a more detailed explanation see this blog post of mine.

How to avoid spring application failure due to BeanCreationException caused by third party package

I am using a third-party package in my spring boot app. This one to be specific. This package has a method that creates a bean when the application starts. The bean is only created successfully if this package is able to talk to nats service. In most cases, this all works fine. The remote server is available, the bean is created, my spring boot apps boots up correctly.
But there are some edge cases when remote nats servers might not be up. This causes my spring boot app to fail to start as the above function throws BeanCreationException
How can I avoid this i.e avoid my spring app boot failure due to this exception when the nats server is not up?
Note: It is fine for my spring app/business logic to be up and running if this bean (connections to nats service) is not available.
Specific Exception :
org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'natsConnection' defined in class path resource [io/nats/spring/boot/autoconfigure/NatsAutoConfiguration.class]:
Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [io.nats.client.Connection]:
Factory method 'natsConnection' threw exception; nested exception is java.io.IOException: Unable to connect to NATS server.\n\tat org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:655)\n\tat org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:635)\n\tat org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1336)\n\tat org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1176)\n\tat org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:556)\n\tat org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:516)\n\tat org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:324)\n\tat org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)\n\tat org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:322)\n\tat org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)\n\tat org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:897)\n\tat org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:879)\n\tat
The bean natsConnection is created by auto-configuration and annotated with #ConditionalOnMissingBean. Such beans are instantiated after your own beans.
You can create your own bean of this type, io.nats.client.Connection, and register it as natsConnection. This bean should have no own logic. When called for the first time, it should create a worker instance via NatsAutoConfiguration.natsConnection(...) and then delegate all calls to it.
Because of #ConditionalOnMissingBean the default bean from the NATS library will not be instantiated and only your bean will be created.

Issue with spring cloud task mutiple datasources

I configured two data sources in my app following the guide of spring example:https://github.com/spring-cloud/spring-cloud-task/blob/master/spring-cloud-task-samples/multiple-datasources.
The spring boot version I use is :2.0.0.RELEASE
The spring.cloud.task.version I use is :1.2.2.RELEASE.
This application works fine in my local computer, But when deploy to the to AWS, I got the following error with the defination of class:CustomTaskConfigurer.java.
which defined the same as here:https://github.com/spring-cloud/spring-cloud-task/blob/master/spring-cloud-task-samples/multiple-datasources/src/main/java/io/spring/configuration/CustomTaskConfigurer.java
The error message is like below:
exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.cloud.task.configuration.SimpleTaskConfiguration': Invocation of init method failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'customTaskConfigurer' defined in file [/home/vcap/app/BOOT-INF/classes/com/xxx/configuration/CustomTaskConfigurer.class]: Bean instantiation via constructor failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.xxx.configuration.CustomTaskConfigurer$$EnhancerBySpringCGLIB$$bc80cd46]: Constructor threw exception; nested exception is java.lang.IllegalStateException: Unable to create a TaskExecutionDao.
The root cause for this error is that when I developed the application locally I configure a local datasource bean for postgresql like below:
#Bean
#Primary
#ConfigurationProperties("spring.datasource")
public HikariDataSource sourceDataSource() {
return DataSourceBuilder.create().type(HikariDataSource.class).build();
}
This bean read the properties in the application.properties file which identify the username and password url for the local postgres.
When This application deloyed to cloud,It will connect to the cloud data base instead of the local databases, which means the url,username,and password are no longer correct.
After add the configuration for cloud, this error disppeared.
But this exception stack trace only tell you that it is unable to create taskExecutionDao, It is really hard for the user to fix the issue when see such a error message
If it is a multiple datasource issue, you can try marking it as #Primary. Providing a better stack trace is helpful.

java version "1.8.0_121" Requested bean is currently in creation: Is there an unresolvable circular reference?

When I build and deploy my spring based Application with
java version "1.8.0_112" it compiles and deploys fine.
Also, if i compile with java version "1.8.0_121", and deploy with
java version "1.8.0_112" that works too.
But when I compile and deploy the same Application with
java version "1.8.0_121"
it gives me an error for one service:
Error creating bean with name 'namesServiceImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private a.b.c.backend.services.account.PersonService a.b.c.backend.services.serviceimpl.NamesServiceImpl.personService; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'CISExpressionHandler' defined in URL
[jar:file:/usr/local/tomcat7-7/webapps/ServicesApp/WEB-INF/lib/E2Services.jar!/META-INF/spring/applicationContext-security.xml]: Cannot resolve reference to bean 'CISPermissionEvaluator' while setting bean property 'permissionEvaluator'; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'CISPermissionEvaluator': Requested bean is currently in creation: Is there an unresolvable circular reference?
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private a.b.c.backend.services.ciscase.CaseService a.b.c.backend.services.security.permissionEvaluators.CaseOwnerPermission.caseService; nested exception is org.springframework.beans.factory.BeanCreationException
One explanation, I could find was:
The exception may or may not occur depends on the creation order of beans. We load them with config something like below in web.xml
(/usr/local/tomcat7-7/webapps/ServicesApp/WEB-INF/web.xml)
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:META-INF/spring/applicationContext*.xml</param-value>
</context-param>
The XML files will be loaded by XmlWebApplicationContext class and the loading order of files are not guaranteed.
It just loads files from the file system. The problem is here.
There's no problem if the class loads the application context file first, because your beans are already created when they are used for the construction injection of Spring Security. But, if it loads the Spring Security context file first, the circular reference problem occurs, because Spring tries to use your beans in the constructor injection before they had been created.
How to solve the problem?
Force the loading order of the xml files. loading the security context xml file at the end of the application context file by using
<import resource="applicationContext-security.xml">.
Now how this got introduced with JDK version change? I don't have an explanation for that
ref: Splitting applicationContext to multiple files
Q: How do i get the order of beans at deployment ?

Autowiring fails IllegalArgument un-safe operation exception

I am getting the following exception after upgrading my Spring jars.
org.springframework.web.servlet.DispatcherServlet - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.integration.transformer.HeaderEnricher#4': Cannot create inner bean '(inner bean)' of type [org.springframework.integration.transformer.HeaderEnricher$MessageProcessingHeaderValueMessageProcessor] while setting constructor argument with key [#{partnerHeaderKey}]; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#19': Injection of resource dependencies failed; nested exception is java.lang.IllegalArgumentException: Can not set com.follett.fheg.coursemateriallookup.coursematerial.data.dao.PartnerDAO field com.follett.fheg.coursemateriallookup.coursematerial.integration.headerenricher.PartnerHeaderEnricher.partnerDAO to org.springframework.integration.transformer.HeaderEnricher$MessageProcessingHeaderValueMessageProcessor
at org.springframework.beans.factory.support.BeanDefinitionValue Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#19': Injection of resource dependencies failed; nested exception is java.lang.IllegalArgumentException: Can not set com.follett.fheg.coursemateriallookup.coursematerial.data.dao.PartnerDAO field com.follett.fheg.coursemateriallookup.coursematerial.integration.headerenricher.PartnerHeaderEnricher.partnerDAO to org.springframework.integration.transformer.HeaderEnricher$MessageProcessingHeaderValueMessageProcessor
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessPropertyValues(CommonAnnotationBeanPostProcessor.java:306)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1146)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:271)
... 40 more
Caused by: java.lang.IllegalArgumentException: Can not set com.follett.fheg.coursemateriallookup.coursematerial.data.dao.PartnerDAO field com.follett.fheg.coursemateriallookup.coursematerial.integration.headerenricher.PartnerHeaderEnricher.partnerDAO to org.springframework.integration.transformer.HeaderEnricher$MessageProcessingHeaderValueMessageProcessor
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:146)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:150)
at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:37)
at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:57)
at java.lang.reflect.Field.set(Field.java:657)
at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:150)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessPropertyValues(CommonAnnotationBeanPostProcessor.java:303)
... 44 more
From what I have read I needed to add #Component annotation to my bean and/or create the in my application context - neither of these approaches have worked. The DAO it is referring to is declared like so <bean id="partnerDAO" class="com.follett.fheg.coursemateriallookup.coursematerial.data.dao.impl.PartnerDAOImpl"/>. If I remove the #Component annotation I get a red line under #Autowired and a message that says "Autowired members must be defined in the valid spring bean (#Component/#Service etc..)", but after doing that i still get the errors.
I am using Spring integration so the bean to auto-wire is defined there.
<integration:header-enricher>
<integration:header name="#{partnerHeaderKey}" method="getPartner">
<bean class="com.follett.fheg.coursemateriallookup.coursematerial.integration.headerenricher.PartnerHeaderEnricher"/>
</integration:header>
</integration:header-enricher>
Any thoughts or help is appreciated! Thank you.
Note: the application runs fine if I drop back down to Spring 2.1.4.RELEASE even without declaring the #Component or <bean> in the application context.
UPDATE
As blackpanther mentions below I need a element in the application context. I failed to mention that I DO Have this <context:component-scan base-package="com.follett.fheg.coursemateriallookup.coursematerial.integration.headerenricher" /> There is another for the DAO's as well <context:component-scan base-package="com.follett.fheg.coursemateriallookup.coursematerial.data.dao" />
Not exactly, just putting the annotation #Component does not mean that that Java class will have it's properties autowired. In order to use the #Component annotation effectively, you must tell Spring where to look for these classes. This is done by the <context:component-scan base-package="package.name" /> tag in your Spring configuration.
I would have a look at this article as it may help you.
You can specify #Qualifier on top of the bean declaration inside the component like below.
#Autowired
#Qualifier("loginService")
private ILoginService loginService;
loginService is the name of the bean in the .xml context file.
I was able to resolve this issue by using #Component annotation as well as modifying the way the beans were created in the context.
For some reason when I moved the <bean class=""> out of the <integration:header> and added a ref-"" attribute it started working just fine. I am getting a different error, but I was able to get the application running.
old way
<integration:header-enricher>
<integration:header name="#{partnerHeaderKey}" method="getPartner">
<bean class="com.follett.fheg.coursemateriallookup.coursematerial.integration.headerenricher.Partner HeaderEnricher"/>
</integration:header>
</integration:header-enricher>
new way
<integration:header-enricher>
<integration:header name="#{partnerHeaderKey}" method="getPartner" ref="myBean">
</integration:header>
</integration:header-enricher>
</integration:chain>
<bean id="myBean" class="com.follett.fheg.coursemateriallookup.coursematerial.integration.headerenricher.PartnerHeaderEnricher"/>

Resources