title: 04.实例化Bean
tag: 笔记 手写SSM IOC
读取信息后根据信息去创建Bean。
分析
在注册了所有的BeanDefination
之后,我们就可以进行Bean的实例创建了。
在学习Spring的过程中我们学习到,通常依赖注入的方式有三种:
- 构造方法注入
Setter
方法注入- 字段注入(不推荐)
除了以上三种之外,我们还有一种方式:
- 在
FactoryMethod
工厂方法注入。
@Configuration
public class AppConfig {
@Bean
Hello hello(@Autowired JdbcTemplate jdbcTemplate) {
return new Hello(jdbcTemplate);
}
}
我们可以根据实例化Bean和注入Bean的时机来将这四种种注入分为两种
- Bean的创建与注入是一体的,我们无法拆分。
- 构造方法注入
- 工厂方法注入
这种方式我们通过调用方法来实例化Bean,在Bean被实例化时,同时也被初始化了。
- Bean的创建与注入可以分开
- Setter方法注入
- 属性注入
这种方式我们可以在Bean实例化后再通过反射调用方法或者字段来完成注入。
循环依赖
然后我们可以分析循环依赖问题,循环依赖问题就是A、B互相依赖,或者A依赖B,B依赖C,C依赖A,形成了一个闭环。
循环依赖也可以分为两种:
- 属性必须通过构造方法初始化
class A {
final B b;
A(B b) { this.b = b; }
}
class B {
final A a;
B(A a) { this.a = a; }
}
这种方式在Java中是不能通过编译器编译的。因此我们把这样的依赖称为强依赖,之前构造方法注入和工厂方法注入的依赖就属于此类,这样的循环依赖我们只能报错。
- 属性不必在初始化阶段赋值
class A {
B b;
}
class B {
A a;
}
这样的依赖我们称为弱依赖,之前的Setter方法和注入属性注入就属于此类。
这样的循环依赖我们可以先实例化Bean,再注入依赖。
// 第一步,实例化:
A a = new A();
B b = new B();
// 第二步,注入:
a.b = b;
b.a = a;
因此,对于IoC容器来说,创建Bean的过程分两步:
- 创建Bean的实例,此时必须注入强依赖;
- 对Bean实例进行Setter方法注入和字段注入。
第一步如果遇到循环依赖则直接报错,第二步则不需要关心有没有循环依赖。
实例化Bean
有了上面的基础后,我们就可以开始进行Bean的实例化了。
因为实例化阶段是在获取BeanDefiniation之后,因此我们的入口类如下设计:
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
super();
this.reader = new AnnotatedBeanDefinitionReader(this);
register(componentClasses);//注册BeanDefiniation并读取配置文件
createBean();//实例化Bean
.....
}
这样我们可以在后面需要扩展时只需要在下面继续调用方法即可,并且方便用户使用,只需要传入一个注解配置类即可启动容器。
现在我们只需要实现这个createBean()
方法的逻辑即可。
逻辑实现
我们在这个阶段需要检测循环依赖,我们可以定义一个Set<String>
跟踪当前正在创建的所有Bean的名称,并在创建Bean的方法开始使用下面的代码检测循环依赖:
if (!this.creatingBeanNames.add(def.getName())) {
// 检测到重复创建Bean导致的循环依赖:
throw new UnsatisfiedDependencyException();
}
由于@Configuration
标识的Bean实际上是工厂,它们必须先实例化,才能实例化其他普通Bean,所以我们先把@Configuration
标识的Bean创建出来,再创建普通Bean:
protected void createBean(){
createConfigurationBean();
createCommonBean();
}
private void createConfigurationBean(){
beans.values()
.stream()
.filter(this::isConfigurationDefinition)
.sorted()
.forEach(this::createBeanAsEarlySingleton);
}
private void createCommonBean(){
List<BeanDefinition> beanDefinitions = beans.values()
.stream()
.filter(beanDefinition -> beanDefinition.getInstance() == null)
.toList();
beanDefinitions.forEach(beanDefinition -> {
if(beanDefinition.getInstance() == null) createBeanAsEarlySingleton(beanDefinition);
});
}
接下来需要实现的就是createBeanAsEarlySingleton
了:
/**
* 向BeanDefinition中插入实例化后的对象
* @param definition Bean定义信息
*/
@Override
protected Object createBeanAsEarlySingleton(BeanDefinition definition) {
logger.atDebug().log("Try create bean '{}' as early singleton: {}",
definition.getName(), definition.getBeanClass().getName());
//循环依赖报错
if(!creatingBeanNames.add(definition.getName())){
throw new UnsatisfiedDependencyException(
String.format("Circular dependency detected when create bean '%s'", definition.getName()));
}
Executable createFun = definition.getFactoryName() == null ?
definition.getConstructor() : definition.getFactoryMethod();
assert createFun != null;
Parameter[] parameters = createFun.getParameters();//拿到参数
Annotation[][] annotations = createFun.getParameterAnnotations();//拿到参数的注解
Object[] args = new Object[parameters.length];//为参数注入值
for(int i = 0; i < args.length; i++){
Parameter curParameter = parameters[i];
Annotation[] curParameterAnnotations = annotations[i];
Value value = ClassUtils.getAnnotation(curParameterAnnotations, Value.class);
Autowired autowired = ClassUtils.getAnnotation(curParameterAnnotations, Autowired.class);
// @Configuration类型的Bean是工厂,不允许使用@Autowired创建:
final boolean isConfiguration = isConfigurationDefinition(definition);
if (isConfiguration && autowired != null) {
throw new BeanCreationException(
String.format("Cannot specify @Autowired when create @Configuration bean '%s': %s."
, definition.getName(), definition.getBeanClass().getName()));
}
// 参数需要@Value或@Autowired两者之一:
if (value != null && autowired != null) {
throw new BeanCreationException(
String.format("Cannot specify both @Autowired and @Value when create bean '%s': %s."
, definition.getName(), definition.getBeanClass().getName()));
}
if (value == null && autowired == null) {
throw new BeanCreationException(
String.format("Must specify @Autowired or @Value when create bean '%s': %s.",
definition.getName(), definition.getBeanClass().getName()));
}
final Class<?> type = curParameter.getType();
if(value != null){
args[i] = propertyResolver.getProperty(value.value(),type);
}else{
String dependencyName = autowired.name();
boolean required = autowired.value();
BeanDefinition dependencyDefinition = dependencyName.isEmpty() ?
findBeanDefinition(type) : findBeanDefinition(dependencyName, type);
if(required && dependencyDefinition == null){
throw new BeanCreationException(String.format("Missing autowired bean with type '%s' when create bean '%s': %s.", type.getName(),
definition.getName(), definition.getBeanClass().getName()));
}
if(dependencyDefinition != null){
Object dependencyInstance = dependencyDefinition.getInstance();
if(dependencyInstance == null){
dependencyInstance = createBeanAsEarlySingleton(dependencyDefinition);
}
args[i] = dependencyInstance;
}else{
args[i] =null;
}
}
}
Object instance = null;
if(definition.getFactoryName() == null){
try {
instance = definition.getConstructor().newInstance(args);
} catch (Exception e) {
throw new BeanCreationException(String.format("Exception when create bean '%s': %s",
definition.getName(), definition.getBeanClass().getName()), e);
}
}else{
Object bean = getBean(definition.getFactoryName());
try {
instance = definition.getFactoryMethod().invoke(bean,args);
}catch (Exception e){
throw new BeanCreationException(String.format("Exception when create bean '%s': %s",
definition.getName(), definition.getBeanClass().getName()), e);
}
}
definition.setInstance(instance);
return instance;
}
上面的代码虽然很长,但主要逻辑就是:
- 检测循环依赖
- 通过构造函数的参数列表获取到对应注入的值,如果有依赖Bean则递归拿到依赖。
- 拿到注入的值之后调用工厂方法或者构造方法拿到实例。
注意:
这里的递归调用:
public Object createBeanAsEarlySingleton(BeanDefinition def) {
...
Object[] args = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
...
// 获取依赖Bean的实例:
Object autowiredBeanInstance = dependsOnDef.getInstance();
if (autowiredBeanInstance == null && !isConfiguration) {
// 当前依赖Bean尚未初始化,递归调用初始化该依赖Bean:
autowiredBeanInstance = createBeanAsEarlySingleton(dependsOnDef);
}
...
}
...
}
依赖注入过程
假设如下的Bean依赖:
@Component
class A {
// 依赖B,C:
A(@Autowired B, @Autowired C) {}
}
@Component
class B {
// 依赖C:
B(@Autowired C) {}
}
@Component
class C {
// 无依赖:
C() {}
}
如果按照A、B、C的顺序创建Bean实例,那么系统流程如下:
- 准备创建A;
- 检测到依赖B:未就绪;
- 准备创建B:
- 检测到依赖C:未就绪;
- 准备创建C;
- 完成创建C;
- 完成创建B;
- 检测到依赖C,已就绪;
- 完成创建A。
如果按照B、C、A的顺序创建Bean实例,那么系统流程如下:
- 准备创建B;
- 检测到依赖C:未就绪;
- 准备创建C;
- 完成创建C;
- 完成创建B;
- 准备创建A;
- 检测到依赖B,已就绪;
- 检测到依赖C,已就绪;
- 完成创建A。
可见无论以什么顺序创建,C总是最先被实例化,A总是最后被实例化。