spring bean的实例化
spring bean的实例化、属性注入和初始化都是在doCreateBean方法中完成的。
在doCreateBean方法中,首先会创建bean的实例,负责创建的方法为createBeanInstance:
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// 解析class
Class<?> beanClass = resolveBeanClass(mbd, beanName);
//确保class不为空,并且访问权限为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());
}
//配置的一种特殊的callback回调方法,通过这个callback创建bean
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
//通过工厂方法创建
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// 一个类可能有多个构造器,所以Spring得根据参数个数、类型确定需要调用的构造器
// 在使用构造器创建实例后,Spring会将解析过后确定下来的构造器或工厂方法保存在缓存中,避免再次创建相同bean时再次解析
boolean resolved = false;
boolean autowireNecessary = false;
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
if (mbd.resolvedConstructorOrFactoryMethod != null) {
//已经解析过class的构造器
resolved = true;
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
if (resolved) {
//已经解析过class的构造器,使用已经解析好的构造器
if (autowireNecessary) {
//构造函数自动注入
return autowireConstructor(beanName, mbd, null, null);
}
else {
//使用默认构造器
return instantiateBean(beanName, mbd);
}
}
// 需要根据参数解析、确定构造函数
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
// 解析的构造器不为空 || 注入类型为构造函数自动注入 || bean定义中有构造器参数 || 传入参数不为空
if (ctors != null ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
//构造函数自动注入
return autowireConstructor(beanName, mbd, ctors, args);
}
// 使用默认构造器
return instantiateBean(beanName, mbd);
}
代码逻辑如下:
1.如果bean定义中存在 InstanceSupplier ,会使用这个回调接口创建对象(应该是3.X以后新加的,3.X的源码中没有)
2.根据配置的factoryMethodName或factory-mtehod创建bean
3.解析构造函数并进行实例化
因为一个类可能有多个构造函数,所以需要根据配置文件中配置的参数或者传入的参数确定最终调用的构造函数。因为判断过程会比较消耗性能,所以Spring会将解析、确定好的构造函数缓存到BeanDefinition中的resolvedConstructorOrFactoryMethod字段中。在下次创建相同bean的时候,会直接从RootBeanDefinition中的属性resolvedConstructorOrFactoryMethod缓存的值获取,避免再次解析。
对于实例的创建,Spring分为通用的实例化(默认无参构造函数)和带有参数的实例化。
1、有参数的实例化
下面代码是带有参数情况的实例化。因为需要确定使用的构造函数,所以需要有大量工作花在根据参数个数、类型来确定构造函数上:
public BeanWrapper autowireConstructor(final String beanName, final RootBeanDefinition mbd,
@Nullable Constructor<?>[] chosenCtors, @Nullable final Object[] explicitArgs) {
//实例化BeanWrapper,是包装bean的容器
BeanWrapperImpl bw = new BeanWrapperImpl();
this.beanFactory.initBeanWrapper(bw);
Constructor<?> constructorToUse = null;
ArgumentsHolder argsHolderToUse = null;
Object[] argsToUse = null;
//如果getBean中传入的参数不为空,那么就使用传入的参数
if (explicitArgs != null) {
argsToUse = explicitArgs;
}
//否则就需要解析配置文件中的参数
else {
Object[] argsToResolve = null;
//先尝试从缓存中获取
synchronized (mbd.constructorArgumentLock) {
//缓存中的构造器
constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;
if (constructorToUse != null && mbd.constructorArgumentsResolved) {
// 在缓存中找到了构造器,就继续从缓存中寻找缓存的构造器参数
argsToUse = mbd.resolvedConstructorArguments;
if (argsToUse == null) {
//没有缓存的参数,就需要获取配置文件中配置的参数
argsToResolve = mbd.preparedConstructorArguments;
}
}
}
//如果缓存中没有缓存的参数的话,即argsToResolve不为空,就需要解析配置的参数
if (argsToResolve != null) {
//解析参数类型,比如将配置的String类型转换成int、boolean等类型
argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve);
}
}
//如果没有缓存,就需要从构造函数开始解析
if (constructorToUse == null) {
//是否需要解析构造器
boolean autowiring = (chosenCtors != null ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
ConstructorArgumentValues resolvedValues = null;
int minNrOfArgs;
if (explicitArgs != null) {
//getBean方法传入的参数
minNrOfArgs = explicitArgs.length;
}
else {
//配置文件中的配置的参数
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
//用于承载解析后的构造函数参数的值
resolvedValues = new ConstructorArgumentValues();
//解析配置文件中的参数,并且返回参数个数
minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
}
// 如果传入的构造器数组不为空,就使用传入的构造器参数,否则通过反射获取class中定义的构造器
Constructor<?>[] candidates = chosenCtors;
if (candidates == null) {
Class<?> beanClass = mbd.getBeanClass();
//省略try/catch
//使用public的构造器或者所有构造器
candidates = (mbd.isNonPublicAccessAllowed() ?
beanClass.getDeclaredConstructors() : beanClass.getConstructors());
}
//给构造函数排序,public构造函数优先、参数数量降序排序
AutowireUtils.sortConstructors(candidates);
int minTypeDiffWeight = Integer.MAX_VALUE;
Set<Constructor<?>> ambiguousConstructors = null;
LinkedList<UnsatisfiedDependencyException> causes = null;
for (Constructor<?> candidate : candidates) {
Class<?>[] paramTypes = candidate.getParameterTypes();
if (constructorToUse != null && argsToUse.length > paramTypes.length) {
// Already found greedy constructor that can be satisfied ->
// do not look any further, there are only less greedy constructors left.
break;
}
//如果从bean类中解析到的构造函数参数个数小于从beanDefinition中解析到的构造
//函数参数个数,那么肯定不会使用该方法实例化,循环继续
if (paramTypes.length < minNrOfArgs) {
continue;
}
//封装解析到的参数信息
ArgumentsHolder argsHolder;
if (resolvedValues != null) {
//处理参数在配置文件中的情况
try {
String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length);
if (paramNames == null) {
ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
if (pnd != null) {
paramNames = pnd.getParameterNames(candidate);
}
}
argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,
getUserDeclaredConstructor(candidate), autowiring);
}
//catch
}
else {
// 处理参数由getBean方法传入的情况
if (paramTypes.length != explicitArgs.length) {
continue;
}
argsHolder = new ArgumentsHolder(explicitArgs);
}
//因为不同构造函数的参数个数相同,而且参数类型为父子关系,所以需要找出类型最符合的一个构造函数
//Spring用一种权重的形式来表示类型差异程度,差异权重越小越优先
int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
// 当前构造函数最为匹配的话,清空先前ambiguousConstructors列表
if (typeDiffWeight < minTypeDiffWeight) {
constructorToUse = candidate;
argsHolderToUse = argsHolder;
argsToUse = argsHolder.arguments;
minTypeDiffWeight = typeDiffWeight;
ambiguousConstructors = null;
}
//存在相同权重的构造器,将构造器添加到一个ambiguousConstructors列表变量中
//注意,这时候constructorToUse 指向的仍是第一个匹配的构造函数
else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {
if (ambiguousConstructors == null) {
ambiguousConstructors = new LinkedHashSet<>();
ambiguousConstructors.add(constructorToUse);
}
ambiguousConstructors.add(candidate);
}
}
if (constructorToUse == null) {
//如果没有匹配的构造函数,抛出异常。略
}
else if (ambiguousConstructors != null && !mbd.isLenientConstructorResolution()) {
//如果存在多个构造函数匹配程度相同,并且BeanDefinition中设置isLenientConstructorResolution为false(默认值为true),
//表示构造器创建为严格模式的话,会抛出异常。异常代码略
}
//这一步就是将解析好的构造函数放入缓存resolvedConstructorOrFactoryMethod,如果需要的话也会缓存参数
//并设置constructorArgumentsResolved为true,表示已经解析过构造函数
if (explicitArgs == null) {
argsHolderToUse.storeCache(mbd, constructorToUse);
}
}
//使用策略模式,通过构造函数、参数实例化bean
try {
final InstantiationStrategy strategy = beanFactory.getInstantiationStrategy();
Object beanInstance;
if (System.getSecurityManager() != null) {
final Constructor<?> ctorToUse = constructorToUse;
final Object[] argumentsToUse = argsToUse;
beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
strategy.instantiate(mbd, beanName, beanFactory, ctorToUse, argumentsToUse),
beanFactory.getAccessControlContext());
}
else {
beanInstance = strategy.instantiate(mbd, beanName, this.beanFactory, constructorToUse, argsToUse);
}
bw.setBeanInstance(beanInstance);
return bw;
}
//catch...
}
上面代码非常长,总体的功能逻辑如下:
1.确定参数。
1.如果调用getBean方式时传入的参数不为空,则可以直接使用传入的参数;
2.再尝试从缓存中获取参数
3.否则,需要解析配置<bean>节点时,配置的构造器参数。
2.确定构造函数。根据第一步中确定下来的参数,接下来的任务就是根据参数的个数、类型来确定最终调用的构造函数。首先是根据参数个数匹配,把所有构造函数根据参数个数升序排序,再去筛选参数个数匹配的构造函数;因为配置文件中可以通过参数位置索引,也可以通过参数名称来设定参数值,如<constructor name="title">,所有还需要解析参数的名称:通过注解的方式获取;通过工具类ParameterNameDiscoverer来获取。最后,根据解析好的参数名称、参数类型、实际参数就可以确定构造函数,并且将参数转换成对应的类型
3.根据确定的构造函数转换成对应的参数类型
4.构造函数不确定性的验证。因为有一些构造函数的参数类型为父子关系,所以Spring会做一次验证
5.如果条件符合(传入参数为空),将解析好的构造函数、参数放入缓存
6.根据实例化策略将构造函数、参数实例化bean
实例化策略:
在上面创建bean的最后一步,Spring并没有通过解析好的构造函数和实参来直接创建,而是使用了策略模式,使用策略模式的类InstantiationStrategy 来创建bean。InstantiationStrategy有两个实现类,结构如下:
SimpleInstantiationStrategy:其功能就如同类名一样,只是简单的根据构造函数和参数来创建bean。
CglibSubclassingInstantiationStrategy:在SimpleInstantiationStrategy的基础上,添加了根据Cglib来动态生成子类的功能。
先分析SimpleInstantiationStrategy的实例化方法:
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
final Constructor<?> ctor, @Nullable Object... args) {
//如果不存在 lookup-override或者replace-override属性的话,直接通过构造函数和参数进行实例化
if (!bd.hasMethodOverrides()) {
if (System.getSecurityManager() != null) {
// use own privileged to change accessibility (when security is on)
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
ReflectionUtils.makeAccessible(ctor);
return null;
});
}
return (args != null ? BeanUtils.instantiateClass(ctor, args) : BeanUtils.instantiateClass(ctor));
}
else {
//因为使用了lookup-override或者replace-override功能的话,就需要通过动态代理来创建bean
return instantiateWithMethodInjection(bd, beanName, owner, ctor, args);
}
}
a、反射方式创建
BeanUtils创建bean源码:
public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
Assert.notNull(ctor, "Constructor must not be null");
try {
ReflectionUtils.makeAccessible(ctor);
return (KotlinDetector.isKotlinType(ctor.getDeclaringClass()) ?
KotlinDelegate.instantiateClass(ctor, args) : ctor.newInstance(args));
}
catch (InstantiationException ex) {
throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex);
}
catch (IllegalAccessException ex) {
throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex);
}
catch (IllegalArgumentException ex) {
throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex);
}
catch (InvocationTargetException ex) {
throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException());
}
}
代码中,先判断传入的构造函数是否是Kotlin的构造函数,如果不是,直接使用反射来创建bean。
b、动态代理方式
SimpleInstantiationStrategy中instantiateWithMethodInjection方法实现:
protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName,
BeanFactory owner, @Nullable Constructor<?> ctor, @Nullable Object... args) {
throw new UnsupportedOperationException("Method Injection not supported in SimpleInstantiationStrategy");
}
就如上面说的那样,SimpleInstantiationStrategy只支持简单地通过反射创建,没有动态代理的功能,所以其功能就交由了其子类CglibSubclassingInstantiationStrategy通过Cglib来实现:
protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
@Nullable Constructor<?> ctor, @Nullable Object... args) {
// Must generate CGLIB subclass...
return new CglibSubclassCreator(bd, owner).instantiate(ctor, args);
}
public Object instantiate(@Nullable Constructor<?> ctor, @Nullable Object... args) {
Class<?> subclass = createEnhancedSubclass(this.beanDefinition);
Object instance;
if (ctor == null) {
instance = BeanUtils.instantiateClass(subclass);
}
else {
try {
Constructor<?> enhancedSubclassConstructor = subclass.getConstructor(ctor.getParameterTypes());
instance = enhancedSubclassConstructor.newInstance(args);
}
catch (Exception ex) {
throw new BeanInstantiationException(this.beanDefinition.getBeanClass(),
"Failed to invoke constructor for CGLIB enhanced subclass [" + subclass.getName() + "]", ex);
}
}
// LookupOverride和ReplaceOverride属性在这里完成代理
Factory factory = (Factory) instance;
factory.setCallbacks(new Callback[] {NoOp.INSTANCE,
new LookupOverrideMethodInterceptor(this.beanDefinition, this.owner),
new ReplaceOverrideMethodInterceptor(this.beanDefinition, this.owner)});
return instance;
}
2、无参数的实例化
下面介绍没有参数时,Spring创建bean的方式:
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
try {
Object beanInstance;
final BeanFactory parent = this;
if (System.getSecurityManager() != null) {
beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
getInstantiationStrategy().instantiate(mbd, beanName, parent),
getAccessControlContext());
}
else {
//和带参数一样,使用特定的策略来实例化bean
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
}
BeanWrapper bw = new BeanWrapperImpl(beanInstance);
initBeanWrapper(bw);
return bw;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
}
}
最重要的代码就是下面这行:
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
与带有参数创建bean一样,都是使用InstantiationStrategy来创建bean,但是因为没有参数,所以也就没有必要执行繁琐的确定构造函数的代码,只需要使用无参构造器进行实例化就行了。
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
// 如果没有需要覆盖的方法,通过反射直接创建
if (!bd.hasMethodOverrides()) {
Constructor<?> constructorToUse;
synchronized (bd.constructorArgumentLock) {
//先尝试从缓存中获取构造函数
constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
if (constructorToUse == null) {
final Class<?> clazz = bd.getBeanClass();
//如果需要实例化的类是接口,则抛出异常
if (clazz.isInterface()) {
throw new BeanInstantiationException(clazz, "Specified class is an interface");
}
try {
if (System.getSecurityManager() != null) {
constructorToUse = AccessController.doPrivileged(
(PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
}
else {
//直接通过反射获取无参构造函数
constructorToUse = clazz.getDeclaredConstructor();
}
//将构造函数缓存起来
bd.resolvedConstructorOrFactoryMethod = constructorToUse;
}
catch (Throwable ex) {
throw new BeanInstantiationException(clazz, "No default constructor found", ex);
}
}
}
//实例化bean,源码已经在前面介绍带有参数实例化bean时贴出
return BeanUtils.instantiateClass(constructorToUse);
}
else {
// 使用动态代理覆盖方法,已经介绍过了
return instantiateWithMethodInjection(bd, beanName, owner);
}
}
至此,终于完成了bean的创建。