簡體   English   中英

創建了Spring bean但未自動裝配

[英]Spring bean created but not autowired

我正在嘗試在Spring中為DAO類運行TestNG測試。 但是,盡管有注釋,但DataSource參考不會自動裝配。 這是測試的一部分:

@ContextConfiguration(locations={"classpath:WEB-INF/servlet-context.xml"})
public class ToDoDaoImplTest extends AbstractTestNGSpringContextTests {

    @Autowired
    // Construction of this object fails
    private ToDoItemDaoImpl toDoDao;
}

這是我的Spring配置:

<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/view/"/>
    <property name="suffix" value=".jsp"/>
</bean>

<!-- DataSource to be injected -->
<bean id="dataSource"
      class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="org.h2.Driver" />
    <property name="url" value="jdbc:h2:mem:test" />
    <property name="username" value="sa" />
    <property name="password" value="" />
</bean>

<jdbc:initialize-database data-source="dataSource" ignore-failures="DROPS">
    <jdbc:script location="classpath:db.create.sql" />
</jdbc:initialize-database>

<context:component-scan base-package="org.myapp"/>

DAO類:

@Repository
public class ToDoItemDaoImpl implements ToDoItemDao {
    private DataSource dataSource;
    private SimpleJdbcInsert insert;

    public ToDoItemDaoImpl() {
        // dataSource is null here
        insert = new SimpleJdbcInsert(dataSource).withTableName("toDoItem").usingGeneratedKeyColumns("id");
    }

    @Autowired
    @Qualifier("dataSource")
    // This method is not called by Spring
    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }

這是錯誤的堆棧跟蹤:

Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [org.myapp.dao.ToDoItemDaoImpl]: Constructor threw exception; nested exception is java.lang.IllegalArgumentException: Property 'dataSource' is required
    at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:163)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:87)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1004)
    ... 50 more
Caused by: java.lang.IllegalArgumentException: Property 'dataSource' is required
    at org.springframework.jdbc.support.JdbcAccessor.afterPropertiesSet(JdbcAccessor.java:134)
    at org.springframework.jdbc.core.JdbcTemplate.<init>(JdbcTemplate.java:165)
    at org.springframework.jdbc.core.simple.AbstractJdbcInsert.<init>(AbstractJdbcInsert.java:97)
    at org.springframework.jdbc.core.simple.SimpleJdbcInsert.<init>(SimpleJdbcInsert.java:60)
    at org.myapp.dao.ToDoItemDaoImpl.<init>(ToDoItemDaoImpl.java:33)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
    at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:148)
    ... 52 more
null

日志的一部分顯示創建了dataSource:

DEBUG - DefaultListableBeanFactory - Creating shared instance of singleton bean 'dataSource'
DEBUG - DefaultListableBeanFactory - Creating instance of bean 'dataSource'
DEBUG - DefaultListableBeanFactory - Eagerly caching bean 'dataSource' to allow for resolving potential circular references
INFO  - DriverManagerDataSource    - Loaded JDBC driver: org.h2.Driver
DEBUG - DefaultListableBeanFactory - Finished creating instance of bean 'dataSource'
DEBUG - DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.jdbc.datasource.init.DataSourceInitializer#0'
DEBUG - DefaultListableBeanFactory - Creating instance of bean 'org.springframework.jdbc.datasource.init.DataSourceInitializer#0'
DEBUG - DefaultListableBeanFactory - Eagerly caching bean 'org.springframework.jdbc.datasource.init.DataSourceInitializer#0' to allow for resolving potential circular references
DEBUG - DefaultListableBeanFactory - Returning cached instance of singleton bean 'dataSource'

這使我感到困惑。 dataSource對象已創建,但未自動裝配到Spring管理的對象中。 我究竟做錯了什么?

問題在這里

public ToDoItemDaoImpl() {
    // dataSource is null here
    insert = new SimpleJdbcInsert(dataSource).withTableName("toDoItem").usingGeneratedKeyColumns("id");
}

在創建對象之后,Spring只能自動連接字段。 那是在構造函數完成之后發生的。

Spring將使用反射,即。 類似Class.forName(yourClass).newInstance()類的東西來創建您的bean,然后再次使用反射來設置每個屬性。

但是,在構造函數中,該字段仍為null因為這是引用類型的所有未初始化字段的默認值。

一種解決方案是將構造函數保留為空,並添加一個@PostConstruct注釋方法

@PostConstruct
public void init() {
    insert = new SimpleJdbcInsert(dataSource).withTableName("toDoItem").usingGeneratedKeyColumns("id");
}

另一種解決方案是在setDataSource()方法中添加該初始化。

除了上面的Sotirios建議之外,您還可以使用Spring的contructor-args依賴項注入來初始化dataSource。 因此,您可以將構造函數修改為:

public ToDoItemDaoImpl(DataSource dataSource) {
        this.dataSource = dataSource;
        insert = new SimpleJdbcInsert(dataSource).withTableName("toDoItem").usingGeneratedKeyColumns("id");
    }

然后,您還需要在Bean配置文件中添加以下行:

<bean id="toDoItemDaoImpl" class="mypackage.ToDoItemDaoImpl">
    <constructor-arg ref="dataSource"/>
</bean> 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM