![](/img/trans.png)
[英]Why NoUniqueBeanDefinitionException: No qualifying bean of type is defined: expected single matching bean but found 2
[英]Why I obtain this Spring Exception No qualifying bean of type is defined expected single matching bean but found 2?
我正在學習Spring Core認證,但我有以下疑問:
當我執行JUnit測試方法時,我會收到此錯誤消息(所提供的用戶指南期望該錯誤消息,然后說明如何修復):
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [rewards.internal.account.AccountRepository] is defined: expected single matching bean but found 2: stubAccountRepository,jdbcAccountRepository
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:970)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:858)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:811)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:739)
... 43 more
據我了解,這是因為Spring發現了多個相同類型的bean: stubAccountRepository和jdbcAccountRepository :
這是StubAccountRepository類:
/**
* A dummy account repository implementation. Has a single Account
* "Keith and Keri Donald" with two beneficiaries "Annabelle" (50% allocation)
* and "Corgan" (50% allocation) associated with credit card "1234123412341234".
*
* Stubs facilitate unit testing. An object needing an AccountRepository can
* work with this stub and not have to bring in expensive and/or complex
* dependencies such as a Database. Simple unit tests can then verify object
* behavior by considering the state of this stub.
*/
@Repository
public class StubAccountRepository implements AccountRepository {
private Logger logger = Logger.getLogger(StubAccountRepository.class);
private Map<String, Account> accountsByCreditCard = new HashMap<String, Account>();
/**
* Creates a single test account with two beneficiaries. Also logs creation
* so we know which repository we are using.
*/
public StubAccountRepository() {
logger.info("Creating " + getClass().getSimpleName());
Account account = new Account("123456789", "Keith and Keri Donald");
account.addBeneficiary("Annabelle", Percentage.valueOf("50%"));
account.addBeneficiary("Corgan", Percentage.valueOf("50%"));
accountsByCreditCard.put("1234123412341234", account);
}
public Account findByCreditCard(String creditCardNumber) {
Account account = accountsByCreditCard.get(creditCardNumber);
if (account == null) {
throw new EmptyResultDataAccessException(1);
}
return account;
}
public void updateBeneficiaries(Account account) {
// nothing to do, everything is in memory
}
}
這是** JdbcAccountRepository **:
/ ** *使用JDBC API從數據源加載帳戶。 * / @Repository公共類JdbcAccountRepository實現AccountRepository {
private Logger logger = Logger.getLogger(JdbcAccountRepository.class);
private DataSource dataSource;
/**
* Constructor logs creation so we know which repository we are using.
*/
public JdbcAccountRepository() {
logger.info("Creating " + getClass().getSimpleName());
}
/**
* Sets the data source this repository will use to load accounts.
* @param dataSource the data source
*/
@Autowired
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
public Account findByCreditCard(String creditCardNumber) {
String sql = "select a.ID as ID, a.NUMBER as ACCOUNT_NUMBER, a.NAME as ACCOUNT_NAME, c.NUMBER as CREDIT_CARD_NUMBER, b.NAME as BENEFICIARY_NAME, b.ALLOCATION_PERCENTAGE as BENEFICIARY_ALLOCATION_PERCENTAGE, b.SAVINGS as BENEFICIARY_SAVINGS from T_ACCOUNT a, T_ACCOUNT_BENEFICIARY b, T_ACCOUNT_CREDIT_CARD c where ID = b.ACCOUNT_ID and ID = c.ACCOUNT_ID and c.NUMBER = ?";
Account account = null;
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = dataSource.getConnection();
ps = conn.prepareStatement(sql);
ps.setString(1, creditCardNumber);
rs = ps.executeQuery();
account = mapAccount(rs);
} catch (SQLException e) {
throw new RuntimeException("SQL exception occurred finding by credit card number", e);
} finally {
if (rs != null) {
try {
// Close to prevent database cursor exhaustion
rs.close();
} catch (SQLException ex) {
}
}
if (ps != null) {
try {
// Close to prevent database cursor exhaustion
ps.close();
} catch (SQLException ex) {
}
}
if (conn != null) {
try {
// Close to prevent database connection exhaustion
conn.close();
} catch (SQLException ex) {
}
}
}
return account;
}
public void updateBeneficiaries(Account account) {
String sql = "update T_ACCOUNT_BENEFICIARY SET SAVINGS = ? where ACCOUNT_ID = ? and NAME = ?";
Connection conn = null;
PreparedStatement ps = null;
try {
conn = dataSource.getConnection();
ps = conn.prepareStatement(sql);
for (Beneficiary beneficiary : account.getBeneficiaries()) {
ps.setBigDecimal(1, beneficiary.getSavings().asBigDecimal());
ps.setLong(2, account.getEntityId());
ps.setString(3, beneficiary.getName());
ps.executeUpdate();
}
} catch (SQLException e) {
throw new RuntimeException("SQL exception occurred updating beneficiary savings", e);
} finally {
if (ps != null) {
try {
// Close to prevent database cursor exhaustion
ps.close();
} catch (SQLException ex) {
}
}
if (conn != null) {
try {
// Close to prevent database connection exhaustion
conn.close();
} catch (SQLException ex) {
}
}
}
}
/**
* Map the rows returned from the join of T_ACCOUNT and T_ACCOUNT_BENEFICIARY to an fully-reconstituted Account
* aggregate.
* @param rs the set of rows returned from the query
* @return the mapped Account aggregate
* @throws SQLException an exception occurred extracting data from the result set
*/
private Account mapAccount(ResultSet rs) throws SQLException {
Account account = null;
while (rs.next()) {
if (account == null) {
String number = rs.getString("ACCOUNT_NUMBER");
String name = rs.getString("ACCOUNT_NAME");
account = new Account(number, name);
// set internal entity identifier (primary key)
account.setEntityId(rs.getLong("ID"));
}
account.restoreBeneficiary(mapBeneficiary(rs));
}
if (account == null) {
// no rows returned - throw an empty result exception
throw new EmptyResultDataAccessException(1);
}
return account;
}
/**
* Maps the beneficiary columns in a single row to an AllocatedBeneficiary object.
* @param rs the result set with its cursor positioned at the current row
* @return an allocated beneficiary
* @throws SQLException an exception occurred extracting data from the result set
*/
private Beneficiary mapBeneficiary(ResultSet rs) throws SQLException {
String name = rs.getString("BENEFICIARY_NAME");
MonetaryAmount savings = MonetaryAmount.valueOf(rs.getString("BENEFICIARY_SAVINGS"));
Percentage allocationPercentage = Percentage.valueOf(rs.getString("BENEFICIARY_ALLOCATION_PERCENTAGE"));
return new Beneficiary(name, allocationPercentage, savings);
}
}
究竟是什么取決於先前的錯誤消息?
我認為這是在應用程序啟動時發生的配置問題。 這是正確的嗎?
我認為,這是由於這樣的事實,無論是類與@Repository(StubAccountRepository和JdbcAccountRepository)annoted並實現AccountRepository接口,以便能春季不知道什么類用作AccountRepository實施庫。
我的推理正確嗎?還是我錯過了什么? 您能給我更多關於這種情況的解釋嗎?
特納克斯
好吧,馬克西姆已經告訴過您了,但是為了讓您更清楚,我將嘗試更加詳細。
您有兩種“ AccountRepository”接口的實現:StubAccountRepository和JdbcAccountRepository。 當在類型'AccountRepository'上使用@Autowired批注時,只需告訴Spring執行“按類型自動裝配”。 因此,Spring檢查應該自動連接的字段的類型,並嘗試查找該類型的SINGLE bean(就像您調用ApplicationContext.getBean(AccountRepository.class)一樣)。 由於無法找到該類型的SINGLE bean,因此ApplicationContext無法啟動。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.