背景是,GPT4o给我提了一个问题:ApplicationContext是如何创建Bean的?
测试代码
package com.wiring;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.stereotype.Component;
@Component
class SimpleBean {
public SimpleBean() {
System.out.println("1. SimpleBean 构造函数被调用");
}
@PostConstruct
public void init() {
System.out.println("2. SimpleBean 初始化方法被调用");
}
@PreDestroy
public void destroy() {
System.out.println("3. SimpleBean 销毁方法被调用");
}
}
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext("com.wiring");
//反射构造
SimpleBean bean = context.getBean(SimpleBean.class);
context.close();
}
}
现在主要想研究这句话
SimpleBean bean = context.getBean(SimpleBean.class);
详细解释 Spring 创建 Bean 实例的完整调用链:
1. getBean() - Spring 入口
// AbstractBeanFactory
public Object getBean(String name) throws BeansException {
// 获取 bean,如果不存在则创建
return doGetBean(name, null, null, false);
}
2. createBeanInstance() - 开始创建实例
// AbstractAutowireCapableBeanFactory
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
// 通过反射获取构造函数并创建实例
Constructor<?> constructorToUse = getConstructorToUse(beanName, mbd);
return instantiateBean(beanName, mbd);
}
3. Constructor.newInstance() - Java反射API
@CallerSensitive
@ForceInline
public T newInstance(Object... initargs) {
// 获取调用者并执行实例化
Class<?> caller = override ? null : Reflection.getCallerClass();
return newInstanceWithCaller(initargs, !override, caller);
}
4. newInstanceWithCaller() - 权限检查和访问器获取
private T newInstanceWithCaller(Object[] args, boolean checkAccess, Class<?> caller) {
// 检查访问权限
if (checkAccess) checkAccess(caller, clazz, clazz, modifiers);
// 获取构造函数访问器
ConstructorAccessor ca = constructorAccessor;
if (ca == null) {
ca = acquireConstructorAccessor();
}
// 创建实例
return (T) ca.newInstance(args);
}
5. ConstructorAccessor.newInstance() - 实例创建准备
// DirectConstructorHandleAccessor
public Object newInstance(Object[] args) throws InstantiationException {
// 检查参数
if (args != null && args.length != paramCount) {
throw new IllegalArgumentException("参数个数不匹配");
}
// 调用实际的构造函数
return invokeImpl(args);
}
6. invokeImpl() - 最终的实例创建
@Hidden
@ForceInline
Object invokeImpl(Object[] args) throws Throwable {
return switch (paramCount) {
case 0 -> target.invokeExact(); // 无参构造
case 1 -> target.invokeExact(args[0]); // 单参数构造
case 2 -> target.invokeExact(args[0], args[1]);
case 3 -> target.invokeExact(args[0], args[1], args[2]);
default -> target.invokeExact(args);
};
}
总结
从技术上讲,最终创建对象实例的是 invokeExact(args)
这个调用。其他所有的步骤都是为了确保这个调用能够正确、安全、并且在正确的上下文中发生。
Spring 容器的管理(
getBean()
):这一步骤是 Spring 容器的入口,它负责检查缓存、解析 Bean 定义、处理作用域和依赖注入等。这些操作确保了 Bean 的创建是在正确的上下文中进行的,例如,如果 Bean 是单例的,那么它只会被创建一次。实例创建策略(
createBeanInstance()
):这一步骤根据 Bean 定义来决定如何创建 Bean 实例。它会解析构造函数、处理依赖注入、处理代理逻辑等。这些操作确保了 Bean 的创建符合 Spring 的依赖注入和 AOP 功能。反射调用(
Constructor.newInstance()
):这一步骤是 Java 反射 API 的一部分,它负责动态调用构造函数。这一步骤确保了构造函数的调用是动态的,可以处理不同的参数和异常。权限检查(
newInstanceWithCaller()
):这一步骤检查访问权限,确保调用者有权限访问目标类的构造函数。这一步骤确保了代码的安全性。参数处理(
ConstructorAccessor.newInstance()
):这一步骤检查参数,确保传入的参数与构造函数的参数匹配。这一步骤确保了参数的正确性。最终创建(
invokeExact()
):这一步骤是最终的实例化操作,它调用目标类的构造函数。这一步骤是真正创建对象实例的地方。
Top comments (0)