Why DataSource cannot be autowired in spring boot application? - spring

I know that spring boot will create a dataSource Bean automatically if related configurations are set in application.properties, like:
spring.datasource.url = jdbc:mysql://192.168.10.103:3306/hms?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull
spring.datasource.username=root
spring.datasource.password=test#123
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
Application codeļ¼š
package com.synline.mdataserver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.apache.tomcat.jdbc.pool.DataSource;
#SpringBootApplication
public class Application implements CommandLineRunner {
#Autowired
AnnotationConfigApplicationContext context;
/*#Autowired
DataSource dataSource;*/
public static void main(String[] args) throws InterruptedException {
SpringApplication.run(Application.class, args);
}
#Override
public void run(String... args) throws Exception {
DataSource dataSource = (DataSource)context.getBean("dataSource");
System.out.println(dataSource);
while (true) {
Thread.sleep(5000);
}
}
}
If the #Autowired DataSource is commented out, the Bean information will be printed:
org.apache.tomcat.jdbc.pool.DataSource#1800a575{ConnectionPool[defaultAutoCommit=null; defaultReadOnly=null; ....}
So I think Spring Boot really created the Bean.
But if #Autowried DataSource is used, exception occurs to complain No Such Bean
Error creating bean with name 'application': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: org.apache.tomcat.jdbc.pool.DataSource com.synline.mdataserver.Application.dataSource; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.apache.tomcat.jdbc.pool.DataSource] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}

Your variable should be declared as a standard JDBC DataSource (i.e. javax.sql.DataSource), not as a particular implementation of that interface.

Related

Unsatisfied dependency expressed through field on factory-bean

I am getting the following error :
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'factoryBO': Unsatisfied dependency expressed through field 'cleanupProvider': No qualifying bean of type [com.spring.factory.interfaces.impl.CleanupProvider] found for dependency [com.spring.factory.interfaces.impl.CleanupProvider]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.spring.factory.interfaces.impl.CleanupProvider] found for dependency [com.spring.factory.interfaces.impl.CleanupProvider]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:573)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:350)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:775)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:861)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:541)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
at com.spring.factory.runner.FactoryRunner.main(FactoryRunner.java:10)
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.spring.factory.interfaces.impl.CleanupProvider] found for dependency [com.spring.factory.interfaces.impl.CleanupProvider]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1398)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1051)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1018)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:570)
... 15 more
Source code :
FactoryBo.java
I added #Autowired on top od CleanupProvider class; I did it for corresponding interface as well; But it didn't work for me;
package com.spring.factory.bo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.spring.factory.interfaces.ICleanupProvider;
import com.spring.factory.interfaces.impl.CleanupProvider;
#Component
public class FactoryBO {
#Autowired
CleanupProvider cleanupProvider;
public void getFactoryProviderLogic() {
cleanupProvider.performCleanup("Algo");
}
}
CleanupProvider.java
package com.spring.factory.interfaces.impl;
import com.spring.factory.interfaces.ICleanupProvider;
import com.spring.factory.interfaces.ICleanupStrategy;
public class CleanupProvider implements ICleanupProvider {
#Override
public String performCleanup(String strate) {
System.out.println("Received Text:::"+ strate);
return strate+":"+"Received";
}
#Override
public void registerStrategy(ICleanupStrategy normalizeStrategy) {
System.out.println("NormalizationProvider:::registerStrategy::");
}
}
CleanupProviderFactory .java
So, here I want to make the existing method createInstance as a factory method;
package com.spring.factory.interfaces.impl;
import com.spring.factory.interfaces.ICleanupProvider;
import com.spring.factory.interfaces.ICleanupProviderFactory;
public class CleanupProviderFactory implements ICleanupProviderFactory {
public ICleanupProvider createInstance() {
ICleanupProvider normalizeProvider = new CleanupProvider();
normalizeProvider.registerStrategy(new CleanupStrategy());
return normalizeProvider;
}
public static ICleanupProviderFactory createFactoryInstance() {
return new CleanupProviderFactory();
}
}
ICleanupProvider.java
package com.spring.factory.interfaces;
public interface ICleanupProvider {
public String performCleanup(String algo);
public void registerStrategy(ICleanupStrategy strategy);
}
ICleanupProviderFactory.java
package com.spring.factory.interfaces;
public interface ICleanupProviderFactory {
}
package com.spring.factory.runner;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.spring.factory.bo.FactoryBO;
public class FactoryRunner {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
FactoryBO bo = context.getBean(FactoryBO.class);
bo.getFactoryProviderLogic();
context.close();
}
}
spring.xml
<context:annotation-config/>
<context:component-scan base-package="com.spring.factory.bo"></context:component-scan>
<bean id="cleanupProviderFactory"
class="com.spring.factory.interfaces.impl.CleanupProviderFactory"
factory-method="createFactoryInstance"></bean>
<bean id="cleanupProvider"
class="com.spring.factory.interfaces.ICleanupProvider"
factory-bean="cleanupProviderFactory" lazy-init="default" factory-method="createInstance"></bean>
Is there anything I missed?
You can add #Component to your CleanupProvider class:
#Component
public class CleanupProvider { ...}
Or define a method to create your been like so:
#Bean
public CleanupProvider getCleanupProvider() {
return new CleanupProvider();
}
An explanation of which annotation to use is best described here: Understanding Spring #Autowired usage
I believe you just missed providing your CleanupProvider class a #Bean annotation (like #Component, #Service, #Repository, #Controller) so that bean factory recognizes it and is able to Autowire, like this Spring documentation tells you to do so.
EDIT
Ok, so have seen your spring.xml, I assume the mistake was you were declaring the bean as ICleanupProvider class, which is the interface, whereas FactoryBO autowires the implementation (CleanupProvider).

Error creating bean with name 'batchConfigurer' in Spring Boot

I have a spring batch written using Spring boot. My batch only reads from MongoDB and prints the record.
I'm not using any SQL DB nor have any dependencies declared in project but While running it I'm getting below exception:
s.c.a.AnnotationConfigApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'batchConfigurer' defined in class path resource [org/springframework/boot/autoconfigure/batch/BatchConfigurerConfiguration$JdbcBatchConfiguration.class]: Unsatisfied dependency expressed through method 'batchConfigurer' parameter 1; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'javax.sql.DataSource' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
o.s.j.e.a.AnnotationMBeanExporter : Unregistering JMX-exposed beans on shutdown
ConditionEvaluationReportLoggingListener :
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2018-06-01 10:43:39.485 ERROR 15104 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter :
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 1 of method batchConfigurer in org.springframework.boot.autoconfigure.batch.BatchConfigurerConfiguration$JdbcBatchConfiguration required a bean of type 'javax.sql.DataSource' that could not be found.
- Bean method 'dataSource' not loaded because #ConditionalOnProperty (spring.datasource.jndi-name) did not find property 'jndi-name'
- Bean method 'dataSource' not loaded because #ConditionalOnClass did not find required class 'javax.transaction.TransactionManager'
Action:
Consider revisiting the conditions above or defining a bean of type 'javax.sql.DataSource' in your configuration.
In my pom.xml I've added below dependancies:
spring-boot-starter-batch
spring-boot-starter-data-mongodb
spring-boot-starter-test
spring-batch-test
Here's my batch configuration class:
#Configuration
#EnableBatchProcessing
public class BatchConfig {
#Autowired
private JobBuilderFactory jobBuilderFactory;
#Autowired
private StepBuilderFactory stepBuilderFactory;
#Autowired
private MongoTemplate mongoTemplate;
#Bean
public Job job() throws Exception {
return jobBuilderFactory.get("job1").flow(step1()).end().build();
}
#Bean
public Step step1() throws Exception {
return stepBuilderFactory.get("step1").<BasicDBObject, BasicDBObject>chunk(10).reader(reader())
.writer(writer()).build();
}
#Bean
public ItemReader<BasicDBObject> reader() {
MongoItemReader<BasicDBObject> reader = new MongoItemReader<BasicDBObject>();
reader.setTemplate(mongoTemplate);
reader.setCollection("test");
reader.setQuery("{'status':1}");
reader.setSort(new HashMap<String, Sort.Direction>() {
{
put("_id", Direction.ASC);
}
});
reader.setTargetType((Class<? extends BasicDBObject>) BasicDBObject.class);
return reader;
}
public ItemWriter<BasicDBObject> writer() {
MongoItemWriter<BasicDBObject> writer = new MongoItemWriter<BasicDBObject>();
return writer;
}
}
Here's is my launcher class:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
#SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
public class MyBatchApplication {
...
}
Spring Batch requires the use of a relational data store for the job repository. Spring Boot enforces that fact. In order to fix this, you'll need to add an in memory database or create your own BatchConfigurer that uses the Map based repository. For the record, the recommended approach is to add an in memory database (HSQLDB/H2/etc).

Spring JPA not implementing/autowiring repository despite #EnableJpaRepositories annotation

I'm getting an exception when I start my application, where Spring complain about UnsatisfiedDependencyException:
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'applicationConfig': Unsatisfied dependency expressed through field 'controlRepository'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean found for dependency [com.oak.api.finance.repository.ControlRepository]: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:569)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
My application is organized in this format:
I declared my repository interfaces, with the proper Spring JPA annotations:
#RepositoryRestResource(collectionResourceRel = "exchange", path = "exchanges")
public interface ControlRepository extends PagingAndSortingRepository<Control, Long> {
}
I annotated the EntryPoint class that contains the main method
#SpringBootApplication
#EntityScan(basePackages = {"com.oak.api.finance.model.dto"})
#EnableJpaRepositories(basePackages = {"com.oak.api.finance.repository"})
public class EntryPoint {
public static void main(String[] args) {
Logger logger = LogManager.getLogger(EntryPoint.class);
logger.info("Starting application");
ApplicationContext ctx = new AnnotationConfigApplicationContext(ApplicationConfig.class);
// SpringApplication.run(EntryPoint.class, args);
ctx.getBean(ApplicationServer.class).start();
}
I used #Autowired to inject my repository into my spring config (java based) ApplicationConfig class:
#Autowired
private ControlRepository controlRepository;
#Autowired
private CompanyRepository companyRepository;
#Autowired
private SectorRepository sectorRepository;
Essentially I want to control the dependency on Spring and limit it to a couple of packages, (the repositories, the java config, and the program entry point - EntryPoint)
I assumed that, by specifying #EnableJpaRepositories with the package where my repositories are located, spring would create a proxy for my repository and instantiate an instance of that, and that by the time I call :
ApplicationContext ctx = new AnnotationConfigApplicationContext(ApplicationConfig.class)
The repositories instances would be present in the beans poole and would be possible to autowire them into my ApplicationConfig context, and then inject them into my controller.
This is clearly not happening, and Spring is complaining about the missing Bean to autowire, but I'm not sure what am I missing.
Below a snapshot of my packages:
any ideas?
My guess is your repositories are not being scanned, so as a result beans are not getting created. Can you try removing these 2 annotations
#EntityScan(basePackages = {"com.oak.api.finance.model.dto"})
#EnableJpaRepositories(basePackages = {"com.oak.api.finance.repository"})
And keep only #SpringBootApplication. If this is not working, you might need to check the package structure (if possible paste a screenshot here)
Edit 1
replace #SpringBootApplication with
#Configuration
#EnableAutoConfiguration
#ComponentScan("com.oak")
Edit2
Use
new SpringApplicationBuilder()
.sources(SpringBootApp.class)
.web(false)
.run(args);
Or use CommandLineRunner after changing ComponentScan path to "com.oak" as mh-dev suggested

Is it possible to inject beans using an XML file in Spring?

I am trying to inject a bean into an application using an XML file. The main function has
try(ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("/spring/application.xml")) {
context.registerShutdownHook();
app.setResourceLoader(context);
app.run(args);
} catch (final Exception ex) {
ex.printStackTrace();
}
I also have a Person POJO and is set in the xml file.
The xml defination is as follows:
<context:annotation-config/>
<bean id="person" class="hello.service.Person" p:name="Ben" p:age="25" />
<bean class="hello.HelloBeanPostProcessor"/>
The link to my repo is:
https://bitbucket.org/rkc2015/gs-scheduling-tasks-complete
It is the default guide from Spring boot that does a scheduled task.
I'm trying to inject the Person POJO defined in the xml file into a scheduled task.
I am currently getting this error:
Error creating bean with name 'scheduledTasks': Injection of autowired
dependencies failed; nested exception is
org.springframework.beans.factory.BeanCreationException: Could not
autowire field: private hello.service.Person
hello.service.ScheduledTasks.person; nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type [hello.service.Person] found for dependency:
expected at least 1 bean which qualifies as autowire candidate for
this dependency. Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
Can anyone please help? I am new to Spring.
You can use #ImportResource annotation to import xml configurations.
Documentation link
#SpringBootApplication
#EnableScheduling
#ImportResource("/spring/application.xml")
public class Application {
public static void main(String[] args) throws Exception {
SpringApplication app = new SpringApplication(Application.class);
app.run();
}
}
If this is through spring bean you should have used #component annotation for you bean definition or else i application.xml you should have defined scheduledTasks bean also and with it member variable of person so that both beans are created and can be autowired.

Spring-boot with Liquibase Overloading Property

I am using Spring boot and Liquibase.
Using this url as guidelines
http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/
In pom.xml, the below entry is present so that spring boot knows about liquibase.
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
</dependency>
and put the changelog file in resources folder.
db.changelog-master.xml
Now Spring boot first tring to find db.changelog-master.yaml in classpath and throwing the exception like this.
Cannot find changelog location: class path resource [db/changelog/db.changelog-master.yaml
To Fix the Issue, I have added the bean like below in my class and tried to set changeLog proprty.
#Configuration
#ComponentScan
#EnableAutoConfiguration
public class SampleDataJpaApplication {
#Autowired
LiquibaseProperties properties;
#Autowired
private DataSource dataSource;
#Bean
public SpringLiquibase liquibase() {
SpringLiquibase liquibase = new SpringLiquibase();
properties.setChangeLog("classpath:/db/changelog/db.changelog-master.xml");
liquibase.setChangeLog(this.properties.getChangeLog());
liquibase.setContexts(this.properties.getContexts());
liquibase.setDataSource(this.dataSource);
liquibase.setDefaultSchema(this.properties.getDefaultSchema());
liquibase.setDropFirst(this.properties.isDropFirst());
liquibase.setShouldRun(this.properties.isEnabled());
return liquibase;
}
public static void main(String[] args) throws Exception {
Logger logger = LoggerFactory.getLogger("SampleDataJpaApplication");
SpringApplication springApplication = new SpringApplication();
springApplication.run(SampleDataJpaApplication.class, args);
}
}
but it is failing with the message.
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'sampleDataJpaApplication': Injection of
autowired dependencies failed; nested exception is
org.springframework.beans.factory.BeanCreationException: Could not
autowire field:
org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties
sample.data.jpa.SampleDataJpaApplication.properties; nested exception
is org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type
[org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties]
found for dependency: expected at least 1 bean which qualifies as
autowire candidate for this dependency. Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
Caused by: org.springframework.beans.factory.BeanCreationException:
Could not autowire field:
org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties
sample.data.jpa.SampleDataJpaApplication.properties; nested exception
is org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type
[org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties]
found for dependency: expected at least 1 bean which qualifies as
autowire candidate for this dependency. Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
Please provide the inputs here, why i am getting this exception or Is there any any other available way to override the same class so that i can change the changeLog property of liquibase properties.
I'm not entirely sure what the exact runtime path to your change log is, but why don't you just use the "liquibase.*" properties in application.properties? You should be able to leave out the Liquibase #Bean and let Boot do it for you.
If you prefer to add you own Liquibase #Bean then take the hint and make sure you define a LiquibaseProperties bean as well (e.g. by declaring #EnableConfigurationProperties(LiquibaseProperties.class)).

Resources