darc darc - 1 month ago 4
Java Question

How to properly @Autowire Property and use it in other bean

I am new to spring and I want to use as less as xml configuration. I am trying to Autowire BasicDataSource property but getting errors. I know I am missing something but what I don't know or I am using wrong approach.

public class DataS {

private BasicDataSource bds;

public BasicDataSource getBds() {
return bds;
}

@Autowired
public void setBds(BasicDataSource bds) {
bds.setDriverClassName("oracle.jdbc.driver.OracleDriver");
bds.setUrl("jdbc:oracle:thin:@127.0.0.1:1521:xe");
bds.setUsername("user");
bds.setPassword("123454");
this.bds = bds;
}
}


JdbcTemplate Class

public class TemplateClass {
private JdbcTemplate template;

@Autowired
public void setDataSource(BasicDataSource dataSource) {
this.template = new JdbcTemplate(dataSource);
}
}


XML

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">

<context:annotation-config/>
<context:component-scan base-package="com.example.ds"/>
<bean id="bds" class="com.example.ds.DataS"/>
<bean id="template" class="com.example.ds.TemplateClass"/>
</beans>


I am getting following error

Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataS': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void com.example.ds.DataS.setBds(org.apache.tomcat.dbcp.dbcp2.BasicDataSource); nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.apache.tomcat.dbcp.dbcp2.BasicDataSource] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataS': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void com.example.ds.DataS.setBds(org.apache.tomcat.dbcp.dbcp2.BasicDataSource); nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.apache.tomcat.dbcp.dbcp2.BasicDataSource] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334)
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:772)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:839)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:538)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
at com.example.ds.test.main(test.java:10)
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void com.example.ds.DataS.setBds(org.apache.tomcat.dbcp.dbcp2.BasicDataSource); nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.apache.tomcat.dbcp.dbcp2.BasicDataSource] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:661)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331)
... 13 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.apache.tomcat.dbcp.dbcp2.BasicDataSource] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1373)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1119)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1014)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:618)


One thing that makes me confuse about @Autowired is how can we reference other bean. Like

<bean id="bds" class="...dbcp2.BasicDataSource">
<property name=''.../>
.
.
</bean>
<bean id="template" class="...pkg.templateClass">
<property name="dataSource" ref="bds"> <!--- how can we achieve this using annotation -->
</bean>

Answer

Your stack trace says that your application context cant find any valid spring bean of class BasicDataSource and thus cannot autowire it.

To make your application xml-less, try to write @Configuration class, it can look like this:

@Configuration
@ComponentScan("com.example.ds")
public class AppConfig {

    @Bean
    public BasicDataSource basicDataSource() {
        BasicDataSource bds = new BasicDataSource(); //or other subclass
        bds.setDriverClassName(...);
        // etc
        return bds;
    }
}

And then you can simply autowire it to your class:

@Component
public class DataS {

    private BasicDataSource bds;

    public BasicDataSource getBds() {
        return bds;
    }

    @Autowired
    public DataS(BasicDataSource bds) {
        this.bds = bds;
    }
}

Or using field injection:

@Component
public class DataS {
    @Autowired
    private BasicDataSource bds;
    ....
}
Comments