一、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定义、初始化单例Beaninitialize();}/*** 核心方法:根据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);// 只处理单例Beanif ("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);}
}