這是service介面
public interface AccountService {
public List<Account> findAll();
}
這是service介面的實作類
@Service("accountService")
public class AccountServiceImpl implements AccountService {
@Autowired
AccountDao accountDao;
@Override
public List<Account> findAll() {
System.out.println("業務層,查詢所有賬戶資訊。。。");
return accountDao.findAll();
}
}
這是controller方法
@Controller
@RequestMapping("/account")
public class AccountController {
@Autowired
private AccountServiceImpl accountService1;
@RequestMapping("/findAll")
public String findAll(){
System.out.println("表現層--AccountController.findAll()");
List<Account> list = accountService1.findAll();
for(Account a:list){
System.out.println(a);
}
return "success";
}
}
在spring中對service的實作類(AccountServiceImpl)進行宣告式事務控制,報錯,報錯核心資訊是
Bean named 'accountService' is expected to be of type 'com.service.impl.AccountServiceImpl' but was actually of type 'com.sun.proxy.$Proxy24'
找到原因是spring的事務控制是對AccountServiceImpl進行基于介面的動態代理,將controller中的自動注入型別改為
@Autowired
private AccountService accountService1;
即可。那么我就很奇怪,動態代理的原物件肯定也是存在的,為什么自動注入原物件型別會報錯呢?
而且報錯的資訊除了注入失敗以外,最主要的還是spring容器中id為accountService的bean型別本應該為AccountServiceImpl型別。spring是怎么知道bean物件原本型別的?
uj5u.com熱心網友回復:

@Autowired會自動進行型別匹配,但是你指定了bean的名稱,需要再加上@Qualifier注解并指定名稱就行了,或者直接加一個@Resources注解指定名稱就行了,至于為什么找不到,仔細去看一下@Autowired是怎么進行匹配的就知道了
uj5u.com熱心網友回復:
你controller層的注入不應該是這么寫么@Autowired
private AccountService accountService
uj5u.com熱心網友回復:
Spring 動態代理默認使用的是jdk動態代理JDK動態代理的原理是根據定義好的規則,用傳入的介面創建一個新類,所以只能用介面參考指向代理,而不能用傳入的類參考執行動態類。
例如是這個格式:
public class $Proxy1 extends Proxy implements 傳入的介面{}
如果想直接注入實作類的話,可以配置 <aop:aspectj-autoproxy proxy-target-class="true"/> 使用cglib代理;
cglib采用的是用創建一個繼承實作類的子類
uj5u.com熱心網友回復:
其實樓主記住這句話就可以了 --> 根據型別獲取bean:有介面根據介面型別獲取bean,沒有介面根據本身型別獲取bean。簡單的講解一下:
目標類被切面后,需要根據它實作的介面型別從容器中獲取bean,而不是它(實作類)本身。
容器中保存的是代理物件,代理物件也是這個介面型別。因為代理類也會去實作,實作類所實作的介面。這時代理物件和目標物件唯一產生關聯的地方,他們實作了同一個介面。
你可以嘗試獲取目標類物件的型別,他的真實型別就是一個代理($Proxy)。我們拿著這個代理物件為什么可以呼叫介面中的方法呢?就是因為代理物件也實作了目標類所實作的介面。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/284183.html
標籤:Java EE
