尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

手写极简Spring容器,深入理解IoC与AOP

手写极简Spring容器,深入理解IoC与AOP 正文一、前言很多开发只会使用 Spring 框架但完全搞不懂 IoC 控制反转、AOP 切面底层到底怎么运行。网上讲解源码门槛太高今天我们从零手写极简版迷你 Spring 容器只用 JDK 原生技术自定义注解、反射、动态代理实现核心功能组件扫描、单例 Bean 管理、自动依赖注入、方法日志切面增强。项目完全脱离 Spring 依赖纯原生 Java 实现看完就能彻底理解Spring 如何通过注解自动创建对象IoC 容器Autowired 自动注入的底层反射原理Component 扫描包的实现逻辑JDK 动态代理实现 AOP 前置 / 后置通知单例 Bean 缓存设计、容器启动完整流程适合 Java 进阶、面试突击 Spring 底层原理、课程实训作业。二、项目整体需求与架构2.1 核心功能需求注解驱动 Bean 管理自定义 Component 注解标记业务类容器自动扫描实例化无需手动 new单例全局缓存容器启动统一创建单例对象全局复用自动依赖注入自定义 Autowired通过反射给成员变量赋值解除硬编码耦合AOP 切面增强自定义 Aspect 标记切面类JDK 动态代理对目标方法前后添加日志不修改原有业务代码容器统一上下文入口一键启动扫描、创建 Bean、生成代理、获取实例。2.2 整体包分层结构com.example.ioc ├── annotation // 自定义注解 │ Component.java │ Autowired.java │ Aspect.java │ Scope.java ├── aop // AOP切面基础 │ BaseAspect.java │ AspectHandler.java ├── context // IoC容器核心 │ BeanDefinition.java │ BeanScanner.java │ BeanFactory.java │ AopProxyFactory.java │ MiniSpringContext.java ├── service // 业务接口实现 │ UserService.java │ OrderService.java │ impl │ UserServiceImpl.java │ OrderServiceImpl.java └── TestContainer // 启动测试类2.3 核心技术点梳理注解 反射运行时读取类上 Component、Autowired 注解动态创建对象、赋值成员变量单例模式BeanFactory 使用 ConcurrentHashMap 缓存单例保证线程安全工厂模式Bean 工厂负责对象创建代理工厂统一生成 AOP 代理JDK 动态代理实现 InvocationHandler 拦截方法完成切面增强IO 文件遍历包扫描器递归读取 class 文件加载 Class 对象泛型、函数式编程简化容器获取 Bean 逻辑。三、Maven 项目配置pom.xml 核心依赖?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0 modelVersion4.0.0/modelVersion groupIdcom.example.ioc/groupId artifactIdmini-spring-ioc/artifactId version1.0-SNAPSHOT properties maven.compiler.source17/maven.compiler.source maven.compiler.target17/maven.compiler encodingUTF-8 /properties dependencies !-- Lombok简化实体代码 -- dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId version1.18.38/version scopeprovided/scope /dependency !-- 日志依赖 -- dependency groupIdorg.slf4j/groupId artifactIdslf4j-api/artifactId version2.0.9/version /dependency dependency groupIdch.qos.logback/groupId artifactIdlogback-classic/artifactId version1.4.11/version /dependency !-- JUnit测试 -- dependency groupIdjunit/groupId artifactIdjunit/artifactId version4.13/version scopetest/scope /dependency /dependencies /project四、分层完整代码实现4.1 自定义注解层 annotation1. Component 标记容器管理 Beanpackage com.example.ioc.annotation; import java.lang.annotation.*; /** * 标记类为IoC容器管理组件 */ Target(ElementType.TYPE) Retention(RetentionPolicy.RUNTIME) Documented public interface Component { String value() default ; }2. Autowired 自动注入注解package com.example.ioc.annotation; import java.lang.annotation.*; /** * 字段自动依赖注入 */ Target(ElementType.FIELD) Retention(RetentionPolicy.RUNTIME) Documented public interface Autowired { }3. Scope 作用域注解package com.example.ioc.annotation; import java.lang.annotation.*; /** * Bean作用域默认singleton单例 */ Target(ElementType.TYPE) Retention(RetentionPolicy.RUNTIME) public interface Scope { String value() default singleton; }4. Aspect 切面注解package com.example.ioc.annotation; import java.lang.annotation.*; /** * 标记切面类value指定要代理的目标类全限定名 */ Target(ElementType.TYPE) Retention(RetentionPolicy.RUNTIME) public interface Aspect { String value() default ; }4.2 AOP 切面基础层 aop1. 切面基类 BaseAspectpackage com.example.ioc.aop; /** * 切面统一父类定义前后置通知规范 */ public abstract class BaseAspect { // 方法执行前增强 public abstract void before(); // 方法执行后增强 public abstract void after(); }2. 动态代理拦截器 AspectHandlerpackage com.example.ioc.aop; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * JDK动态代理调用处理器拦截目标方法执行切面逻辑 */ public class AspectHandler implements InvocationHandler { // 原始目标对象 private final Object target; // 切面增强类 private final BaseAspect aspect; public AspectHandler(Object target, BaseAspect aspect) { this.target target; this.aspect aspect; } Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 前置通知 aspect.before(); // 执行原始业务方法 Object result method.invoke(target, args); // 后置通知 aspect.after(); return result; } /** 创建代理对象 */ public Object getProxy() { return java.lang.reflect.Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), this ); } }3. 日志切面实现类package com.example.ioc.aop; import com.example.ioc.annotation.Aspect; import com.example.ioc.annotation.Component; import lombok.extern.slf4j.Slf4j; /** * 日志切面拦截UserServiceImpl所有方法打印前后日志 */ Slf4j Component Aspect(value com.example.ioc.service.impl.UserServiceImpl) public class LogAspect extends BaseAspect{ Override public void before() { log.info(【AOP前置通知】方法即将执行); } Override public void after() { log.info(【AOP后置通知】方法执行完成); } }4.3 IoC 容器核心层 context1. BeanDefinition Bean 元数据模型package com.example.ioc.context; import com.example.ioc.annotation.Scope; import lombok.Getter; import lombok.Setter; /** * Bean定义存储类名、作用域、Bean标识名称 */ Getter Setter public class BeanDefinition { private String beanName; private Class? beanClass; private String scope singleton; public BeanDefinition(String beanName, Class? beanClass) { this.beanName beanClass; // 读取Scope注解 if (beanClass.isAnnotationPresent(Scope.class)) { this.scope beanClass.getAnnotation(Scope.class).value(); } } public boolean isSingleton() { return singleton.equals(scope); } }2. 包扫描器 BeanScannerpackage com.example.ioc.context; import com.example.ioc.annotation.Component; import java.io.File; import java.net.URL; import java.util.HashMap; import java.util.Map; /** * 包扫描工具递归遍历包下class文件识别Component生成BeanDefinition */ public class BeanScanner { private MapString, BeanDefinition beanDefinitionMap new HashMap(); public void scan(String basePackage) throws Exception { // 包路径转文件路径 String path basePackage.replace(., /); URL resource getClass().getClassLoader().getResource(path); if (resource null) return; File root new File(resource.toURI()); scanFile(root, basePackage); } // 递归扫描目录 private void scanFile(File file, String pkg) throws ClassNotFoundException { if (file.isDirectory()) { File[] files file.listFiles(); if (files null) return; for (File f : files) { if (f.isDirectory()) { scanFile(f, pkg . f.getName()); } else { String className pkg . f.getName().replace(.class, ); Class? clazz Class.forName(className); // 标记Component才注册 if (clazz.isAnnotationPresent(Component.class)) { registerBean(clazz); } } } } } // 注册Bean定义 private void registerBean(Class? clazz) { Component comp clazz.getAnnotation(Component.class); String beanName; if (comp.value().isBlank()) { // 首字母小写作为beanName String simpleName clazz.getSimpleName(); beanName Character.toLowerCase(simpleName.charAt(0)) simpleName.substring(1); // 去除Impl后缀 if (beanName.endsWith(Impl)) { beanName beanName.substring(0, beanName.length() - 4); } } else { beanName comp.value(); } beanDefinitionMap.put(beanName, new BeanDefinition(beanName, clazz)); } public MapString, BeanDefinition getBeanDefinitionMap() { return beanDefinitionMap; } }3. AOP 代理工厂 AopProxyFactorypackage com.example.ioc.context; import com.example.ioc.aop.AspectHandler; import com.example.ioc.aop.BaseAspect; import com.example.ioc.annotation.Aspect; /** * AOP代理单例工厂生成JDK动态代理对象 */ public class AopProxyFactory { private static final AopProxyFactory INSTANCE new AopProxyFactory(); private AopProxyFactory(){} public static AopProxyFactory getInstance() { return INSTANCE; } public Object createProxy(Class? aspectCls) throws Exception { // 实例化切面 BaseAspect aspect (BaseAspect) aspectCls.getDeclaredConstructor().newInstance(); // 获取切面指定的目标类 Aspect aspectAnno aspectCls.getAnnotation(Aspect.class); Class? targetCls Class.forName(aspectAnno.value()); Object target targetCls.getDeclaredConstructor().newInstance(); // 创建代理 AspectHandler handler new AspectHandler(target, aspect); return handler.getProxy(); } }4. Bean 工厂 BeanFactorypackage com.example.ioc.context; import com.example.ioc.annotation.Autowired; import java.lang.reflect.Field; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * Bean工厂负责实例化、依赖注入、单例缓存、代理替换 */ public class BeanFactory { private static final BeanFactory INSTANCE new BeanFactory(); // 单例Bean缓存池线程安全 private final MapString, Object singletonObjects new ConcurrentHashMap(); private MapString, BeanDefinition beanDefinitionMap; private BeanFactory(){} public static BeanFactory getInstance() { return INSTANCE; } public void init(MapString, BeanDefinition map) { this.beanDefinitionMap map; } // 初始化所有单例原始Bean public void createSingletonBeans() throws Exception { for (BeanDefinition def : beanDefinitionMap.values()) { if (def.isSingleton() !singletonObjects.containsKey(def.getBeanName())) { Object bean def.getBeanClass().getDeclaredConstructor().newInstance(); singletonObjects.put(def.getBeanName(), bean); } } } // 自动依赖注入 public void injectBean() throws Exception { for (BeanDefinition def : beanDefinitionMap.values()) { Class? clazz def.getBeanClass(); Object bean clazz.getDeclaredConstructor().newInstance(); // 遍历所有字段处理Autowired Field[] fields clazz.getDeclaredFields(); for (Field field : fields) { if (field.isAnnotationPresent(Autowired.class)) { field.setAccessible(true); // 根据类型从缓存获取依赖Bean Object depBean getBeanByType(field.getType()); field.set(bean, depBean); } } singletonObjects.put(def.getBeanName(), bean); } } // 替换切面目标Bean为代理对象 public void replaceAopProxy() throws Exception { AopProxyFactory proxyFactory AopProxyFactory.getInstance(); for (BeanDefinition def : beanDefinitionMap.values()) { Class? clazz def.getBeanClass(); if (clazz.isAnnotationPresent(com.example.ioc.annotation.Aspect.class)) { Object proxy proxyFactory.createProxy(clazz); // 覆盖缓存中原对象 modifyBean(clazz, proxy); } } } // 根据类型获取Bean SuppressWarnings(unchecked) public T T getBeanByType(ClassT clazz) { for (Object bean : singletonObjects.values()) { if (clazz.isAssignableFrom(bean.getClass())) { return (T) bean; } } return null; } // 根据Bean名称获取实例 public Object getBean(String beanName) { return singletonObjects.get(beanName); } // 根据类型替换缓存中的Bean public void modifyBean(Class? targetCls, Object proxyBean) { for (Map.EntryString, Object entry : singletonObjects.entrySet()) { if (targetCls.isAssignableFrom(entry.getValue().getClass())) { singletonObjects.put(entry.getKey(), proxyBean); } } } public MapString, Object getSingletonObjects() { return singletonObjects; } }5. 容器上下文 MiniSpringContextpackage com.example.ioc.context; import lombok.extern.slf4j.Slf4j; /** * IoC容器统一入口单例全局上下文 */ Slf4j public class MiniSpringContext { private static MiniSpringContext INSTANCE; private final String basePackage; private final BeanScanner scanner; private final BeanFactory beanFactory; private MiniSpringContext(String basePackage) { this.basePackage basePackage; this.scanner new BeanScanner(); this.beanFactory BeanFactory.getInstance(); refresh(); } // 容器刷新核心流程扫描-创建Bean-注入依赖-生成AOP代理 private void refresh() { try { log.info(迷你IoC容器开始启动...); // 1.包扫描 scanner.scan(basePackage); // 2.初始化工厂 beanFactory.init(scanner.getBeanDefinitionMap()); // 3.创建原始单例 beanFactory.createSingletonBeans(); // 4.自动依赖注入 beanFactory.injectBean(); // 5.替换AOP代理对象 beanFactory.replaceAopProxy(); log.info(IoC容器启动完成); } catch (Exception e) { log.error(容器启动失败, e); } } // 获取容器单例 public static MiniSpringContext getInstance(String basePackage) { if (INSTANCE null) { synchronized (MiniSpringContext.class) { if (INSTANCE null) { INSTANCE new MiniSpringContext(basePackage); } } } return INSTANCE; } // 根据类型获取Bean public T T getBean(ClassT clazz) { return beanFactory.getBeanByType(clazz); } // 根据Bean名称获取 public Object getBean(String beanName) { return beanFactory.getBean(beanName); } }4.4 业务层 Service1. UserService 接口package com.example.ioc.service; public interface UserService { void sayHello(); }2. UserServiceImpl 实现类被 AOP 拦截package com.example.ioc.service.impl; import com.example.ioc.annotation.Component; import com.example.ioc.service.User; Component public class UserServiceImpl implements UserService { Override public void sayHello() { System.out.println(用户业务方法执行Hello IoCAOP); } }3. OrderService 接口package com.example.ioc.service; public interface OrderService { void testOrder(); }4. OrderServiceImpl依赖注入 UserServicepackage com.example.ioc.service.impl; import com.example.ioc.annotation.Autowired; import com.example.ioc.annotation.Component; import com.example.ioc.service.OrderService; import com.example.ioc.service.UserService; Component public class OrderServiceImpl implements OrderService { Autowired private UserService userService; Override public void testOrder() { System.out.println(订单业务逻辑执行); userService.sayHello(); } }4.5 测试启动类package com.example.ioc; import com.example.ioc.context.MiniSpringContext; import com.example.ioc.service.OrderService; import lombok.extern.slf4j.Slf4j; Slf4j public class TestContainer { public static void main(String[] args) { // 扫描根包启动容器 MiniSpringContext context MiniSpringContext.getInstance(com.example.ioc); // 根据类型获取Bean Order order1 context.getBean(OrderService.class); // 根据名称获取Bean Order order2 (OrderService) context.getBean(orderService); log.info(order1和order2是否为同一个单例{}, order1 order2); log.info(执行业务方法观察AOP日志); order1.testOrder(); } }五、运行结果解析控制台输出流程容器启动日志完成包扫描、Bean 实例化、依赖注入打印两个 OrderService 对象地址完全相同证明单例缓存生效执行 testOrder () 方法 先打印【AOP 前置通知】再输出订单业务调用 userService.sayHello 后打印【AOP 后置通知】自动注入成功OrderServiceImpl 中无需手动 new UserService容器自动装配。六、底层核心原理拆解面试高频1. IoC 控制反转传统写法业务代码主动 new 依赖对象主动创建 IoC 容器由容器统一创建所有 Bean业务直接获取控制权交给容器反转 本项目通过包扫描 反射动态创建对象完全模拟 Spring 的 Bean 工厂。2. Autowired 注入原理反射获取类所有 Field 字段判断字段标注 Autowired根据字段类型去单例缓存池中匹配对应 BeansetAccessible (true) 打破私有权限反射赋值实现自动装配。3. AOP JDK 动态代理限制JDK 动态代理只能代理实现接口的类原理运行时生成目标接口的代理类拦截所有接口方法 如果类没有实现接口需要 CGLIB 字节码代理本项目为简化使用 JDK 代理。4. 单例线程安全设计BeanFactory 使用 ConcurrentHashMap 存储单例容器创建使用双重校验锁实现单例上下文避免多线程启动容器创建多个上下文实例。七、结尾这份迷你 Spring 容器项目没有任何 Spring 框架依赖全部基于 Java 基础注解、反射、动态代理、单例、工厂模式手写实现完美复刻 Spring 两大核心 IoC 和 AOP。很多开发者只会调 Autowired、Aspect 注解但完全不知道底层如何反射创建对象、如何拦截方法跟着本项目逐行调试就能打通 Spring 底层知识盲区面试问到 IoC/AOP 手写实现也能流畅作答。
返回列表