// ❌ 報錯:BeanNotOfRequiredTypeException
@Resource
private EmployeeService employeeService; // 具體實現類
// ✅ 正常:注入接口
@Resource
private EmployeeServiceInter employeeService; // 接口
報錯信息:Bean named 'employeeService' must be of type [com.xidian.service.imp.EmployeeService], but was actually of type [com.sun.proxy.$Proxy67]
| 維度 | JDK 動態代理 | CGLIB 代理 |
|---|---|---|
| 前提條件 | 目標類實現至少一個接口 | 無需接口,繼承目標類 |
| 生成對象 | 實現目標接口的匿名類($ProxyX) | 目標類的子類($$EnhancerByCGLIB$$) |
| 類型關系 | proxy instanceof Interface == trueproxy instanceof ImplClass == false | proxy instanceof ImplClass == true |
| 最終類 | 可代理 | 不可代理 |
| 私有方法 | 不可攔截 | 不可攔截 |
| 性能 | 調用稍慢(反射),創建快 | 調用快,創建慢(字節碼操作) |
@EnableAspectJAutoProxy(proxyTargetClass = true) 或 spring.aop.proxy-target-class=true// 運行時類型
EmployeeService service = context.getBean("employeeService", EmployeeService.class);
// 實際類型:com.sun.proxy.$Proxy67
// $Proxy67 implements EmployeeServiceInter
// $Proxy67 NOT instanceof EmployeeService (實現類)
// 注入字段類型為 EmployeeService (具體類)
// Spring 嘗試將 $Proxy67 賦值給 EmployeeService 類型字段 → 類型不匹配 → 拋出異常
public interface EmployeeService { void save(Employee e); }
@Service
public class EmployeeServiceImpl implements EmployeeService { ... }
// Controller
@Autowired
private EmployeeService employeeService; // 接口類型 ✅
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true) // 全局強制 CGLIB
public class AppConfig { }
@Service
public class EmployeeServiceImpl { ... } // 無 @Transactional/@Async 等 AOP 注解
// 注入實現類無問題,因為不會創建代理
# application.yml
spring:
aop:
proxy-target-class: false # 默認 false,優先 JDK 動態代理
# 設為 true 則全局 CGLIB,等同於 @EnableAspectJAutoProxy(proxyTargetClass=true)
面向接口編程不僅是解決代理類型匹配問題,更是架構解耦、可測試性、擴展性的基石。Spring 通過默認 JDK 動態代理「強制」引導開發者遵循最佳實踐,這是框架設計的精妙之處。