IOC 容器啟動階段:掃描註解/解析 XML → 反射實例化 Bean → 注入依賴 → 放入單例池。
AOP 運行時:基於動態代理(JDK/CGLIB)為目標 Bean 生成代理對象,攔截方法調用織入切面邏輯。
ClassPathBeanDefinitionScanner 掃描 @Component 等,或 XmlBeanDefinitionReader 解析 <bean>。SimpleInstantiationStrategy 使用 Constructor.newInstance()(反射)創建對象。AutowiredAnnotationBeanPostProcessor 反射設置 @Autowired 字段/方法。InitializingBean.afterPropertiesSet()、@PostConstruct。DefaultSingletonBeanRegistry.singletonObjects Map。
// 獲取構造器
Constructor> ctor = clazz.getDeclaredConstructor(paramTypes);
ctor.setAccessible(true); // 破壞私有封裝
Object bean = ctor.newInstance(args); // 實例化
// 設置字段
Field field = clazz.getDeclaredField("dependency");
field.setAccessible(true);
field.set(bean, dependencyInstance);
| 維度 | JDK 動態代理 | CGLIB |
|---|---|---|
| 前提條件 | 目標類實現至少一個接口 | 無需接口,繼承目標類 |
| 核心類 | java.lang.reflect.Proxy | net.sf.cglib.proxy.Enhancer |
| 代理類型 | 接口類型(實現目標接口) | 子類類型(繼承目標類) |
| final 方法 | 可代理 | 無法代理(無法重寫) |
| 性能 | 調用稍慢(反射調用) | FastClass 機制,調用較快 |
| Spring 默認策略 | 有接口用 JDK,無接口用 CGLIB | proxy-target-class=true 強制 CGLIB |
// 1. 目標對象
UserService target = new UserServiceImpl();
// 2. 攔截器(切面邏輯)
InvocationHandler handler = (proxy, method, args) -> {
// 前置通知
System.out.println("Before: " + method.getName());
Object result = method.invoke(target, args); // 執行目標方法
// 後置通知
System.out.println("After: " + method.getName());
return result;
};
// 3. 生成代理
UserService proxy = (UserService) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
handler
);
// 4. 客戶端調用代理而非目標
proxy.saveUser(); // 觸發攔截器
AnnotationAwareAspectJAutoProxyCreator(BeanPostProcessor)在 Bean 初始化後創建代理。DefaultAopProxyFactory 根據 proxyTargetClass 決定 JDK/CGLIB。AdvisedSupport 封裝切點、攔截器鏈,MethodInterceptor 統一調用入口。singletonObjects、earlySingletonObjects、singletonFactories)+ 提前暴露 ObjectFactory。this.method() 繞過代理)、final 方法、非公共方法(JDK)、Bean 未被容器管理。「IOC 用反射造對象,AOP 用代理攔截調用」 —— 這兩句話串起了 Spring 核心容器的骨架與靈魂。