Spring source code learning 15: finishbeanfactoryinitialization (key)

Programmer Xiaohang 2021-01-21 19:59:03
spring source code learning finishbeanfactoryinitialization


Preface

It can be said that all the work ahead is preparatory work , And the next thing to start is the point , It will be done in this step BeanFactory The initialization , Instantiate singletons at the same time Bean.

How to operate it , Let's read the source code together !

But before you read the source code , Still need to know some knowledge .

  1. What is? FactoryBean ?
  2. FactoryBean How it is used ?
  3. Bean How to initialize ?
  4. How to solve the problem of circular dependence ?

What is? FactoryBean ?

This article on the official website 《What's a FactoryBean?》[1] There are relevant answers in , Interested friends can have a look at .

Interfaces implemented by internally used objects , These objects BeanFactory The factory itself is a single object . If bean Implement this interface , Then it will be used as the factory for object exposure , Instead of being used directly to make itself public bean example .

Be careful : The bean Can't be used as ordinary bean. FactoryBean With bean Style definition , But for bean quote (getObject()) The exposed object is always the object it creates .

FactoryBeans Can support singletons and prototypes , And you can delay the creation of objects on demand , You can also create objects at startup .

When life is one FactoryBean when , There will be two types Bean, Namely FactoryBean In itself , And the type it needs to create Bean.

Here is an example of how to use :

Use

1. PaidComponent

public class PaidComponent {
public PaidComponent() {
System.out.println("PaidComponent Parameterless construction is called ");
}
}

2. PaidComponentFactoryBean

@Component
public class PaidComponentFactoryBean implements FactoryBean<PaidComponent> {
@Override
public PaidComponent getObject() throws Exception {
System.out.println("PaidComponentFactoryBean Of getObject Method is called ");
return new PaidComponent();
}
@Override
public Class<?> getObjectType() {
return PaidComponent.class;
}
}

3 Test

public class AnnotationConfigApplicationTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(JavaConfig.class);
context.refresh();
System.out.println(context.getBean("paidComponentFactoryBean"));
System.out.println(context.getBean("&paidComponentFactoryBean"));
System.out.println(context.getBean(PaidComponent.class));
}
}

You can see that there are two Bean, One is paidComponentFactoryBean , The other is &paidComponentFactoryBean.

And direct access paidComponentFactoryBean What we get is FactoryBean Of getObject() Method return type .

finishBeanFactoryInitialization Source code

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// Initialize conversion service for this context.
// Initialize type converter
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}
// Register a default embedded value resolver if no bean post-processor
// (such as a PropertyPlaceholderConfigurer bean) registered any before:
// at this point, primarily for resolution in annotation attribute values.
// It is mainly used for parsing annotation attribute values
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
}
// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
// Initialize as early as possible LoadTimeWeaverAware Bean, In order to register its converter as soon as possible .
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}
// Stop using the temporary ClassLoader for type matching.
// Stop using temporary ClassLoader Type matching .
beanFactory.setTempClassLoader(null);
// Allow for caching all bean definition metadata, not expecting further changes.
// Set up beanDefinition Metadata It can't be modified any more
beanFactory.freezeConfiguration();
// Instantiate all remaining (non-lazy-init) singletons.
// Instantiate a single instance bean
beanFactory.preInstantiateSingletons();
}

Focus here on the last line

beanFactory.preInstantiateSingletons();

preInstantiateSingletons

This one goes into classes DefaultListableBeanFactory Class source code .

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.
// take beanDefinitionNames Put it in the set
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...
// Traverse
for (String beanName : beanNames) {
// obtain bd Information , Because maybe Defined parentBeanDefinition
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
// Non Abstract , Single case , And it's not lazy loading
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
// Judge whether it is FactoryBean
if (isFactoryBean(beanName)) {
// FactoryBean You need to add a prefix & , adopt getBean(&beanName) What you get is FactoryBean In itself
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
FactoryBean<?> factory = (FactoryBean<?>) bean;
// Determine whether initialization is required
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(
(PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
// It needs to be initialized
if (isEagerInit) {
getBean(beanName);
}
}
}
else {
getBean(beanName);
}
}
}
// Trigger post-initialization callback for all applicable beans...
// If Bean Realized SmartInitializingSingleton,
// In this case, we will call afterSingletonsInstantiated Method
for (String beanName : beanNames) {
Object singletonInstance = getSingleton(beanName);
if (singletonInstance instanceof SmartInitializingSingleton) {
StartupStep smartInitialize = this.getApplicationStartup().start("spring.beans.smart-initialize")
.tag("beanName", beanName);
SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
smartSingleton.afterSingletonsInstantiated();
return null;
}, getAccessControlContext());
}
else {
smartSingleton.afterSingletonsInstantiated();
}
smartInitialize.end();
}
}
}

In the above method, through the loop beanNames To initialize Bean.

There needs to be a difference BeanFactory and Ordinary Bean. That's why I first introduced What is? BeanFactory ?

Now we need to focus on getBean(beanName) Method .

getBean

public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}

stay getBean Method is called doGetBean Method .

doGetBean

doGetBean The function of the method is : Return an instance , The instance can be a specified bean Shared or independent of .

The method takes four parameters :

"name – To retrieve bean The name of requiredType – To retrieve bean Required type of , This can be empty args – Create... With explicit parameters bean Parameters to be used in the instance ( Apply only when creating a new instance instead of retrieving an existing one ) typeCheckOnly – Whether to get instances for type checking instead of actual use

protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
// Remove the prefix of the factory reference , Also change aliases
String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
// Check whether the singleton already exists from the cache
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
// If you get it from the cache , Ordinary Bean Go straight back to , FactoryBean Then return to FactoryBean Created Bean
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
// Returns the specified Prototype bean (prototype Type of Bean) Is currently being created ( In the current thread ).
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// Check if bean definition exists in this factory.
// Check BeanFactory Is there this Bean Of BeanDefinition
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
// Check if there is a definition in the parent container
String nameToLookup = originalBeanName(name);
// Returns the result of a query from the parent container
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else if (requiredType != null) {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}
if (!typeCheckOnly) {
// Will the current beanName Put one in alreadyCreated Of Set Collection .
// Identify the calling method , Not to get bean The type of , It's about creating instances , take beanName Deposit in alreadyCreated aggregate , On behalf of bean Already created , Back try..catch If there is an exception, it will be cleared beanName
markBeanAsCreated(beanName);
}
StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
.tag("beanName", name);
try {
if (requiredType != null) {
beanCreation.tag("beanType", requiredType::toString);
}
// obtain Bean Of BeanDefinition
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
// Make sure you rely on Bean Has been initialized , such as @DependsOn annotation
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
try {
// Create dependent Bean
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
// Create bean instance.
if (mbd.isSingleton()) {
// Single case bean
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// Create prototypes Bean
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
// Delegate to the implementation class
String scopeName = mbd.getScope();
if (!StringUtils.hasLength(scopeName)) {
throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");
}
Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new ScopeNotActiveException(beanName, scopeName, ex);
}
}
}
catch (BeansException ex) {
beanCreation.tag("exception", ex.getClass().toString());
beanCreation.tag("message", String.valueOf(ex.getMessage()));
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
finally {
beanCreation.end();
}
}
// Check if required type matches the type of the actual bean instance.
// Check that the type required is the same as the actual bean Type matching of instances .
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return convertedBean;
}
catch (TypeMismatchException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}

The above code is quite long , Basically the steps have been annotated , Basically, it can be divided into three steps :

  1. Get... From the cache Bean, Create the corresponding Bean;
  2. Not getting... From the cache Bean, Create the corresponding Bean;
  3. Check that the type required is the same as the actual bean Type matching of instances .

Here are three steps :

  • Get... From the cache Bean, Create the corresponding Bean

Object sharedInstance = getSingleton(beanName);

public Object getSingleton(String beanName) {
return getSingleton(beanName, true);
}
/**
* Returns... Registered with the given name ( original ) Singleton object .
*
* Check the instantiated singletons , And allows early references to the currently created singleton ( Resolving circular references )
*/
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// Quick check for existing instance without full singleton lock
// private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
// Cached Single case Bean
Object singletonObject = this.singletonObjects.get(beanName);
// If not , And the current Bean Being created
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
// private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
// Early singletons , First from earlySingletonObjects In order to get
singletonObject = this.earlySingletonObjects.get(beanName);
// Not from earlySingletonObjects In the cache
if (singletonObject == null && allowEarlyReference) {
synchronized (this.singletonObjects) {
// Consistent creation of early reference within full singleton lock
// Get and check again
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
// private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
// from singletonFactories Get in cache
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
// Add to earlySingletonObjects In cache
this.earlySingletonObjects.put(beanName, singletonObject);
// from singletonFactories Delete... In cache
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}

You can see here , Get one Bean :

  1. First from singletonObjects In order to get Bean;
  2. Can't get , from earlySingletonObjects In order to get Bean;
  3. Can't get , from singletonFactories In order to get Bean.

Of course, this one involves circular references , Limited space , I'll focus on circular references later .

  • Not getting... From the cache Bean, Create the corresponding Bean
// Create bean instance.
if (mbd.isSingleton()) {
// Single case bean
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
} else if (mbd.isPrototype()) {
// Create prototypes Bean
} else {
// Delegate to the implementation class
String scopeName = mbd.getScope();
}
  • Check that the type required is the same as the actual bean Type matching of instances

summary

Here we mainly introduce Bean The creation process of , The main thing is to have a general understanding and familiarity with the whole process , The process is illustrated as follows :

among Bean Instantiation of focuses on singletons Bean Instantiation , Later, we will study it in detail , Then explain .

Reference link :

[1]

What's a FactoryBean?: https://spring.io/blog/2011/08/09/what-s-a-factorybean

- <End /> -

This article is from WeChat official account. - Programmer Xiaohang (gh_liuzhihang) , author : Liu Zhihang

The source and reprint of the original text are detailed in the text , If there is any infringement , Please contact the yunjia_community@tencent.com Delete .

Original publication time : 2021-01-13

Participation of this paper Tencent cloud media sharing plan , You are welcome to join us , share .

版权声明
本文为[Programmer Xiaohang]所创,转载请带上原文链接,感谢
https://javamana.com/2021/01/20210121195549800g.html

  1. 【计算机网络 12(1),尚学堂马士兵Java视频教程
  2. 【程序猿历程,史上最全的Java面试题集锦在这里
  3. 【程序猿历程(1),Javaweb视频教程百度云
  4. Notes on MySQL 45 lectures (1-7)
  5. [computer network 12 (1), Shang Xuetang Ma soldier java video tutorial
  6. The most complete collection of Java interview questions in history is here
  7. [process of program ape (1), JavaWeb video tutorial, baidu cloud
  8. Notes on MySQL 45 lectures (1-7)
  9. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
  10. Refined spring boot 03: spring boot configuration files and configuration management, and reading configuration files in three ways
  11. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
  12. Refined spring boot 03: spring boot configuration files and configuration management, and reading configuration files in three ways
  13. 【递归,Java传智播客笔记
  14. [recursion, Java intelligence podcast notes
  15. [adhere to painting for 386 days] the beginning of spring of 24 solar terms
  16. K8S系列第八篇(Service、EndPoints以及高可用kubeadm部署)
  17. K8s Series Part 8 (service, endpoints and high availability kubeadm deployment)
  18. 【重识 HTML (3),350道Java面试真题分享
  19. 【重识 HTML (2),Java并发编程必会的多线程你竟然还不会
  20. 【重识 HTML (1),二本Java小菜鸟4面字节跳动被秒成渣渣
  21. [re recognize HTML (3) and share 350 real Java interview questions
  22. [re recognize HTML (2). Multithreading is a must for Java Concurrent Programming. How dare you not
  23. [re recognize HTML (1), two Java rookies' 4-sided bytes beat and become slag in seconds
  24. 造轮子系列之RPC 1:如何从零开始开发RPC框架
  25. RPC 1: how to develop RPC framework from scratch
  26. 造轮子系列之RPC 1:如何从零开始开发RPC框架
  27. RPC 1: how to develop RPC framework from scratch
  28. 一次性捋清楚吧,对乱糟糟的,Spring事务扩展机制
  29. 一文彻底弄懂如何选择抽象类还是接口,连续四年百度Java岗必问面试题
  30. Redis常用命令
  31. 一双拖鞋引发的血案,狂神说Java系列笔记
  32. 一、mysql基础安装
  33. 一位程序员的独白:尽管我一生坎坷,Java框架面试基础
  34. Clear it all at once. For the messy, spring transaction extension mechanism
  35. A thorough understanding of how to choose abstract classes or interfaces, baidu Java post must ask interview questions for four consecutive years
  36. Redis common commands
  37. A pair of slippers triggered the murder, crazy God said java series notes
  38. 1、 MySQL basic installation
  39. Monologue of a programmer: despite my ups and downs in my life, Java framework is the foundation of interview
  40. 【大厂面试】三面三问Spring循环依赖,请一定要把这篇看完(建议收藏)
  41. 一线互联网企业中,springboot入门项目
  42. 一篇文带你入门SSM框架Spring开发,帮你快速拿Offer
  43. 【面试资料】Java全集、微服务、大数据、数据结构与算法、机器学习知识最全总结,283页pdf
  44. 【leetcode刷题】24.数组中重复的数字——Java版
  45. 【leetcode刷题】23.对称二叉树——Java版
  46. 【leetcode刷题】22.二叉树的中序遍历——Java版
  47. 【leetcode刷题】21.三数之和——Java版
  48. 【leetcode刷题】20.最长回文子串——Java版
  49. 【leetcode刷题】19.回文链表——Java版
  50. 【leetcode刷题】18.反转链表——Java版
  51. 【leetcode刷题】17.相交链表——Java&python版
  52. 【leetcode刷题】16.环形链表——Java版
  53. 【leetcode刷题】15.汉明距离——Java版
  54. 【leetcode刷题】14.找到所有数组中消失的数字——Java版
  55. 【leetcode刷题】13.比特位计数——Java版
  56. oracle控制用户权限命令
  57. 三年Java开发,继阿里,鲁班二期Java架构师
  58. Oracle必须要启动的服务
  59. 万字长文!深入剖析HashMap,Java基础笔试题大全带答案
  60. 一问Kafka就心慌?我却凭着这份,图灵学院vip课程百度云