# MySpringAnno **Repository Path**: sradon/MySpringAnno ## Basic Information - **Project Name**: MySpringAnno - **Description**: 手搓实现Spring的IOC和DI的注解版本 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-09-11 - **Last Updated**: 2025-11-02 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 🌱 手写Spring框架:IOC容器和DI注解的完整实现 > 一个从零开始实现的轻量级Spring框架,深入理解Spring IOC和DI的核心原理 ## 📋 项目概述 本项目是一个从零开始实现的轻量级Spring框架,主要实现了Spring的两大核心功能: - 🔧 **IOC(控制反转)**:通过注解自动扫描并管理Bean的生命周期 - 💉 **DI(依赖注入)**:通过注解自动注入Bean之间的依赖关系 ## 🏗️ 项目架构设计 ### 整体架构图 ``` MySpringAnno/ ├── src/ │ ├── applicationContext.xml # 配置文件 │ └── org/sradon/ │ ├── mySpring/ # 框架核心 │ │ ├── anno/ # 注解定义 │ │ │ ├── ioc/ # IOC相关注解 │ │ │ └── di/ # DI相关注解 │ │ ├── context/ # 容器核心 │ │ ├── model/ # 执行器 │ │ └── utils/ # 工具类 │ ├── dao/ # 数据访问层 │ ├── service/ # 服务层 │ ├── pojo/ # 实体类 │ └── test/ # 测试类 └── lib/ # 依赖库 ``` ### 📦 包职责划分 | 包路径 | 职责描述 | |--------|----------| | `org.sradon.mySpring.anno.ioc` | IOC注解定义:@Component、@Service、@Repository等 | | `org.sradon.mySpring.anno.di` | DI注解定义:@Autowired、@Value、@Qualifier、@Primary | | `org.sradon.mySpring.context` | 容器核心:ApplicationContext、BeanFactory等 | | `org.sradon.mySpring.model` | 执行器:IocExecutor、DiExecutor | | `org.sradon.mySpring.utils` | 工具类:AnnoUtils、ReflectUtils | ## 🔧 IOC注解实现原理 ### 1. 注解定义 #### 🏷️ @Component(基础组件注解) ```java @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface Component { String value() default ""; } ``` #### 🚀 @Service(服务层注解) ```java @Component // 元注解:继承Component语义 @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface Service { String value() default ""; } ``` #### 🗄️ @Repository(数据访问层注解) ```java @Component // 元注解:继承Component语义 @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface Repository { String value() default ""; } ``` ### 2. IOC实现核心:IocExecutor ```java public class IocExecutor { // IOC注解数组,用于匹配 public static final Class[] IOC_ANNOS = new Class[]{Component.class, Service.class, Repository.class}; /** * 递归扫描包路径,加载所有被IOC注解标记的类 */ public static String BeanLoader(File dir, String packageName, ClassLoader loader, Map beans, List defines) { // 1. 遍历目录中的所有文件 for (File file : Objects.requireNonNull(dir.listFiles())) { if (file.isDirectory()) { // 递归处理子目录 BeanLoader(file, packageName + "." + file.getName(), loader, beans, defines); } else if (file.getName().endsWith(".class")) { String className = packageName + "." + file.getName().replace(".class", ""); try { // 2. 加载字节码文件 Class clazz = loader.loadClass(className); // 3. 检查是否被IOC注解修饰 Class iocAnno = AnnoUtils.isComponent(clazz); if (iocAnno != null) { // 4. 创建Bean实例 Object bean = clazz.newInstance(); // 5. 执行初始化方法(@PostConstruct) AnnoUtils.useInit(clazz, bean); // 6. 确定Bean在容器中的Key String beanKey = getBeanKey(clazz, iocAnno); // 7. 存入容器和定义列表 beans.put(beanKey, bean); defines.add(new BeanDefine(beanKey, clazz, clazz.getInterfaces(), clazz.getSuperclass())); } } catch (Exception e) { throw new RuntimeException("处理对象" + className + "时失败", e); } } } return null; } } ``` ### 3. 🏷️ Bean命名策略 Bean在容器中的命名遵循以下优先级: 1. **注解value值**:如`@Service("userService")`,则key为"userService" 2. **全限定类名**:如`org.sradon.service.impl.UserServiceImpl` ## 💉 DI注解实现原理 ### 1. DI注解定义 #### 🔗 @Autowired(按类型自动装配) ```java @Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) public @interface Autowired { } ``` #### 📝 @Value(值注入) ```java @Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) public @interface Value { String value(); } ``` #### 🎯 @Qualifier(指定注入Bean名称) ```java @Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) public @interface Qualifier { String value(); } ``` #### ⭐ @Primary(标记首选Bean) ```java @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface Primary { } ``` ### 2. DI实现核心:DiExecutor ```java public class DiExecutor { public static void ValueLoader(Object bean, Map context, List defines) { Field[] fields = bean.getClass().getDeclaredFields(); for (Field field : fields) { // 处理@Value注解 if (field.isAnnotationPresent(Value.class)) { AnnoUtils.setValue(bean, field); } // 处理@Autowired注解 if (field.isAnnotationPresent(Autowired.class)) { AnnoUtils.putAutowired(bean, field, context, defines); } // 处理@Resource注解 if (field.isAnnotationPresent(Resource.class)) { AnnoUtils.putResource(bean, field, context, defines); } } } } ``` ### 3. 🔄 自动装配策略 #### @Autowired装配流程 1. **检查@Qualifier**:如果存在,直接按名称注入 2. **按类型匹配**:在容器中查找相同类型的Bean 3. **接口匹配**:如果是接口类型,查找实现类 4. **@Primary优先**:多个候选Bean时,优先选择@Primary标记的 5. **唯一性检查**:确保只有一个匹配的Bean #### 核心装配代码 ```java public static void putAutowired(Object obj, Field f, Map beans, List defines) { try { // 1. 优先处理@Qualifier指定名称注入 if (f.isAnnotationPresent(Qualifier.class)) { String qualifierValue = f.getAnnotation(Qualifier.class).value(); Object targetBean = beans.get(qualifierValue); ReflectUtils.FieldSetter(f, obj, targetBean); return; } // 2. 按类型在容器中查找 Object bean = beans.get(f.getType().getName()); if (bean != null) { ReflectUtils.FieldSetter(f, obj, bean); } else { // 3. 按接口匹配实现类 String beanKey = findInterface(defines, f, beans); bean = beans.get(beanKey); if (bean == null) { throw new RuntimeException("未找到匹配的Bean: " + f.getName()); } ReflectUtils.FieldSetter(f, obj, bean); } } catch (Exception e) { throw new RuntimeException("自动装配失败: " + f.getName(), e); } } ``` ## 🏛️ 容器核心组件 ### 1. BeanFactory接口 ```java public interface BeanFactory { Object getBean(String name); // 获取Bean void listBeans(); // 列出所有Bean void listDefines(); // 列出所有Bean定义 } ``` ### 2. ApplicationContext接口 ```java public interface ApplicationContext extends BeanFactory { // 继承BeanFactory,未来可扩展更多功能 } ``` ### 3. ClassPathXmlApplicationContext实现类 这是容器的核心实现,负责: - 解析XML配置文件 - 扫描指定包路径 - 执行IOC和DI #### 核心数据结构 ```java public class ClassPathXmlApplicationContext implements ApplicationContext { // Spring容器:存储Bean实例 private final Map beans = new ConcurrentHashMap<>(); // Bean定义列表:存储Bean的元信息 private final List defines = Collections.synchronizedList(new ArrayList<>()); public ClassPathXmlApplicationContext(String resourceName) { try { // 1. 解析XML配置文件 Document doc = parseXmlConfig(resourceName); // 2. 执行IOC:扫描包,创建Bean IOCbyAnno(doc); // 3. 执行DI:注入依赖关系 DIbyAnno(); System.out.println("[SUCCESS] Spring容器初始化成功"); } catch (Exception e) { throw new RuntimeException("[ERR] 创建Spring容器失败", e); } } } ``` ### 4. BeanDefine Bean定义类 ```java public class BeanDefine { private String contextKey; // 在容器中的Key private Class clazz; // 类的字节码对象 private Class[] interfaces; // 实现的接口 private Class superClass; // 父类 // 用于解决接口注入问题: // 当需要注入的是接口类型,容器中存储的是实现类时, // 通过BeanDefine匹配接口与实现类的关系 } ``` ## 🛠️ 工具类详解 ### 1. AnnoUtils(注解工具类) #### 注解检测 ```java /** * 判断类是否被IOC注解修饰 */ public static Class isComponent(Class clazz) { Annotation[] annos = clazz.getDeclaredAnnotations(); for (Annotation a : annos) { for (Class ioc_a : IocExecutor.IOC_ANNOS) { if (a.annotationType().equals(ioc_a)) { return ioc_a; } } } return null; } ``` #### 接口匹配算法 ```java /** * 从定义列表中匹配接口实现类 */ public static String findInterface(List defines, Field f, Map beans) { List beanKeys = new ArrayList<>(); // 遍历所有Bean定义 for (BeanDefine define : defines) { // 检查是否实现了目标接口 for (Class interfaceClass : define.getInterfaces()) { if (interfaceClass.getName().equals(f.getType().getName())) { // 检查是否被@Primary标记 if (define.getClazz().isAnnotationPresent(Primary.class)) { return define.getContextKey(); // 立即返回Primary Bean } beanKeys.add(define.getContextKey()); } } } // 结果验证 if (beanKeys.isEmpty()) return null; if (beanKeys.size() > 1) { throw new RuntimeException("存在多个匹配接口的Bean,请使用@Primary或@Qualifier"); } return beanKeys.get(0); } ``` ### 2. ReflectUtils(反射工具类) ```java public class ReflectUtils { /** * 暴力反射给字段赋值 */ public static void FieldSetter(Field f, Object obj, Object value) { try { f.setAccessible(true); // 突破访问权限 f.set(obj, value); // 设置字段值 } catch (Exception e) { throw new RuntimeException("字段赋值失败: " + f.getName(), e); } } } ``` ## ⚙️ 配置文件与扫描 ### applicationContext.xml ```xml ``` ## 🚀 使用示例 ### 1. 定义服务类 ```java @Service public class GoodsServiceImpl implements GoodsService { @Autowired private GoodsDao goodsDao; @Autowired @Qualifier("DDI3") // 指定注入名为"DDI3"的Bean private DoubleDao doubleDao; @Override public void getGoodsById() { goodsDao.getGoodsById(1); doubleDao.run(); } } ``` ### 2. 定义DAO类 ```java @Repository("DDI3") // 指定Bean名称 public class DoubleDaoImpl3 implements DoubleDao { @Override public void run() { System.out.println("DoubleDaoImpl3 执行中..."); } } ``` ### 3. 测试代码 ```java @Test public void testAll() { // 1. 创建Spring容器 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); // 2. 从容器获取Bean GoodsService goodsService = (GoodsService) context.getBean("org.sradon.service.impl.GoodsServiceImpl"); // 3. 使用Bean goodsService.getGoodsById(); // 4. 查看容器状态 context.listBeans(); context.listDefines(); } ``` ## 📊 核心流程时序图 ```mermaid sequenceDiagram participant Client participant Context as ClassPathXmlApplicationContext participant IocExecutor participant DiExecutor participant AnnoUtils Client->>Context: new ClassPathXmlApplicationContext() Context->>Context: 解析XML配置文件 Context->>IocExecutor: IOCbyAnno() IocExecutor->>IocExecutor: 扫描包路径 IocExecutor->>AnnoUtils: 检查IOC注解 IocExecutor->>Context: 创建Bean并存入容器 Context->>DiExecutor: DIbyAnno() DiExecutor->>AnnoUtils: 处理DI注解 DiExecutor->>AnnoUtils: 注入依赖关系 Context->>Client: 容器初始化完成 ``` ## ✨ 技术特点与优势 ### 1. 🎯 设计模式应用 - **工厂模式**:BeanFactory负责Bean的创建和管理 - **单例模式**:容器中的Bean默认为单例 - **策略模式**:不同注解采用不同的处理策略 - **模板方法模式**:IOC和DI的执行流程 ### 2. 🔬 核心技术点 - **反射机制**:动态创建对象和属性注入 - **注解处理**:运行时注解解析和处理 - **XML解析**:使用dom4j解析配置文件 - **包扫描**:递归扫描指定包路径 - **接口匹配**:解决接口类型的依赖注入 ### 3. 🔧 扩展性设计 - **注解继承**:@Service和@Repository通过@Component实现语义继承 - **多重匹配策略**:支持@Primary和@Qualifier解决Bean冲突 - **生命周期支持**:支持@PostConstruct初始化方法 ## 📈 与Spring官方框架对比 | 特性 | 本实现 | Spring官方 | |------|--------|------------| | IOC容器 | ✅ 基础实现 | ✅ 完整实现 | | DI注入 | ✅ @Autowired、@Value等 | ✅ 更多注解支持 | | 作用域 | ❌ 仅支持单例 | ✅ 多种作用域 | | AOP | ❌ 未实现 | ✅ 完整AOP支持 | | 条件装配 | ❌ 未实现 | ✅ @Conditional等 | | 配置类 | ❌ 仅支持XML | ✅ JavaConfig + XML | ## 🎯 总结 本项目通过纯手工实现的方式,深入展示了Spring框架IOC和DI的核心原理: ### 🔍 核心原理 1. **IOC原理**:通过反射机制扫描注解,自动创建和管理Bean的生命周期 2. **DI原理**:通过注解解析和类型匹配,自动注入Bean之间的依赖关系 3. **容器设计**:采用Map存储Bean实例,List存储Bean定义,实现高效的Bean管理 4. **扩展机制**:通过BeanDefine和AnnoUtils等工具类,实现了灵活的扩展能力 ### 🎓 学习价值 这个实现虽然相比Spring官方框架较为简化,但包含了Spring最核心的设计思想和实现原理,是学习Spring框架源码的绝佳入门项目。通过这个项目,你可以深入理解: - ✅ Spring IOC容器的工作原理 - ✅ 注解驱动开发的实现机制 - ✅ 依赖注入的多种策略 - ✅ 反射和注解在框架中的应用 ### 🚀 项目亮点 - **📚 注解驱动开发**:完全基于注解的IOC和DI实现 - **🔗 接口匹配算法**:解决接口类型依赖注入的核心技术 - **⚡ 多重装配策略**:支持@Primary和@Qualifier解决Bean冲突 - **🔬 反射机制应用**:深度使用反射实现动态对象创建和属性注入 - **🏗️ 扩展性设计**:良好的架构设计支持功能扩展 --- > **作者**:[Sradon] > **项目地址**:MySpringAnno > **创建时间**:2025年9月13日 > **版本**:v1.0 --- **🌟 如果这个项目对你有帮助,请给个Star支持一下!**