title: Spring 框架源码解读4
date: 2020/04/16 13:56
本节内容 & 思考题
Spring 创建对象的几种方式?
1、空参构造(@Component)
<bean id="apple" class="cn.x5456.Apple" />
2、静态工厂方法(了解)
<bean id="apple" class="cn.x5456.Apple" factory-method="createApple" />
public Apple createApple() {
return new Apple();
}
3、实例工厂(@Bean)
<bean name="appleFactory" class="cn.x5456.AppleFactory" />
<bean id="apple" factory-bean="appleFactory" factory-method="createApple" />
本节将会介绍第一种和第三种配置的实现方式(不会介绍注解实现)
注:本教程暂不考虑有参构造(包括自动注入的有参构造),因为其实都是差不多的。
装饰者模式:BeanWrapper
策略模式:实例化对象的方式
新增工厂方法创建对象
1、BD 新增字段
// 工厂类注册到容器中的 beanName
private String factoryBean;
// 工厂方法名
private String factoryMethod;
2、修改 ABF
/**
* 根据 bd 创建对象
* <p>
* 1)创建bean 日后需要对有参构造进行扩展
* 2)注入属性 日后新增
* 3)执行初始化操作
* 4)注册销毁的处理
*/
private Object createBean(BeanDefinition beanDefinition) {
// 1、创建 bean
Object bean = this.createBeanInstance(beanDefinition);
// 2、注入属性 todo
// 3、执行初始化操作(在 Spring 中是直接调用的该类中的 initializeBean 方法,为了让他面向对象一点,我给他抽出一个类)
InitializeBeanAdapter initializeBeanAdapter = new InitializeBeanAdapter(bean, beanDefinition);
initializeBeanAdapter.afterPropertiesSet();
// 4、注册销毁的处理
if (this.check(beanDefinition, bean)) {
registry.registerDisposableBean(beanDefinition.getName(), new DisposableBeanAdapter(bean, beanDefinition));
}
return bean;
}
/**
* 分两种情况
* <p>
* 1. 工厂方法(无参版)
* 2. 空参构造
*/
private Object createBeanInstance(BeanDefinition beanDefinition) {
if (ObjectUtil.isNotNull(beanDefinition.getFactoryBean())) {
// 从容器中找到工厂对象
Object bean = this.getBean(beanDefinition.getFactoryBean());
if (ObjectUtil.isNull(bean)) {
throw new RuntimeException("工厂 bean 不存在!");
}
return ReflectUtil.invoke(bean, beanDefinition.getFactoryMethod());
}
return ReflectUtil.newInstance(beanDefinition.getClassName());
}
3、测试
public class TestJsonBF {
public static void main(String[] args) {
ListableBeanFactory bf = new JsonBeanFactoryImpl("/Users/x5456/IdeaProjects/Summer/src/test/resources/apple.json");
Apple apple = bf.getBean("apple", Apple.class);
System.out.println(apple);
}
}
apple.json
[
{
"name": "appleFactory",
"className": "cn.x5456.summer.AppleFactory"
},
{
"name": "apple",
"factoryBean": "appleFactory",
"factoryMethod": "createApple"
}
]
public class AppleFactory {
public Apple createApple() {
Apple apple = new Apple();
apple.setName("黄元帅");
return apple;
}
}
思考:配置文件中把 factory 放到 bean 的后面会不会报错吗?
不会,因为 BF 先把所有的 BD 读到 BDMap 中,然后 AP 再一个一个 get,不管先后顺序,总能获取到对象;这也是 BF 懒加载的好处。
Spring 0.9
Spring 0.9 只有根据构造创建的,所以没有参考 0.9 版本
Spring 5.0
创建 Bean 部分代码
// AbstractAutowireCapableBeanFactory.java
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// Make sure bean class is actually resolved at this point.
Class<?> beanClass = resolveBeanClass(mbd, beanName);
// 判断一个类的访问权限, Spring默认情况下对于非public的类是不允许访问的
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
}
// 不重要,跳过
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
// 这里是处理工厂方法的,比如你的类里面设置了一个工厂方法返回一个对象,比如:
// @Bean
// public static Object query() {
// return new Ant();
// }
// xml配置如下:
// <bean id="user" class="com.ant.context.service.UserService" factory-method="query">
//
// </bean>
// 那么这个query方法就会在这里处理,这里spring就会给你构建一个新的对象Ant,然后放到实例容器中去
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// 重新创建同一个bean时的快捷方式(Shortcut)...
boolean resolved = false;
boolean autowireNecessary = false;
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
if (mbd.resolvedConstructorOrFactoryMethod != null) {
// 如果已经解析了构造方法的参数,则直接把这个属性设置为true
// 则后面的if判断方法则会直接进入,而不会去执行后续的方法
resolved = true;
// 如果已经解析了构造方法参数, 则必须要通过一个带参构造方法来实例
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
// 判断是否已经解析过了构造函数
if (resolved) {
if (autowireNecessary) {
// 通过构造方法自动装配的方式构造 bean 对象
return autowireConstructor(beanName, mbd, null, null);
}
else {
// 通过默认的无参构造方法进行
return instantiateBean(beanName, mbd);
}
}
// 这个方法比较重要,spring通过判断我们的bean对象的构造方法的数量和结构,
// 来判断我们在实例化对象的时候,到底要使用哪个构造函数去对我们的bean进行实例化
// 如果我们的bean只有一个默认的无参构造方法,则会返回null
// Candidate constructors for autowiring?
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
// 如果我们的bean自己有一个特殊的构造方法,则会执行这个方法,这个方法比较复杂,也比较重要
return autowireConstructor(beanName, mbd, ctors, args);
}
// 如果bean只有一个默认的无参构造方法,则使用下面的方法去实例化我们的bean对象
// No special handling: simply use no-arg constructor.
return instantiateBean(beanName, mbd);
}
1)工厂方法方式
- 从工厂类中找到用户配置的那个方法
- 找到那个方法需要依赖注入的参数
- 如果没找到工厂方法则抛出异常,检查返回值是不是 void
- 和下面一样,选个策略创建对象
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean name="appleFactory" class="com.dist.ars.aop.AppleFactory" />
<bean id="apple" factory-bean="appleFactory" factory-method="createApple">
<constructor-arg ref="seed" />
</bean>
<bean name="seed" class="com.dist.ars.aop.Seed" />
</beans>
2)空参构造方式
这就是创建对象的流程,再往下就是 DI 了,也是使用 BeanWrapper 的目的。