在程序员的职业生涯中,会经历从“会用工具”到“理解工具”,再到“创造工具”的蜕变。如果说初级程序员的核心竞争力是熟练度,那么中高级程序员的分水岭便是框架驾驭能力与源码思想领悟能力。
本文将围绕“精通主流框架与源码思想”这一核心主题,从框架设计哲学、核心源码解析、IOC与DI、AOP、设计模式在框架中的应用、SPI机制、以及如何高效阅读源码七个维度,带你深入掌握这一进阶技能。
一、为什么需要“精通”而不仅仅是“使用”?
大多数开发者都停留在“配置即运行”的层面:引入Spring Boot Starter,写几个注解,启动服务,调通接口。但面对以下场景时,往往束手无策:
线上诡异Bug:Bean循环依赖导致的启动失败,事务失效,AOP切面不执行。
性能调优:不知道Spring是如何管理连接池、缓存、异步任务的。
二次开发:需要基于已有框架(如Dubbo、Netty)做深度定制。
面试:大厂面试中,“请你谈谈Spring Boot的自动配置原理”几乎是必考题。
精通框架意味着:你不再被框架限制,而是能够预测、调试甚至重构框架的行为。
二、主流框架的核心——Spring Framework
当前Java生态中,Spring Framework是绝对的事实标准。掌握Spring,就等于掌握了Java后端开发半壁江山的钥匙。
2.1 Spring的设计哲学:从“侵入式”到“非侵入式”
Spring的核心承诺是 POJO (Plain Old Java Object) 编程。它不要求你继承特定的类或实现特定的接口(相比于EJB),而是通过元数据(注解或XML)来增强POJO。
// 普通的POJO,没有任何框架痕迹
public class OrderService {
public void createOrder() {
System.out.println("Creating order...");
}
}
// 通过注解,变成Spring管理的Bean
@Service
public class OrderService {
@Transactional
public void createOrder() {
// 业务逻辑
}
}
2.2 控制反转(IoC)与依赖注入(DI)源码级剖析
IoC容器是Spring的心脏。其核心工作流程如下:
资源定位:找到配置文件或注解标记的类。
BeanDefinition加载:将配置解析成BeanDefinition对象(包含类名、作用域、构造函数参数等)。
BeanDefinition注册:将定义注册到BeanDefinitionRegistry(实际是一个ConcurrentHashMap)。
Bean实例化:通过反射或CGLIB创建对象实例。
依赖注入:填充对象的属性。
初始化:执行各种Aware接口、@PostConstruct、init-method。
核心源码追踪:refresh() 方法
在org.springframework.context.support.AbstractApplicationContext中,refresh()是整个IoC启动的入口:
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 1. 准备刷新环境
prepareRefresh();
// 2. 获取BeanFactory(默认DefaultListableBeanFactory)
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 3. 设置BeanFactory的类加载器、后处理器等
prepareBeanFactory(beanFactory);
// 4. 调用BeanFactoryPostProcessor(允许修改BeanDefinition)
invokeBeanFactoryPostProcessors(beanFactory);
// 5. 注册BeanPostProcessor(Bean的后置处理器)
registerBeanPostProcessors(beanFactory);
// 6. 初始化MessageSource(国际化)
initMessageSource();
// 7. 初始化ApplicationEventMulticaster(事件广播器)
initApplicationEventMulticaster();
// 7.5 允许子类刷新其他特殊Bean
onRefresh();
// 8. 注册监听器
registerListeners();
// 9. 完成BeanFactory初始化,实例化所有单例Bean(非懒加载)
finishBeanFactoryInitialization(beanFactory);
// 10. 完成刷新,发布事件
finishRefresh();
}
}
依赖注入解决循环依赖:三级缓存
Spring通过三级缓存解决单例Bean的循环依赖问题:
// DefaultSingletonBeanRegistry中的缓存定义
/** 一级缓存:完全初始化好的单例Bean */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** 二级缓存:早期暴露的原始Bean(未填充属性) */
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
/** 三级缓存:Bean的工厂对象,用于生成代理 */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
流程解析:
A创建时,将自己放入三级缓存(singletonFactories)。
A注入B,发现B未创建,开始创建B。
B创建时,发现需要注入A,从三级缓存获取ObjectFactory,调用getObject()得到A的早期引用,并移入二级缓存。
B完成注入和初始化,存入一级缓存。
A继续完成注入和初始化,存入一级缓存。
为什么需要三级缓存? —— 为了处理AOP代理。如果A需要被代理,三级缓存中的ObjectFactory返回的是代理对象而非原始对象,确保注入的是代理。
三、面向切面编程(AOP)—— 动态代理的艺术
AOP允许你将日志、事务、权限等横切关注点与业务逻辑分离。
3.1 JDK动态代理 vs CGLIB
3.2 源码解析:创建AOP代理
Spring AOP的核心类是JdkDynamicAopProxy和CglibAopProxy。以JDK实现为例:
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 获取拦截器链(所有匹配该方法的Advice)
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
if (chain.isEmpty()) {
// 无拦截器,直接反射调用目标方法
return AopUtils.invokeJoinpointUsingReflection(target, method, args);
}
// 创建方法调用对象
MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// 执行拦截器链
return invocation.proceed();
}
}
3.3 手写一个简单的AOP实现
理解AOP本质的最好方式是自己实现一个极简版:
// 1. 定义切面注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyBefore {
String value();
}
// 2. 代理工厂
public class ProxyFactory {
public static Object createProxy(Object target, MyAspect aspect) {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
(proxy, method, args) -> {
// 前置增强
if (aspect.beforeMethod(method.getName())) {
aspect.before();
}
// 调用原方法
Object result = method.invoke(target, args);
return result;
}
);
}
}