本次主要想写spring bean的实例化相关的内容。建立spring bean 实例是spring bean 生命周期的第一阶段。bean 的生命周期主要有以下几个步骤:面试
在实例化bean以前在BeanDefinition里头已经有了全部须要实例化时用到的元数据,接下来spring 只须要选择合适的实例化方法以及策略便可。实例化方法有两大类分别是工厂方法和构造方法实例化,后者是最多见的。spring默认的实例化方法就是无参构造函数实例化。
如咱们在xml里定义的 <bean id="xxx" class="yyy"/>
以及用注解标识的bean都是经过默认实例化方法实例化的。spring
使用适当的实例化方法为指定的bean建立新实例:工厂方法,构造函数实例化。缓存
代码演示bash
启动容器时会实例化全部注册的bean(lazy-init懒加载的bean除外),对于全部单例非懒加载的bean来讲当从容器里获取bean(getBean(String name))的时候不会触发,实例化阶段,而是直接从缓存获取已准备好的bean,而生成bean的时机则是下面这行代码运行时触发的。更多关于懒加载的内容能够参考这篇文章。
Spring lazy-init 原理分析app
@Test
public void testBeanInstance(){
// 启动容器
ApplicationContext context = new ClassPathXmlApplicationContext("spring-beans.xml");
}
复制代码
public class FactoryInstance {
public FactoryInstance() {
System.out.println("instance by FactoryInstance");
}
}
复制代码
public class MyBeanFactory {
public static FactoryInstance getInstanceStatic(){
return new FactoryInstance();
}
}
复制代码
<?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 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="factoryInstance" class="spring.service.instance.MyBeanFactory"
factory-method="getInstanceStatic"/>
</beans>
复制代码
输出结果为:ide
instance by FactoryInstance函数
public class MyBeanFactory {
/**
* 实例工厂建立bean实例
*
* @return
*/
public FactoryInstance getInstance() {
return new FactoryInstance();
}
}
复制代码
<?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 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 工厂实例 -- >
<bean id="myBeanFactory" class="MyBeanFactory"/>
<bean id="factoryInstance" factory-bean="myBeanFactory" factory-method="getInstance"/>
</beans>
复制代码
输出结果为:源码分析
instance by FactoryInstancepost
public class ConstructorInstance {
public ConstructorInstance() {
System.out.println("ConstructorInstance none args");
}
}
复制代码
<?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 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="constructorInstance" class="spring.service.instance.ConstructorInstance"/>
</beans>
复制代码
输出结果为:ui
ConstructorInstance none args
public class ConstructorInstance {
private String name;
public ConstructorInstance(String name) {
System.out.println("ConstructorInstance with args");
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
复制代码
<?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 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="constructorInstance" class="spring.service.instance.ConstructorInstance">
<constructor-arg index="0" name="name" value="test constructor with args"/>
</bean>
</beans>
复制代码
输出结果为:
ConstructorInstance with args
下面这段是 有关spring bean生命周期的代码,也是咱们本次要讨论的bean 实例化的入口。
doCreateBean方法具体实如今AbstractAutowireCapableBeanFactory类,感兴趣的朋友能够进去看看调用链。
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
//第一步 建立bean实例 还未进行属性填充和各类特性的初始化
BeanWrapper instanceWrapper = null;
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
Object exposedObject = bean;
try {
// 第二步 进行属性填充(依赖注入)
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
// 第三步 执行bean的初始化方法
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
}catch (Throwable ex) {
// 抛相应的异常
}
// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
复制代码
咱们这里只需关注第一步建立bean实例的流程便可
instanceWrapper = createBeanInstance(beanName, mbd, args);
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
// Make sure bean class is actually resolved at this point.
Class<?> beanClass = resolveBeanClass(mbd, beanName);
// 使用工厂方法进行实例化
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// Need to determine the constructor...
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
// 使用带参构造函数初始化
if (ctors != null ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}
// 默认实例化方式 无参构造实例化
return instantiateBean(beanName, mbd);
}
复制代码
上面代码就是spring 实现bean实例建立的核心代码。这一步主要根据BeanDefinition里的元数据定义决定使用哪一种实例化方法,主要有下面三种:
工厂方法的实例化手段没有选择策略直接用了发射实现的
实例化策略都是对于构造函数实例化而言的
上面说到的两构造函数实例化方法无论是哪种都会选一个实例化策略进行,到底选哪种策略也是根据BeanDefinition里的定义决定的。
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
复制代码
上面这一行代码就是选择实例化策略的代码,进入到上面两种方法的实现以后发现都有这段代码。
下面选一个instantiateBean的实现来介绍
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
try {
Object beanInstance;
final BeanFactory parent = this;
if (System.getSecurityManager() != null) {
beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
return getInstantiationStrategy().instantiate(mbd, beanName, parent);
}
}, getAccessControlContext());
}
else {
// 在这里选择一种策略进行实例化
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);
}
}
复制代码
选择使用反射仍是cglib
先判断若是beanDefinition.getMethodOverrides()为空也就是用户没有使用replace或者lookup的配置方法,那么直接使用反射的方式,简单快捷,可是若是使用了这两个特性,在直接使用反射的方式建立实例就不妥了,由于须要将这两个配置提供的功能切入进去,因此就必需要使用动态代理的方式将包含两个特性所对应的逻辑的拦截加强器设置进去,这样才能够保证在调用方法的时候会被相应的拦截器加强,返回值为包含拦截器的代理实例。---引用自《spring 源码深度剖析》这本书
<bean id="constructorInstance" class="spring.service.instance.ConstructorInstance" >
<lookup-method name="getName" bean="xxx"/>
<replaced-method name="getName" replacer="yyy"/>
</bean>
复制代码
若是使用了lookup或者replaced的配置的话会使用cglib,不然直接使用反射。
具体lookup-method和replaced-method的用法能够查阅相关资料。
public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) {
// Don't override the class with CGLIB if no overrides. if (bd.getMethodOverrides().isEmpty()) { constructorToUse = clazz.getDeclaredConstructor((Class[]) null); return BeanUtils.instantiateClass(constructorToUse); }else { // Must generate CGLIB subclass. return instantiateWithMethodInjection(bd, beanName, owner); } } 复制代码
因为篇幅省略了部分代码
其余文章
【Spring面试题】Spring 为啥默认把bean设计成单例的?