写在前面
原本计划写一篇从启动代码开始,逐行分析Spring Boot整个启动过程的文章。写完第一部分发现这样做并不现实,而且也不合理,且成品对读者也不友好。最后觉得,还是应该拆开,从不同部分去解读Spring这个框架。于是便有了该系列文章。
该系列文章会均以源码为基础,一起来探索Spring这个框架(以Spring Boot2的方式)。
该系列每篇文章都会带着一个疑问去看代码。本文的问题是:Spring是如何创建bean的?在什么时候创建?原型和单例的bean的创建有何不同?Spring中bean的生命周期如何?
准备
本文基于Spring boot2.2.1.RELEASE。
准备一个Person类
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
//省略getter setter方法
}
一个Boy类,含有一个Person字段girlFriend,使用注解注册该类实例到容器中。
@Component
public class Boy extends Person{
private Person girlFriend;
//该对象依赖一个person实例,使用构造器注入
@Autowired
public Boy(@Qualifier("someonesGirlFriend") Person girlFriend) {
this.girlFriend = girlFriend;
}
public Boy(String name, int age) {
super(name, age);
}
//省略getter setter方法
}
一个配置类,使用注解注册,一个为原型的badMan,一个单例女朋友(暗示女朋友只有一个,坏男人千千万万)
@Configuration
public class CommonConfig {
@Bean(value = "badMan")
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public Person man(){
return new Person();
}
@Bean("someonesGirlFriend")
public Person getXmm(){
return new Person("liLi",20);
}
}
启动类代码:
@SpringBootApplication
public class NaocosDiscoveryApplication {
public static void main(String[] args) {
ConfigurableApplicationContext run = SpringApplication.run(NaocosDiscoveryApplication.class, args);
Person boy = run.getBean("boy", Person.class);
System.out.println(boy.getName());
System.out.println(boy.getAge());
Person badMan = run.getBean("badMan", Person.class);
System.out.println(badMan.getName());
}
}
什么时候创建bean?
这里说的bean是指我们平时使用@Service、@Component、@Controller()注解注册的bean。
这边有个技巧就是在org.springframework.beans.factory.BeanFactory接口的getBean(…)这几个方法上打上断点,debug的时候就一目了然。
为了节省时间,大家请在org.springframework.context.support.AbstractApplicationContext的550行finishBeanFactoryInitialization(beanFactory);
处打上断点,该处是实例化我们注册bean的核心入口。
进入该方法,看到核心方法
// Instantiate all remaining (non-lazy-init) singletons.
beanFactory.preInstantiateSingletons();
注释已经告诉大家了,这个方法的作用就是Instantiate all remaining (non-lazy-init) singletons.(细心的人会发现前面是会实例化一些bean,但不是本文关注的重点)
通过调用栈我们可以看到,创建bean的时机为:
创建bean的过程解析
进入preInstantiateSingletons()方法
@Override
public void preInstantiateSingletons() throws BeansException {
if (logger.isTraceEnabled()) {
logger.trace("Pre-instantiating singletons in " + this);
}
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
//获取需要创建的beanName列表
//你会发现我们想要创建beanName都在
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
//这个方法有兴趣可以进去看,可以当做黑盒处理,获取bean的BeanDefinition信息
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
//判断是否不为抽象
//单例
//非懒加载
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
//判断这个bean是不是FactoryBean
//是的话走使用FactoryBean创建对象
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
final FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.do