首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

Spring IOC 與 AOP 底層原理:反射實例化 Bean、動態代理織入切面

     編輯:程式設計疑難解答

核心結論

IOC 容器啟動階段:掃描註解/解析 XML → 反射實例化 Bean → 注入依賴 → 放入單例池。
AOP 運行時:基於動態代理(JDK/CGLIB)為目標 Bean 生成代理對象,攔截方法調用織入切面邏輯。

IOC:反射驅動的 Bean 生命周期

關鍵步驟

  1. BeanDefinition 解析:ClassPathBeanDefinitionScanner 掃描 @Component 等,或 XmlBeanDefinitionReader 解析 <bean>。
  2. 實例化:SimpleInstantiationStrategy 使用 Constructor.newInstance()(反射)創建對象。
  3. 屬性填充:AutowiredAnnotationBeanPostProcessor 反射設置 @Autowired 字段/方法。
  4. 初始化回調:InitializingBean.afterPropertiesSet()、@PostConstruct。
  5. 註冊單例:放入 DefaultSingletonBeanRegistry.singletonObjects Map。

反射核心 API


// 獲取構造器
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);

AOP:動態代理兩大實現

維度JDK 動態代理CGLIB
前提條件目標類實現至少一個接口無需接口,繼承目標類
核心類java.lang.reflect.Proxynet.sf.cglib.proxy.Enhancer
代理類型接口類型(實現目標接口)子類類型(繼承目標類)
final 方法可代理無法代理(無法重寫)
性能調用稍慢(反射調用)FastClass 機制,調用較快
Spring 默認策略有接口用 JDK,無接口用 CGLIBproxy-target-class=true 強制 CGLIB

代理創建流程(以 JDK 為例)


// 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(); // 觸發攔截器

Spring AOP 關鍵切點

  1. AnnotationAwareAspectJAutoProxyCreator(BeanPostProcessor)在 Bean 初始化後創建代理。
  2. DefaultAopProxyFactory 根據 proxyTargetClass 決定 JDK/CGLIB。
  3. AdvisedSupport 封裝切點、攔截器鏈,MethodInterceptor 統一調用入口。

常見面試追問與回答要點

  • 為什麼 Spring Bean 默認單例? 減少創建開銷、狀態共享、便於事務管理。
  • 循環依賴怎麼解決? 三級緩存(singletonObjects、earlySingletonObjects、singletonFactories)+ 提前暴露 ObjectFactory。
  • AOP 失效場景? 內部方法調用(this.method() 繞過代理)、final 方法、非公共方法(JDK)、Bean 未被容器管理。

「IOC 用反射造對象,AOP 用代理攔截調用」 —— 這兩句話串起了 Spring 核心容器的骨架與靈魂。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved