手写Spring容器核心原理

一、Spring容器基础架构

/**
 * Zhouyu-Spring核心容器类
 * 职责:加载配置、管理Bean定义、创建和管理Bean实例
 */
public class ZhouyuApplicationContext {

    // 存储配置类的Class对象,用于获取扫描路径等配置信息
    private Class configClass;
    
    // Bean定义映射表:key=Bean名称, value=Bean元数据(类型、作用域等)
    private ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
    
    // 单例对象池:缓存单例Bean实例(key=Bean名称)
    private ConcurrentHashMap<String, Object> singletonObject = new ConcurrentHashMap<>();

    /**
     * 容器构造器
     * @param configClass Spring配置类的Class对象
     */
    public ZhouyuApplicationContext(Class configClass) {
        this.configClass = configClass;
        // 初始化容器:扫描包路径、注册Bean定义、初始化单例Bean
        initialize();
    }

    /**
     * 核心方法:根据Bean名称获取Bean实例
     * @param beanName 要获取的Bean名称
     * @return Bean实例对象
     */
    public Object getBean(String beanName) {
        // 具体实现将在第五部分完成
        return null;
    }
}

创建容器时传入配置类



public class Test {
    public static void main(String[] args) {
        // 创建Spring容器实例,传入配置类
        ZhouyuApplicationContext context = new ZhouyuApplicationContext(AppConfig.class);
        
        // 从容器中获取名为"userService"的Bean实例
        UserService userService = (UserService) context.getBean("userService");
    }
}

二、核心注解实现

1. 组件扫描注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 组件扫描注解:标识要扫描的包路径
 * 只能标注在类上,运行时保留
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ComponentScan {
    /**
     * 指定要扫描的包路径
     * @return 包路径字符串(如"com.zhouyu.service")
     */
    String value() default "";
}

2. 组件标识注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 组件标识注解:标记需要被容器管理的类
 * 只能标注在类上,运行时保留
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Component {
    /**
     * 指定Bean在容器中的名称
     * @return Bean名称(如"userService")
     */
    String value() default "";
}

3. 单例多利注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Scope {
    /**
     * 指定Bean是单例还是多礼
     * @return (如"singleton"或"prototype")
     */
    String value() default "";
}

三、配置类与Bean定义

配置类示例
/**
 * Spring配置类示例
 * 使用@ComponentScan指定扫描包路径
 */
@ComponentScan("com.zhouyu.service") // 扫描com.zhouyu.service包及其子包
public class AppConfig {
    // 配置类可以包含其他配置信息
}

Bean定义类
/**
 * Bean定义类:封装Bean的元数据信息
 */
public class BeanDefinition {
    // Bean的Class类型(如UserService.class)
    private Class type;
    
    // Bean的作用域(singleton/prototype)
    private String scope;

    // Setter和Getter方法
    public Class getType() {
        return type;
    }

    public void setType(Class type) {
        this.type = type;
    }

    public String getScope() {
        return scope;
    }

    public void setScope(String scope) {
        this.scope = scope;
    }
}

四、容器初始化流程

1. 扫描路径处理


/**
 * 容器初始化方法
 * 1. 解析配置类的@ComponentScan注解
 * 2. 扫描指定包路径下的所有类文件
 * 3. 创建所有单例Bean
 */
private void initialize() {
    // 检查配置类是否有ComponentScan注解
    if (configClass.isAnnotationPresent(ComponentScan.class)) {
        // 获取注解实例
        ComponentScan scan = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
        
        // 将包路径转换为文件系统路径(com.zhouyu.service -> com/zhouyu/service)
        String path = scan.value().replace(".", "/");
        
        // 获取类加载器
        ClassLoader classLoader = getClass().getClassLoader();
        
        // 获取资源在类路径中的位置
        URL resource = classLoader.getResource(path);
        
        // 将URL转为文件对象
        File dir = new File(resource.getFile());
        
        // 确保是目录
        if (dir.isDirectory()) {
            // 遍历目录下所有文件
            for (File file : dir.listFiles()) {
                // 处理每个文件(类文件)
                processClassFile(file, classLoader);
            }
        }
    }
    
    // 初始化所有单例Bean(容器启动时创建)
    createSingletonBeans();
}

2. 类文件处理逻辑


/**
 * 处理单个类文件
 * @param file 类文件对象
 * @param classLoader 类加载器
 */
private void processClassFile(File file, ClassLoader classLoader) {
    String fileName = file.getAbsolutePath();
    
    // 只处理.class文件
    if (fileName.endsWith(".class")) {
        // 从绝对路径中提取完整类名(com\zhouyu\service\UserService -> com.zhouyu.service.UserService)
        String className = fileName.substring(
            fileName.indexOf("com"),       // 从"com"开始
            fileName.indexOf(".class")      // 到".class"结束
        ).replace("\\", ".");              // 替换路径分隔符
        
        try {
            // 加载类对象
            Class<?> clazz = classLoader.loadClass(className);
            
            // 检查是否有@Component注解
            if (clazz.isAnnotationPresent(Component.class)) {
                // 注册Bean定义到容器
                registerBeanDefinition(clazz);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

3. Bean定义注册


/**
 * 注册Bean定义到容器
 * @param clazz 要注册的Class对象
 */
private void registerBeanDefinition(Class<?> clazz) {
    // 获取@Component注解配置
    Component component = clazz.getAnnotation(Component.class);
    String beanName = component.value();
    
    // 创建Bean定义对象
    BeanDefinition definition = new BeanDefinition();
    definition.setType(clazz); // 设置Bean类型
    
    // 检查是否有@Scope注解
    if (clazz.isAnnotationPresent(Scope.class)) {
        // 获取作用域配置
        Scope scope = clazz.getAnnotation(Scope.class);
        definition.setScope(scope.value());
    } else {
        // 默认单例模式
        definition.setScope("singleton");
    }
    
    // 将Bean定义存入映射表
    beanDefinitionMap.put(beanName, definition);
}

五、Bean创建与管理

1. 单例Bean预创建


/**
 * 初始化所有单例Bean(在容器启动时创建)
 */
private void createSingletonBeans() {
    // 遍历所有Bean定义
    for (String beanName : beanDefinitionMap.keySet()) {
        BeanDefinition definition = beanDefinitionMap.get(beanName);
        
        // 只处理单例Bean
        if ("singleton".equals(definition.getScope())) {
            // 创建Bean实例
            Object bean = createBean(beanName, definition);
            // 存入单例对象池
            singletonObject.put(beanName, bean);
        }
    }
}

2. Bean实例化方法


/**
 * 创建Bean实例
 * @param beanName Bean名称
 * @param definition Bean定义
 * @return 创建的Bean实例
 */
private Object createBean(String beanName, BeanDefinition definition) {
    Class clazz = definition.getType();
    try {
        // 通过默认构造器创建实例(反射机制)
        return clazz.getConstructor().newInstance();
    } catch (Exception e) {
        // 封装创建异常
        throw new RuntimeException("创建Bean失败: " + beanName, e);
    }
}

3. getBean实现


/**
 * 获取Bean实例的核心方法
 * @param beanName 要获取的Bean名称
 * @return Bean实例
 * @throws NullPointerException 如果找不到Bean定义
 */
public Object getBean(String beanName) {
    // 从Bean定义映射表获取元数据
    BeanDefinition definition = beanDefinitionMap.get(beanName);
    
    // 检查Bean定义是否存在
    if (definition == null) {
        throw new NullPointerException("未定义的Bean: " + beanName);
    }
    
    // 获取Bean的作用域配置
    String scope = definition.getScope();
    
    // 根据作用域类型返回Bean实例
    if ("singleton".equals(scope)) {
        // 单例模式:从单例池获取
        Object bean = singletonObject.get(beanName);
        // 双重检查:如果还未创建则创建并缓存
        if (bean == null) {
            bean = createBean(beanName, definition);
            singletonObject.put(beanName, bean);
        }
        return bean;
    } else {
        // 原型模式:每次创建新实例
        return createBean(beanName, definition);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值