Spring 框架核心的 IOC(控制反转)和 AOP(面向切面编程)机制让开发者摆脱了繁琐的对象管理和重复的横切逻辑编写。本文将通过手写极简版 Spring 框架,用最浅显的代码拆解 IOC 容器的初始化流程和 AOP 动态代理的生成原理,让你彻底搞懂 Spring 底层核心逻辑。

一、核心需求与整体设计

我们要实现的核心功能:

  1. IOC 容器:扫描指定包下的组件、解析注解、创建 Bean 实例、管理 Bean 的生命周期(依赖注入、Aware 接口回调);

  2. AOP 代理:基于 CGLIB 实现事务切面(模拟 Spring 的 @Transactional 注解)。

先看整体架构,核心类只有这些:

  • 注解类:@Component、@Autowired、@Transactional 等(模拟 Spring 注解);

  • 核心接口:BeanNameAware、ApplicationContextAware(感知 Bean 名称和容器);

  • 容器核心:HzApplicationContext(模拟 Spring 的 ApplicationContext);

  • 辅助类:BeanDefinition(存储 Bean 的元信息)。

二、第一步:定义核心注解(模拟 Spring 注解)

首先复刻 Spring 的核心注解,这些注解是 IOC 和 AOP 的 “开关”:

1. 组件扫描与 Bean 定义注解

// 组件注解:标记需要被IOC容器管理的类
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Component {
    String value() default ""; // 自定义Bean名称
}

// 组件扫描注解:指定IOC容器要扫描的包路径
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ComponentScan {
    String value(); // 扫描包路径
}

// 作用域注解:单例/原型
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Scope {
    String value() default "singleton";
}

// 自动注入注解:依赖注入
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {
    boolean required() default true;
}

// 事务注解:AOP切面标记
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Transactional {
}

2. Aware 接口(感知容器 / Bean 信息)

模拟 Spring 的 Aware 接口,让 Bean 能感知自身的 Bean 名称、所属容器等信息:

// 感知Bean名称
public interface BeanNameAware {
    void setBeanName(String name);
}

// 感知应用上下文
public interface ApplicationContextAware {
    void setApplicationContext(HzApplicationContext applicationContext);
}

3. BeanDefinition(Bean 元信息存储)

Spring 会为每个 Bean 创建一个 “定义对象”,存储 Bean 的类型、作用域、是否懒加载等信息:

public class BeanDefinition {
    private Class type; // Bean的类型
    private String scope; // 作用域:singleton/prototype
    private boolean isLazy; // 是否懒加载

    // 省略get/set方法
}

三、第二步:实现 IOC 容器核心(HzApplicationContext)

IOC 容器是 Spring 的 “心脏”,核心流程分为 3 步:扫描包→解析 Bean 定义→创建 Bean 实例

1. 容器初始化核心逻辑

public class HzApplicationContext {
    private Class configClass; // 配置类(如AppConfig)
    private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>(); // Bean定义缓存
    private Map<String, Object> singletonObjects = new HashMap<>(); // 单例Bean缓存

    // 构造方法:初始化容器
    public HzApplicationContext(Class configClass) {
        this.configClass = configClass;
        // 第一步:扫描指定包下的所有组件
        scan(configClass);
        // 第二步:初始化非懒加载的单例Bean
        for (String beanName : beanDefinitionMap.keySet()) {
            BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
            // 单例+非懒加载:立即创建Bean
            if (beanDefinition.getScope().equals("singleton") && !beanDefinition.isLazy()) {
                Object bean = createBean(beanName, beanDefinition);
                singletonObjects.put(beanName, bean);
            }
        }
    }
}

2. 第一步:扫描包(解析 @ComponentScan 注解)

扫描指定包下的所有.class 文件,解析 @Component 注解,生成 BeanDefinition:

private void scan(Class configClass) {
    // 1. 解析@ComponentScan注解,获取扫描路径
    if (configClass.isAnnotationPresent(ComponentScan.class)) {
        ComponentScan annotation = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
        String scanPath = annotation.value(); // 如:com.vvhz.user
        // 2. 包路径转文件路径(com.vvhz.user → com/vvhz/user)
        scanPath = scanPath.replace(".", "/");
        // 3. 类加载器加载资源
        ClassLoader classLoader = this.getClass().getClassLoader();
        URL resource = classLoader.getResource(scanPath);
        File scanDir = new File(resource.getFile());
        // 4. 遍历目录下的所有.class文件
        List<File> classFiles = new ArrayList<>();
        if (scanDir.isDirectory()) {
            collectClassFiles(scanDir, classFiles); // 递归收集所有.class文件
        }
        // 5. 解析每个.class文件,生成BeanDefinition
        for (File classFile : classFiles) {
            // 文件路径转类名(如:com\vvhz\user\service\UserService → com.vvhz.user.service.UserService)
            String absolutePath = classFile.getAbsolutePath();
            String className = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"))
                    .replace("\\", ".");
            try {
                Class<?> clazz = classLoader.loadClass(className);
                // 只有标记@Component的类才会被管理
                if (clazz.isAnnotationPresent(Component.class)) {
                    // 生成BeanDefinition
                    BeanDefinition beanDefinition = new BeanDefinition();
                    beanDefinition.setType(clazz);
                    beanDefinition.setLazy(clazz.isAnnotationPresent(Lazy.class));
                    // 解析@Scope注解(默认单例)
                    if (clazz.isAnnotationPresent(Scope.class)) {
                        beanDefinition.setScope(clazz.getAnnotation(Scope.class).value());
                    } else {
                        beanDefinition.setScope("singleton");
                    }
                    // 生成Bean名称(自定义名称优先,否则类名首字母小写)
                    String beanName = clazz.getAnnotation(Component.class).value();
                    if (beanName.isEmpty()) {
                        beanName = Introspector.decapitalize(clazz.getSimpleName());
                    }
                    // 存入BeanDefinitionMap
                    beanDefinitionMap.put(beanName, beanDefinition);
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    }
}

// 递归收集所有.class文件
private void collectClassFiles(File dir, List<File> classFiles) {
    for (File file : dir.listFiles()) {
        if (file.isDirectory()) {
            collectClassFiles(file, classFiles);
        } else {
            if (file.getName().endsWith(".class")) {
                classFiles.add(file);
            }
        }
    }
}

3. 第二步:创建 Bean 实例(核心!依赖注入 + Aware 回调 + AOP 代理)

createBean方法是 IOC 容器的核心,完成:实例化→依赖注入→Aware 接口回调→AOP 代理生成

private Object createBean(String beanName, BeanDefinition beanDefinition) {
    Class clazz = beanDefinition.getType();
    try {
        // 1. 实例化Bean(无参构造)
        Object beanInstance = clazz.newInstance();

        // 2. 依赖注入(解析@Autowired注解)
        for (Field field : clazz.getDeclaredFields()) {
            if (field.isAnnotationPresent(Autowired.class)) {
                // 递归获取依赖的Bean(如UserService依赖OrderService)
                Object dependentBean = getBean(field.getName());
                field.setAccessible(true); // 突破private访问限制
                field.set(beanInstance, dependentBean); // 注入
            }
        }

        // 3. Aware接口回调(让Bean感知容器/自身名称)
        if (beanInstance instanceof BeanNameAware) {
            ((BeanNameAware) beanInstance).setBeanName(beanName);
        }
        if (beanInstance instanceof ApplicationContextAware) {
            ((ApplicationContextAware) beanInstance).setApplicationContext(this);
        }

        // 4. AOP代理(基于CGLIB生成事务代理)
        if (clazz.isAnnotationPresent(Transactional.class)) {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(clazz); // 设置父类(CGLIB基于继承)
            Object target = beanInstance; // 原始Bean实例
            // 方法拦截器(模拟事务逻辑)
            enhancer.setCallback(new MethodInterceptor() {
                @Override
                public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                    // 前置增强:开启事务
                    System.out.println("开启数据库事务");
                    // 执行原始方法
                    Object result = method.invoke(target, args);
                    // 后置增强:提交事务
                    System.out.println("提交数据库事务");
                    return result;
                }
            });
            // 生成代理对象(替换原始Bean)
            beanInstance = enhancer.create();
        }

        return beanInstance;
    } catch (InstantiationException | IllegalAccessException e) {
        e.printStackTrace();
    }
    return null;
}

4. 第三步:获取 Bean(getBean 方法)

对外提供获取 Bean 的接口,区分单例 / 原型 Bean:

public Object getBean(String beanName) {
    BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
    if (beanDefinition == null) {
        throw new NullPointerException("Bean不存在:" + beanName);
    }
    // 单例Bean:从缓存获取,缓存没有则创建
    if ("singleton".equals(beanDefinition.getScope())) {
        Object singletonBean = singletonObjects.get(beanName);
        if (singletonBean == null) {
            singletonBean = createBean(beanName, beanDefinition);
            singletonObjects.put(beanName, singletonBean);
        }
        return singletonBean;
    } else {
        // 原型Bean:每次获取都创建新实例
        return createBean(beanName, beanDefinition);
    }
}

四、第三步:测试 IOC 容器与 AOP 代理

1. 编写业务类(模拟实际开发)

// 订单服务(被依赖)
@Component
public class OrderService {
}

// 用户服务(依赖OrderService,开启事务)
@Component
@Transactional
public class UserService implements BeanNameAware, ApplicationContextAware {
    @Autowired
    private OrderService orderService;

    private HzApplicationContext applicationContext;
    private String beanName;

    public void test() {
        System.out.println("OrderService实例:" + orderService);
        System.out.println("容器实例:" + applicationContext);
        System.out.println("Bean名称:" + beanName);
    }

    // 实现Aware接口的回调方法
    @Override
    public void setApplicationContext(HzApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }
    @Override
    public void setBeanName(String name) {
        this.beanName = name;
    }
}

2. 编写配置类

@ComponentScan("com.vvhz.user") // 指定扫描包
public class AppConfig {
}

3. 启动容器测试

public class MyApplication {
    public static void main(String[] args) {
        // 初始化容器
        HzApplicationContext context = new HzApplicationContext(AppConfig.class);
        // 获取Bean
        UserService userService = (UserService) context.getBean("userService");
        // 调用方法(触发事务代理)
        userService.test();
    }
}

4. 运行结果

开启数据库事务
OrderService实例:com.vvhz.user.service.OrderService@6d03e736
容器实例:com.vvhz.springframework.HzApplicationContext@568db2f2
Bean名称:userService
提交数据库事务

从结果能看到:

  • IOC 容器完成了 OrderService 的自动注入;

  • BeanNameAware 和 ApplicationContextAware 回调成功;

  • @Transactional 触发了 AOP 代理,方法执行前后自动开启 / 提交事务。

四、核心原理总结

1. IOC 容器核心流程

  1. 扫描:解析 @ComponentScan 注解,递归扫描指定包下的 @Component 类,生成 BeanDefinition;

  2. 初始化:非懒加载的单例 Bean 在容器启动时创建,原型 Bean 在 getBean 时创建;

  3. 依赖注入:通过反射解析 @Autowired 注解,递归获取依赖 Bean 并注入;

  4. 生命周期回调:执行 Aware 接口的回调方法,让 Bean 感知容器 / 自身信息;

  5. 缓存管理:单例 Bean 存入 singletonObjects,原型 Bean 每次创建新实例。

2. AOP 代理核心原理(CGLIB)

  1. 识别 @Transactional 注解的类;

  2. 通过 CGLIB 的 Enhancer 创建代理类(继承原始类);

  3. 重写原始方法,在方法执行前后插入横切逻辑(事务);

  4. 代理对象替换原始 Bean 实例,对外提供服务。

五、与真实 Spring 的对比

本文的极简版 Spring 省略了很多细节(如循环依赖解决、BeanPostProcessor、注解属性解析、多切面排序等),但核心逻辑和真实 Spring 一致:

  • Spring 的 ApplicationContext 底层也是通过扫描→解析→创建 Bean 的流程;

  • Spring 的 AOP 默认使用 JDK 动态代理(接口)+ CGLIB(类),本文简化为仅 CGLIB;

  • Spring 的依赖注入支持构造器、setter、字段注入,本文仅实现字段注入。

六、总结

通过手写极简版 Spring,我们能清晰看到:

  • IOC 的本质:将对象的创建、依赖管理交给容器,开发者只需关注业务逻辑;

  • AOP 的本质:通过动态代理在不修改原始代码的情况下,为方法添加横切逻辑。

Spring 的源码虽然复杂,但核心原理并不难 —— 无非是 “注解解析 + 反射 + 设计模式(工厂、代理)” 的组合。掌握了这些核心逻辑,后续我们再去看 Spring 源码就会豁然开朗。

完整代码已放在示例中,也可以直接拉取gitee仓库的代码,可以直接运行,也可以尝试扩展(如添加 BeanPostProcessor、循环依赖解决、多切面支持等),进一步加深对 Spring 的理解。

文章作者: Z
本文链接:
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 微博客
Java spring framework spring java
喜欢就支持一下吧