1. 项目背景与价值
去年在团队内部做技术分享时,我发现很多同事虽然天天用Spring框架,但对它的核心机制理解很模糊。这就像开车多年却不知道发动机工作原理,遇到复杂故障时就束手无策。于是萌生了一个想法:能不能通过从零实现一个简化版Spring框架,来彻底搞懂那些隐藏在注解背后的魔法?
这个"轮子"项目不是要替代Spring,而是通过造轮子的过程掌握以下核心能力:
- 理解控制反转(IoC)和依赖注入(DI)的实现原理
- 拆解AOP的动态代理机制
- 掌握Bean生命周期管理的设计思路
- 深入理解Spring最核心的注解工作原理
2. 核心架构设计
2.1 最小化架构设计
我们先定义最精简的核心组件:
java复制// 框架核心类结构
MiniSpringContext (入口类)
├── BeanDefinition (Bean定义)
├── BeanFactory (Bean工厂)
├── BeanPostProcessor (Bean处理器)
└── AopProxy (AOP代理)
2.2 IoC容器实现关键点
- Bean定义扫描:
java复制// 类路径扫描实现
public void scan(String basePackage) {
String classpath = this.getClass().getResource("/").getPath();
String packagePath = basePackage.replace(".", "/");
File dir = new File(classpath + packagePath);
for (File file : dir.listFiles()) {
if(file.getName().endsWith(".class")) {
String className = basePackage + "."
+ file.getName().replace(".class", "");
// 解析类注解...
}
}
}
- 依赖注入实现:
- 字段注入:通过反射设置@Autowired标记的字段
- 构造器注入:解析参数类型并递归获取依赖Bean
关键点:循环依赖检测需要引入三级缓存机制,类似Spring的singletonFactories、earlySingletonObjects等设计
3. 核心功能实现细节
3.1 Bean生命周期管理
完整生命周期流程:
code复制1. 实例化Bean
2. 属性填充(Populate)
3. 初始化前处理(@PostConstruct)
4. 初始化(InitializingBean)
5. 初始化后处理(AOP代理)
6. 使用中
7. 销毁前处理(@PreDestroy)
3.2 AOP动态代理实现
我们实现两种代理方式:
- JDK动态代理:
java复制public Object getProxy(Object target) {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
(proxy, method, args) -> {
// 前置增强
System.out.println("[Proxy] Before " + method.getName());
Object result = method.invoke(target, args);
// 后置增强
System.out.println("[Proxy] After " + method.getName());
return result;
}
);
}
- CGLIB代理:
java复制public Object getProxy(Class<?> targetClass) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(targetClass);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method,
Object[] args, MethodProxy proxy) throws Throwable {
// 增强逻辑...
return proxy.invokeSuper(obj, args);
}
});
return enhancer.create();
}
4. 关键注解实现
4.1 @Component注解处理
java复制// 自定义组件注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyComponent {
String value() default "";
}
// 扫描处理逻辑
if (clazz.isAnnotationPresent(MyComponent.class)) {
String beanName = clazz.getAnnotation(MyComponent.class).value();
if (beanName.isEmpty()) {
beanName = Introspector.decapitalize(clazz.getSimpleName());
}
registerBeanDefinition(beanName, clazz);
}
4.2 @Autowired实现技巧
处理字段注入时的递归依赖解决:
java复制Field[] fields = bean.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(MyAutowired.class)) {
Object fieldBean = getBean(field.getType());
field.setAccessible(true);
field.set(bean, fieldBean);
}
}
5. 性能优化实践
5.1 Bean缓存机制
java复制// 三级缓存解决循环依赖
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(); // 一级缓存
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(); // 二级缓存
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(); // 三级缓存
5.2 反射优化技巧
- 缓存Constructor和Method对象
- 对Field.setAccessible做批量处理
- 使用MethodHandle替代反射调用
6. 测试验证方案
6.1 基础功能测试用例
java复制@MyComponent
public class UserService {
@MyAutowired
private OrderService orderService;
public void createOrder() {
orderService.process();
}
}
// 测试代码
MiniSpringContext context = new MiniSpringContext("com.example");
UserService userService = (UserService) context.getBean("userService");
userService.createOrder();
6.2 AOP功能验证
java复制@MyAspect
public class LogAspect {
@MyBefore("execution(* com.example..*.*(..))")
public void before(JoinPoint jp) {
System.out.println("Before: " + jp.getSignature());
}
}
7. 踩坑经验总结
- 循环依赖陷阱:
- 使用三级缓存解决setter注入循环依赖
- 构造器注入的循环依赖无法解决,需要设计规避
- 代理对象问题:
- AOP代理可能影响@Autowired注入
- 需要特殊处理自调用场景
- 注解继承难题:
- 自定义注解需要明确@Inherited策略
- 元注解的继承关系需要特殊处理
- 并发安全注意:
- Bean初始化需要加锁
- 避免在Bean构造方法中调用其他Bean
这个实现过程让我真正理解了Spring的设计精妙之处。比如三级缓存解决循环依赖的方案,单纯看源码很难体会其精妙,自己实现一遍才发现每个缓存层级都有不可替代的作用。建议每个Java开发者都应该尝试实现这样一个简化版核心框架,这比单纯看源码或文档的理解要深刻得多。