Spring5 AOP程式設計:關於org.springframework.beans.factory.BeanNotOfRequiredTypeException報錯
Spring5 AOP程式設計:關於org.springframework.beans.factory.BeanNotOfRequiredTypeException報錯
先上錯誤詳細資訊:
org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'bookDaoImpl' is expected to be of type 'com.atguigu.dao.BookDaoImpl' but was actually of type 'com.sun.proxy.$Proxy19'
直譯過來大概意思是說:這個叫做bookDaoImpl的Bean,應該是BookDaoImpl型別,然而現在是com.sun.proxy.$Proxy19型別
疑惑????檢視對應原始碼:下圖第七行報錯!
@Test public void addTest() { // 在資料庫中,新增 現代光電測試 // 1. Spring讀取配置檔案 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("config.xml"); // 2. 獲取BookDaoImpl物件 (錯誤行) BookDaoImpl bookDaoImpl = context.getBean("bookDaoImpl", BookDaoImpl.class); // 3. 測試方法 bookDaoImpl.add(new Book(18, "現代光電測試", 120, 4)); }
從這段程式碼上,bookDaoImpl確實應該是BookDaoImpl型別,按理說程式碼沒寫錯,為啥getBean()方法返回的不是BookDaoImpl型別。直覺告訴我,應該是增強類程式碼出現問題,上增強類程式碼:
@Service // 建立物件 @Aspect // 這是一個代理物件 public class BookProxy { // 增強類 @Before(value = "execution(* com.atguigu.dao.BookDaoImpl.add(..))") // 注意引數 .. 別忘了 @Order(1) public void addBefore() { System.out.println("Proxy01:新增方法準備就緒!"); } @Before(value = "execution(* com.atguigu.dao.BookDaoImpl.add(..))") @Order(2) public void addBefore01() { System.out.println("Proxy02:執行!"); } }
檢查程式碼之後,發現增強類也沒問題啊............
沒想明白
最後求助百度,發現有人說這個錯誤可能是因為JDK動態代理不支援類注入導致的。
檢查被增強類程式碼,發現確實如此,一切的源頭:下圖第六行程式碼,JdbcTemplate已經是一個類物件,使用JDK動態代理無法進行注入類物件的操作。
原增強類程式碼:
@Service(value = "bookDaoImpl")
public class BookDaoImpl implements BookDao{
// 注入JdbcTemplate
@Autowired
private JdbcTemplate jdbcTemplate; // JDK動態代理並不能進行類的注入!!
.......
}
因為JDK動態代理只支援建立介面實現類代理物件,從而增強類的方法。**
於是,解決方案如下:
新建一個被增強類,命名為BookServiceProxy:其中BookDao是介面,也就是原被增強類BookDaoImpl實現的介面。
解決方案的核心思想:通過一個類封裝介面物件,並在這個類中的各個方法中,呼叫這個介面對應的方法,然後通過增強這個類的各個方法,從而達到 對 實現這個介面的類 的方法 的增強(有點繞,相當於套娃)。
至於為什麼這麼做?是因為JDK動態代理的原理,就是通過建立介面的另一個實現類,被將其作為代理物件,然後在類代理物件中,編寫增強邏輯,從而對原實現類的方法進行增強。
@Service(value = "bookServiceProxy")
public class BookServiceProxy {
// 注入BookDao
@Autowired
private BookDao bookDao; // 被增強類所實現的BookDao介面,因為是介面型別,能夠進行注入!
// add
public void addBook(Book book) { // Book 為 entity
bookDao.add(book);
}
// update
public void updateBook(int classhours, String name) {
bookDao.update(classhours, name);
}
// delete
public void deleteBook(String name) {
bookDao.delete(name);
}
}
重寫編寫增強類程式碼,對新的被增強類BookServiceProxy進行切面操作。
@Service // 建立物件
@Aspect // 這是一個代理物件
public class BookProxy { // 增強類
@Before(value = "execution(* com.atguigu.service.BookServiceProxy.addBook(..))") // 注意引數 .. 別忘了
@Order(1)
public void addBefore() {
System.out.println("Proxy01:新增方法準備就緒!");
}
@Before(value = "execution(* com.atguigu.service.BookServiceProxy.addBook(..))")
@Order(2)
public void addBefore01() {
System.out.println("Proxy02:執行!");
}
}
測試程式碼:
@Test
public void BookServiceProxyTest() {
// 1. Spring讀取配置檔案
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("config.xml");
// 2. 獲取BookDaoImpl物件
BookServiceProxy bookServiceProxy = context.getBean("bookServiceProxy", BookServiceProxy.class);
// 3. 測試方法
bookServiceProxy.addBook(new Book(18, "現代光電測試", 120, 4));
}
執行結果:
Proxy01:新增方法準備就緒!
Proxy02:執行!
10月 15, 2021 9:50:01 下午 com.alibaba.druid.support.logging.JakartaCommonsLoggingImpl info
資訊: {dataSource-1} inited
插入操作執行成功!Process finished with exit code 0