引言
在现代Java开发中,IoC(控制反转)容器是Spring框架的核心组件之一。它通过依赖注入(DI)机制,帮助我们管理对象的生命周期和依赖关系,极大地提升了代码的可维护性和可扩展性。然而,IoC容器的底层实现并不简单,尤其是当涉及到循环依赖 和缓存机制时,其设计思路和实现细节往往令人感到困惑。
你是否曾经好奇过:
- IoC容器是如何管理Bean的实例化和依赖注入的?
- 为什么需要一级缓存和二级缓存?
- 二级缓存是如何解决循环依赖问题的?
本文将通过手动实现一个简单的IoC容器 ,逐步揭开这些问题的答案。我们将从一级缓存 的设计开始,逐步引入二级缓存,并通过代码示例详细讲解其工作原理。无论你是初学者还是有一定经验的开发者,相信这篇文章都能帮助你更深入地理解IoC容器的底层逻辑。
IoC容器的核心功能
在开始之前,我们先回顾一下IoC容器的核心功能:
- Bean的扫描与注册 :通过类加载器扫描指定包下的类,并根据注解(如
@Component
、@Service
)识别Bean。 - Bean的实例化与依赖注入 :通过反射机制实例化Bean,并通过
@Autowired
注解实现依赖注入。 - Bean的生命周期管理:通过缓存机制管理单例Bean,确保每个Bean只被实例化一次。
我们需要实现的功能是为了更好地理解这些功能,我们将通过一个具体的示例来逐步实现一个简单的IoC容器。假设我们有一个DemoApplication
类,它的功能如下:
java
public class DemoApplication {
public static void main(String[] args) throws Exception {
// 启动IoC容器
Application application = Application.start(DemoApplication.class);
// 通过名称获取Bean
UserService userService = application.getBean("UserServiceImpl");
userService.say();
// 通过类型获取Bean
application.getBean(UserService.class).say();
}
}
//用户服务
public interface UserService {
void say();
}
//用户服务的实现
@Service
public class UserServiceImpl implements UserService {
@Autowired
private OrderService orderService;
@Override
public void say() {
System.out.println("hello");
orderService.say();
}
}
//订单服务
public interface OrderService {
void say();
}
//订单服务的实现
@Service
public class OrderServiceImpl implements OrderService {
@Override
public void say() {
System.out.println("hello OrderService");
}
}
为了实现这个功能,我们需要完成以下步骤:
- 扫描指定包下的类 ,识别带有
@Component
或@Service
注解的类。 - 实例化这些类,并将它们存储在容器中。
- 实现依赖注入 ,通过
@Autowired
注解自动注入依赖。 - 提供获取Bean的方法,支持通过名称和类型获取Bean。
接下来,我们将逐步实现这些功能。
java
//首先我们需要几个注解
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired{
}
package org.example.annotation;
import java.lang.annotation.*;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface Component {
}
package org.example.annotation;
import java.lang.annotation.*;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service {
String value() default "";
}
一级缓存的设计与实现
一级缓存的作用
一级缓存(singletonObjects
)是一个ConcurrentHashMap
,用于存储已经完全初始化的单例Bean。它的作用是:
- 确保每个Bean只被实例化一次。
- 提供快速访问Bean实例的能力。
一级缓存的实现
java
package org.example.framework;
import org.example.annotation.Autowired;
import org.example.annotation.Component;
import org.example.annotation.Service;
import javax.annotation.*;
import java.io.File;
import java.lang.annotation.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.net.URL;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 简单的IoC容器实现类,支持Bean的扫描、实例化、依赖注入和缓存管理。
*/
public class Application1 {
// 存储Bean实例的容器
private Map<String, Object> singletonObjects = new ConcurrentHashMap<>();
// 存储每个类型对应的Bean名称列表,用于支持按类型获取Bean
private Map<Class<?>, List<String>> allBeanNamesByType = new ConcurrentHashMap<>();
/**
* 启动IoC容器。
*
* @param aClass 启动类的Class对象,用于确定扫描的包路径
* @return Application1实例
* @throws Exception 如果启动过程中发生异常
*/
public static Application1 start(Class aClass) throws Exception {
// 创建Application1实例并调用run方法
return new Application1().run(aClass);
}
/**
* 运行IoC容器,扫描包路径并初始化Bean。
*
* @param aClass 启动类的Class对象
* @return Application1实例
* @throws Exception 如果运行过程中发生异常
*/
private Application1 run(Class aClass) throws Exception {
// 获取包路径并转换为文件路径
String packageName = aClass.getPackage().getName().replace(".", "/");
// 获取当前线程的类加载器
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
// 获取包路径对应的URL资源
URL resource = contextClassLoader.getResource(packageName);
// 获取资源的文件路径
String path = resource.getPath();
// 截取路径,去掉"/class"部分
path = path.substring(0, path.indexOf("/class"));
// 获取包路径下所有类
List<Class> classList = getClassNameByFile(path);
// 初始化带有@Service注解的Bean
List<Object> serviceBean = constructor(classList.stream()
.filter(e -> e.isAnnotationPresent(Service.class)) // 过滤出带有@Service注解的类
.collect(Collectors.toList())); // 转换为List
serviceInit(serviceBean); // 初始化这些Bean
return this;
}
/**
* 根据Bean名称获取Bean实例。
*
* @param beanName Bean的名称
* @return Bean实例
*/
public <T> T getBean(String beanName) {
// 如果一级缓存中没有该Bean,返回null
if (!singletonObjects.containsKey(beanName)) {
return null;
}
// 从一级缓存中获取Bean实例
return (T) singletonObjects.get(beanName);
}
/**
* 根据类型获取Bean实例。
*
* @param aClass Bean的类型
* @return Bean实例
*/
public <T> T getBean(Class<T> aClass) {
// 根据类型获取Bean名称
String beanName = transformedBeanName(aClass);
// 根据名称获取Bean实例
T bean = getBean(beanName);
// 如果找到Bean,直接返回
if (Objects.nonNull(bean)) {
return bean;
}
// 根据类型获取所有Bean名称
List<String> list = allBeanNamesByType.get(aClass);
// 如果没有找到对应的Bean名称,返回null
if (Objects.isNull(list)) {
return null;
}
// 如果找到多个Bean,抛出异常
if (list.size() != 1) {
throw new RuntimeException("找到多个bean");
}
// 返回第一个Bean实例
return getBean(allBeanNamesByType.get(aClass).iterator().next());
}
/**
* 初始化带有@Service注解的Bean。
*
* @param serviceBeans 需要初始化的Bean列表
* @throws Exception 如果初始化过程中发生异常
*/
public void serviceInit(List<Object> serviceBeans) throws Exception {
// 如果Bean列表为空,直接返回
if (serviceBeans.isEmpty()) {
return;
}
// 用于存储未完成初始化的Bean
List<Object> resultBean = new ArrayList<>();
for (Object serviceBean : serviceBeans) {
// 如果依赖注入成功,则将Bean放入一级缓存
if (autowiredInjection(serviceBean)) {
singletonObjects.put(transformedBeanName(serviceBean.getClass()), serviceBean);
} else {
// 如果依赖注入失败,则将Bean加入待处理列表
resultBean.add(serviceBean);
}
}
// 递归处理未完成的Bean
if (!resultBean.isEmpty()) {
serviceInit(resultBean);
}
}
/**
* 自动注入依赖。
*
* @param bean 需要注入依赖的Bean实例
* @return 是否注入成功
* @throws Exception 如果注入过程中发生异常
*/
public boolean autowiredInjection(Object bean) throws Exception {
// 获取所有带有@Autowired注解的字段
List<Field> fieldList = Stream.of(Arrays.asList(bean.getClass().getFields()), Arrays.asList(bean.getClass().getDeclaredFields()))
.flatMap(Collection::stream) // 将多个列表合并为一个流
.filter(e -> e.isAnnotationPresent(Autowired.class)) // 过滤出带有@Autowired注解的字段
.distinct() // 去重
.collect(Collectors.toList()); // 转换为List
// 获取所有带有@Autowired注解的方法
List<Method> methodList = Stream.of(Arrays.asList(bean.getClass().getMethods()), Arrays.asList(bean.getClass().getDeclaredMethods()))
.flatMap(Collection::stream) // 将多个列表合并为一个流
.filter(e -> e.isAnnotationPresent(Autowired.class)) // 过滤出带有@Autowired注解的方法
.distinct() // 去重
.collect(Collectors.toList()); // 转换为List
// 注入字段依赖
for (Field field : fieldList) {
// 获取字段对应的Bean实例
Object paramBean = getBeanCache(field.getName(), field.getType());
// 如果找不到对应的Bean,返回false
if (Objects.isNull(paramBean)) {
return false;
}
// 设置字段可访问
field.setAccessible(true);
// 将Bean实例注入字段
field.set(bean, paramBean);
}
// 注入方法依赖
for (Method method : methodList) {
// 存储方法参数
List<Object> params = new ArrayList<>();
// 获取方法的所有参数
Parameter[] parameters = method.getParameters();
for (Parameter parameter : parameters) {
// 获取参数对应的Bean实例
Object parameterBean = getBeanCache(parameter.getName(), parameter.getType());
// 如果找不到对应的Bean,返回false
if (Objects.isNull(parameterBean)) {
return false;
}
// 将Bean实例加入参数列表
params.add(parameterBean);
}
// 设置方法可访问
method.setAccessible(true);
// 调用方法,注入参数
method.invoke(bean, params.toArray());
}
return true;
}
/**
* 根据类获取Bean名称。
*
* @param aclass 类的Class对象
* @return Bean的名称
*/
public String transformedBeanName(Class aclass) {
// 如果类带有@Service注解
if (aclass.isAnnotationPresent(Service.class)) {
Service service = (Service) aclass.getAnnotation(Service.class);
// 如果@Service注解的value属性不为空,则使用value作为Bean名称
if (Objects.nonNull(service.value()) && !service.value().isEmpty()) {
return service.value();
}
}
// 否则使用类的简单名称作为Bean名称
return aclass.getSimpleName();
}
/**
* 根据名称和类型从缓存中获取Bean实例。
*
* @param name Bean的名称
* @param clazz Bean的类型
* @return Bean实例
* @throws Exception 如果获取过程中发生异常
*/
private Object getBeanCache(String name, Class clazz) throws Exception {
// 根据名称从缓存中获取Bean实例
Object bean = getBeanCache(name);
// 如果找到Bean,直接返回
if (Objects.nonNull(bean)) {
return bean;
}
// 根据类型从缓存中获取Bean实例
return getBeanCache(clazz);
}
/**
* 根据类型从缓存中获取Bean实例。
*
* @param clazz Bean的类型
* @return Bean实例
* @throws Exception 如果获取过程中发生异常
*/
public Object getBeanCache(Class clazz) throws Exception {
// 根据类型的简单名称从缓存中获取Bean实例
Object bean = getBeanCache(clazz.getSimpleName());
// 如果找到Bean,直接返回
if (Objects.nonNull(bean)) {
return bean;
}
// 根据类型获取所有Bean名称
List<String> list = allBeanNamesByType.get(clazz);
// 如果没有找到对应的Bean名称,返回null
if (Objects.isNull(list)) {
return null;
}
// 如果找到多个Bean,抛出异常
if (list.size() != 1) {
throw new RuntimeException("找到多个Bean:" + clazz.getName());
}
// 返回第一个Bean实例
return getBeanCache(allBeanNamesByType.get(clazz).iterator().next());
}
/**
* 根据名称从缓存中获取Bean实例。
*
* @param name Bean的名称
* @return Bean实例
*/
private Object getBeanCache(String name) {
// 如果一级缓存中有该Bean,返回实例
if (singletonObjects.containsKey(name)) {
return singletonObjects.get(name);
}
// 否则返回null
return null;
}
/**
* 实例化Bean。
*
* @param classList 需要实例化的类列表
* @return Bean实例列表
* @throws Exception 如果实例化过程中发生异常
*/
public List<Object> constructor(List<Class> classList) throws Exception {
// 存储未完成实例化的类
List<Class> resultClass = new ArrayList<>();
// 存储已实例化的Bean
List<Object> beans = new ArrayList<>();
for (Class classes : classList) {
Constructor defaultConstructor = null;
Constructor autowriteConstructor = null;
// 获取类的所有构造函数
Set<Constructor> constructorSet = new HashSet<>();
constructorSet.addAll(Arrays.asList(classes.getConstructors()));
constructorSet.addAll(Arrays.asList(classes.getDeclaredConstructors()));
// 如果只有一个构造函数,则使用默认构造函数
if (constructorSet.size() == 1) {
defaultConstructor = constructorSet.iterator().next();
}
// 获取带有@Autowired注解的构造函数
List<Constructor> constructorList = constructorSet.stream()
.filter(e -> e.isAnnotationPresent(Autowired.class))
.collect(Collectors.toList());
// 如果有多个带有@Autowired注解的构造函数,抛出异常
if (constructorList.size() > 1) {
throw new RuntimeException("存在多个autowrite" + classes.getSimpleName());
}
// 如果只有一个带有@Autowired注解的构造函数,使用它
if (constructorList.size() == 1) {
autowriteConstructor = constructorList.get(0);
}
Constructor constructor = null;
// 优先使用带有@Autowired注解的构造函数
if (Objects.nonNull(autowriteConstructor)) {
constructor = autowriteConstructor;
} else if (Objects.nonNull(defaultConstructor)) {
// 否则使用默认构造函数
constructor = defaultConstructor;
}
Object objectBean = null;
// 如果没有构造函数,则使用默认无参构造函数
if (Objects.isNull(constructor)) {
objectBean = classes.newInstance();
} else {
// 构造函数的参数注入
List<Object> params = new ArrayList<>();
boolean flag = true;
for (Parameter parameter : constructor.getParameters()) {
// 获取参数对应的Bean实例
Object bean = getBeanCache(parameter.getName(), parameter.getType());
// 如果找不到对应的Bean,标记为失败
if (Objects.isNull(bean)) {
flag = false;
break;
}
// 将Bean实例加入参数列表
params.add(bean);
}
// 如果所有参数都找到对应的Bean,则实例化对象
if (flag) {
constructor.setAccessible(true);
objectBean = constructor.newInstance(params.toArray());
}
}
// 如果实例化成功,将Bean加入列表
if (Objects.nonNull(objectBean)) {
beans.add(objectBean);
} else {
// 否则将类加入未完成列表
resultClass.add(classes);
}
}
// 递归处理未完成的类
if (!resultClass.isEmpty()) {
beans.add(constructor(resultClass));
}
return beans;
}
/**
* 根据文件路径获取类名列表。
*
* @param path 文件路径
* @return 类名列表
* @throws ClassNotFoundException 如果类未找到
*/
public List<Class> getClassNameByFile(String path) throws ClassNotFoundException {
List<Class> classList = new ArrayList<>();
File file = new File(path);
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
for (File listFile : file.listFiles()) {
if (listFile.isDirectory()) {
// 递归处理子目录
classList.addAll(getClassNameByFile(listFile.getPath()));
} else {
String childFilePath = listFile.getPath();
if (childFilePath.endsWith(".class")) {
// 转换为类名
childFilePath = childFilePath.substring(childFilePath.indexOf("\classes") + 9, childFilePath.lastIndexOf("."));
childFilePath = childFilePath.replace("\", ".");
Class aClass = classLoader.loadClass(childFilePath);
// 如果类带有@Component注解且不是注解类,则加入列表
if (!getAnnotation(aClass) || aClass.isAnnotation()) {
continue;
}
classList.add(aClass);
// 注册接口与实现类的映射关系
Class[] interfaces = aClass.getInterfaces();
for (Class anInterface : interfaces) {
if (!allBeanNamesByType.containsKey(anInterface)) {
allBeanNamesByType.put(anInterface, Arrays.asList(aClass.getSimpleName()));
} else {
allBeanNamesByType.get(anInterface).add(aClass.getSimpleName());
}
}
}
}
}
return classList;
}
/**
* 判断类是否带有@Component注解。
*
* @param clazz 类的Class对象
* @return 是否带有@Component注解
*/
public boolean getAnnotation(Class<?> clazz) {
Annotation[] annotations = clazz.getAnnotations();
for (Annotation annotation : annotations) {
// 忽略一些常见的注解
if (annotation.annotationType() == Deprecated.class ||
annotation.annotationType() == SuppressWarnings.class ||
annotation.annotationType() == Override.class ||
annotation.annotationType() == PostConstruct.class ||
annotation.annotationType() == PreDestroy.class ||
annotation.annotationType() == Resource.class ||
annotation.annotationType() == Resources.class ||
annotation.annotationType() == Generated.class ||
annotation.annotationType() == Target.class ||
annotation.annotationType() == Retention.class ||
annotation.annotationType() == Documented.class ||
annotation.annotationType() == Inherited.class) {
continue;
}
// 如果类带有@Component注解,返回true
if (annotation.annotationType() == Component.class) {
return true;
} else {
// 递归检查注解的注解
return getAnnotation(annotation.annotationType());
}
}
return false;
}
}
一级缓存的工作流程
Bean 的注册与缓存:
在容器启动时,扫描指定包下的类,识别带有 @Component
或 @Service
注解的类。
通过反射机制实例化这些类,支持以下依赖注入方式:
- 字段注入 :通过
@Autowired
注解直接注入字段。 - 构造器注入 :通过
@Autowired
标记构造器,实例化时自动解析参数依赖。 - 方法注入 :通过
@Autowired
标记方法,在 Bean 初始化后调用方法注入参数。
java
// 构造器注入示例
@Service
public class UserServiceImpl implements UserService {
private final OrderService orderService;
@Autowired // 支持构造器注入
public UserServiceImpl(OrderService orderService) {
this.orderService = orderService;
}
}
// 方法注入示例
@Service
public class OrderServiceImpl implements OrderService {
private UserService userService;
@Autowired // 方法注入
public void setUserService(UserService userService) {
this.userService = userService;
}
}
Bean 的获取
通过 getBean
方法,从一级缓存中获取已初始化的 Bean。
如果缓存中不存在该 Bean,则返回 null
或抛出异常。
循环依赖的困境与二级缓存的解决方案
在实际开发中,循环依赖是一个常见的问题。例如,假设我们在 OrderServiceImpl
中注入 UserServiceImpl
,而 UserServiceImpl
中又注入了 OrderServiceImpl
,这就形成了一个典型的循环依赖场景:
java
// UserServiceImpl
@Service
public class UserServiceImpl implements UserService {
@Autowired
private OrderService orderService;
@Override
public void say() {
System.out.println("hello");
orderService.say();
}
@Override
public void processUser() {
System.out.println("Processing user in UserService");
}
}
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
private UserService userService;
@Override
public void say() {
System.out.println("hello OrderService");
userService.processUser();
}
}
在这种情况下,IoC 容器会陷入一个死循环:
- 实例化
UserServiceImpl
,发现它依赖OrderServiceImpl
。 - 开始实例化
OrderServiceImpl
,发现它依赖UserServiceImpl
。 - 又回到
UserServiceImpl
,导致无限递归,最终抛出异常。
二级缓存的设计与实现
为了解决循环依赖问题,我们引入了二级缓存。
二级缓存的作用
在手动实现的 IoC 容器中,二级缓存(earlySingletonObjects
)是解决循环依赖问题的关键。它的核心作用是:
- 提前暴露 Bean 的引用:在 Bean 还未完全初始化时,将其引用放入二级缓存。
- 打破循环依赖:当另一个 Bean 需要依赖当前 Bean 时,可以从二级缓存中获取其引用,而不需要等待当前 Bean 完全初始化。
二级缓存的设计
二级缓存的设计基于以下核心思想:
- 一级缓存(
singletonObjects
) :存储完全初始化后的单例 Bean,确保全局唯一性和直接可用性。 - 二级缓存(
earlySingletonObjects
) :存储已实例化但未完成依赖注入的 Bean(半成品 Bean),用于解决循环依赖。
二级缓存的实现
java
public class Application {
// 一级缓存:存储完全初始化的 Bean
private Map<String, Object> singletonObjects = new ConcurrentHashMap<>();
// 二级缓存:存储已实例化但未完成初始化的 Bean
private Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>();
// 修改后的 getBeanCache 方法,支持从二级缓存获取 Bean
private Object getBeanCache(String name) throws Exception {
// 先检查一级缓存
if (singletonObjects.containsKey(name)) {
return singletonObjects.get(name);
}
// 再检查二级缓存
if (earlySingletonObjects.containsKey(name)) {
return earlySingletonObjects.get(name);
}
return null;
}
// 修改后的 serviceInit 方法,支持半成品 Bean 的存储
public void serviceInit(List<Object> serviceBeans) throws Exception {
if (serviceBeans.isEmpty()) {
return;
}
List<Object> resultBean = new ArrayList<>();
for (Object serviceBean : serviceBeans) {
String beanName = transformedBeanName(serviceBean.getClass());
if (autowiredInjection(serviceBean)) {
// 依赖注入成功,移入一级缓存并移除二级缓存
singletonObjects.put(beanName, serviceBean);
earlySingletonObjects.remove(beanName);
} else {
// 依赖注入失败,暂存到二级缓存
earlySingletonObjects.put(beanName, serviceBean);
resultBean.add(serviceBean);
}
}
// 递归处理未完成的 Bean
if (!resultBean.isEmpty()) {
serviceInit(resultBean);
}
}
}
解决循环依赖的流程
1. 初始化 UserServiceImpl
当容器开始初始化 UserServiceImpl
时,首先通过反射创建它的实例。此时的 UserServiceImpl
还未完成依赖注入(即 orderService
字段为空),因此它被标记为"半成品"并存入 二级缓存 earlySingletonObjects
。这一步骤的核心目的是 提前暴露 Bean 的引用,使得其他 Bean 在初始化时可以获取到它的引用。
java
// UserServiceImpl 实例化完成,但依赖未注入
Object userService = new UserServiceImpl();
earlySingletonObjects.put("UserServiceImpl", userService);
2.触发 OrderServiceImpl 的初始化
接下来,容器尝试为 UserServiceImpl
注入 OrderService
依赖。由于 OrderServiceImpl
尚未初始化,容器开始创建 OrderServiceImpl
的实例。同样的,OrderServiceImpl
在实例化后也被存入二级缓存,但它的 userService
字段此时尚未注入。
java
// OrderServiceImpl 实例化完成,但依赖未注入
Object orderService = new OrderServiceImpl();
earlySingletonObjects.put("OrderServiceImpl", orderService);
3.解决 OrderServiceImpl 的依赖
当容器为 OrderServiceImpl
注入 UserService
依赖时,它会首先检查 一级缓存 singletonObjects
。由于 UserServiceImpl
尚未完成初始化,容器转而从 二级缓存 earlySingletonObjects
中获取其引用。此时,UserServiceImpl
虽然未完成初始化,但它的引用已经足够让 OrderServiceImpl
完成依赖注入。
java
// 从二级缓存获取 UserServiceImpl 的引用
UserServiceImpl userServiceRef = (UserServiceImpl) earlySingletonObjects.get("UserServiceImpl");
// 将引用注入到 OrderServiceImpl
Field userServiceField = orderService.getClass().getDeclaredField("userService");
userServiceField.setAccessible(true);
userServiceField.set(orderService, userServiceRef);
4.完成 OrderServiceImpl 的初始化
在 OrderServiceImpl
的依赖注入完成后,它会被标记为"完全初始化",并从二级缓存移入 一级缓存 singletonObjects
。此时,OrderServiceImpl
已经可以被其他 Bean 正常使用。
java
// OrderServiceImpl 移入一级缓存
singletonObjects.put("OrderServiceImpl", orderService);
earlySingletonObjects.remove("OrderServiceImpl");
5.完成 UserServiceImpl 的初始化
当 OrderServiceImpl
完成初始化后,容器会重新回到 UserServiceImpl
的依赖注入流程。此时,OrderServiceImpl
已经存在于一级缓存中,容器可以直接获取它的引用并注入到 UserServiceImpl
的 orderService
字段。最终,UserServiceImpl
完成初始化,从二级缓存移入一级缓存。
java
// 从一级缓存获取 OrderServiceImpl 的引用
OrderServiceImpl orderServiceRef = (OrderServiceImpl) singletonObjects.get("OrderServiceImpl");
// 将引用注入到 UserServiceImpl
Field orderServiceField = userService.getClass().getDeclaredField("orderService");
orderServiceField.setAccessible(true);
orderServiceField.set(userService, orderServiceRef);
// UserServiceImpl 移入一级缓存
singletonObjects.put("UserServiceImpl", userService);
earlySingletonObjects.remove("UserServiceImpl");
6.关键点总结
- 二级缓存的桥梁作用:通过临时存储未完成初始化的 Bean,二级缓存充当了循环依赖中的"中间人",使得相互依赖的 Bean 可以交替完成初始化。
- 递归处理机制 :容器通过递归调用
serviceInit
方法,逐步处理未完成的 Bean,直到所有依赖都被解析。 - 线程安全性 :使用
ConcurrentHashMap
确保在多线程环境下缓存的读写安全。
二级缓存的协作边界
二级缓存的本质是通过 提前暴露半成品 Bean 的引用 解决循环依赖,但这一机制高度依赖依赖注入的时机:
- 字段注入与方法注入
依赖注入发生在 Bean 实例化之后,此时半成品 Bean 已存入二级缓存,因此可以解决循环依赖。 - 构造器注入的挑战
构造器注入要求依赖在实例化时完成注入。例如:
java
// UserServiceImpl(构造器注入)
@Service
public class UserServiceImpl implements UserService {
private final OrderService orderService;
@Autowired
public UserServiceImpl(OrderService orderService) {
this.orderService = orderService; // 实例化时必须注入
}
}
- 当容器尝试实例化
UserServiceImpl
时,必须立即获得OrderServiceImpl
的实例。 - 若
OrderServiceImpl
也通过构造器注入依赖UserServiceImpl
,双方都无法提前暴露半成品引用,导致死锁。
这一限制并非缓存设计缺陷,而是由构造器注入的机制决定。实际开发中,可通过优先使用字段注入或代码重构避免此类问题。
通过手动实现 IoC 容器的核心机制,我们揭开了依赖注入与缓存设计的神秘面纱。一级缓存以简洁高效的方式守护着单例 Bean 的生命周期,而二级缓存则化身"破局者",通过提前暴露半成品 Bean 的引用,巧妙化解了循环依赖的死锁困局。若进一步引入三级缓存 ,通过 ObjectFactory
延迟生成代理对象,便可为 AOP 动态代理铺平道路------当 Bean 需要切面增强时,容器能确保依赖注入的是最终代理而非原始对象,从而解决代理滞后导致的逻辑割裂问题。这种分层缓存的协作,不仅是空间换时间的策略,更是对"依赖管理与功能扩展解耦"的深刻实践。未来,通过整合动态代理与注解驱动的切面编程,容器不仅能管理对象生命周期,还能为 Bean 注入行为增强的能力,让代码在控制反转与功能扩展间游刃有余。理解这套底层逻辑,正是深入 Spring 等框架内核的钥匙。愿本文为你打开一扇窗,在框架设计的星辰大海中,找到属于你的航向。若有疑问或灵感,欢迎共探技术之美!