preface

I’m sure many of you have used this word in your resume. Mastery of these four words is based on the level of each person is not the same, understanding is not the same. A recent college graduate, for example, may also say on his resume that he is proficient in the Spring framework, but he has not actually read the spring source code or practiced much. You might just read a few books, write a graduation project using the Spring framework, and say you know the Spring framework. Another example is a candidate with 2003 work experience who says he is familiar with the Spring framework in his resume because he has seen some key code of Spring and developed engineering projects using spring in his actual work. I even wrote a couple of nice extensions to the Spring framework for some business needs. Another example is a programmer who has worked for four or five years and says on his resume that he knows the Spring framework well. Because he has read most of spring and Spring Boot source code, the work has solved many problems involving the original reason. The entire architecture diagram of the Spring framework is well understood. A number of Spring-related best practices have also been summarized. For example, a programmer who has worked for seven or eight years may have a different understanding of Spring. What I really want to say is that one’s opinion is determined by one’s level and experience. Everyone should learn modestly to enrich and consolidate their knowledge system, broaden the breadth of knowledge, strengthen the depth of knowledge. This will be in a limited time, grow into a towering tree. So, without further ado, today’s topic is mastering the Spring framework. So I’m going to start with n questions. Here’s my take on mastery after years of work.

The difference between BeanFactory and FactoryBean

Let’s start with the BeanFactory, which is the top-level interface to the springIOC container. Responsible for managing and producing beans. His is the default implementation: DefaultListableBeanFactory. In the spring the boot project started, execution createApplicationContext after () returns an instance of the type is AnnotationConfigApplicationContext, may have a look of the class hierarchy structure. It is also found to be an implementation class for the BeanFactory interface. The code is in AbstractApplicationContext ApplicationContext of abstract classes, It can be seen that all members of the realization of the BeanFactory or call the GenericApplicationContext DefaultListableBeanFactory the BeanFactory concrete realization. Nature is DefaultListableBeanFactory so Bean management at the core of the code.

Looking at its class hierarchy diagram, you can see that this class has two primary roles, the first being the bean factory and the second being the BeanDefinition registry. Bean factory provides for singleton bean registry (DefaultSingletonBeanRegistry), FactoryBean registry (FactoryBeanRegistrySupport) support. First let’s look at how he implements the bean factory.

Register the singletonbean

use@ Component annotationTo define aUserService

Breakpoint is set on DefaultSingletonBeanRegistry singleton bean addSingleton registry.

Look at the call stack:

  1. Occur in therefreshContextphase
  2. Initialize the singleton pattern bean
  3. Instantiation is triggered by getBeanuserService, getBean is then calleddoGetBean

The doGetBean method can be expanded a bit

It calls the DefaultSingletonBeanRegistry getSingleton the second parameter is the ObjectFactory, Create the bean factory ObjectFactory actual call is AbstractAutowireCapableBeanFactory createBean method, and then call it doCreateBean, Then call createBeanInstance method, and then call instantiateBean method, using SimpleInstantiationStrategy strategy class (the actual use of Java reflection technology dynamic creation object) instance is created.

Access to the singletonbean

So that’s the same example. The getBean method is called in ApplicationRunner’s Run method.

The doGetBean method first checks if there is one in the simple cache and returns it if there is one.

BeanDefinitionregistered

Let’s look at it againBeanDefinitionHow the registry is implemented. We are still inDefaultListableBeanFactorytheregisterBeanDefinitionSet a breakpoint and see the call stack.

  1. It also happensrefreshContextphase
  2. Execute allBeanFactoryPostProcessor
  3. Execute allBeanDefinitionRegistryPostProcessor, the default name is:ConfigurationClassPostProcessor
  4. The main job of this method is to call it firstConfigurationClassUtils.checkConfigurationClassCandidateFind all theConfigurationClassThe candidate is then usedConfigurationClassParserParse eachConfigurationClass.
  5. If it isComponentScanstheConfigurationClass, just callClassPathBeanDefinitionScannerthedoScanScan.
  6. Will scan theBeanDefinitionAdded to theDefaultListableBeanFactorybeanDefinitionMapIn the water. completeBeanDefinitionThe registration.

FactoryBean

Having said so much, I believe readers have a comprehensive understanding of the Spring framework’s BeanFactory. Let’s talk about FactoryBeans. A FactoryBean is a special type of bean in the Spring container.

The implementation of this interface takes the BeanFactory as the factory. Suppose a Bean implements this interface and acts as a factory for producing objects. Rather than exposing themselves directly as normal beans do. Beans are usually exposed using the getObject method. Factorybeans support singletons and stereotypes, and can be created on demand or at startup time. This interface is used extensively within the Spring framework, Such as AOP org. Springframework. AOP) framework. ProxyFactoryBean Jpa’s org. Springframework. Data. Jpa. Repository. Support. JpaRepositoryFactoryBean, however in real business code is not common.

Source Java doc

Let’s take a look at how a FactoryBean works using JpaRepositoryFactoryBean.

Check out the previous article on the JpaRepositoryBean creation process, which does not cover the initialization of aRepository bean in detail. We still call ApplicationContext’s getBean in ApplicationRunner’s run method to get a UserRepository. For the first time, the process looks like this.

  1. callBeanFactorythegetBeanMethods.
  2. The actual logic isAbstractBeanFactorythedoGetBeanIn the method.
  3. According to the beanNameuserRepositoryinSingletonBeanRegistryTo find the correspondingJpaRepositoryFactoryBean
  4. And then based onFactoryBeanRegistryIn the cache offactoryBeanObjectCache) by beanNameuserRepositoryIt was the first time so I couldn’t find it.
  5. callFactoryBeanRegistrySupportthegetObjectFromFactoryBeanMethods. This method has a block of synchronization code to ensure that the object created is still a singleton in the case of concurrency.
  6. Synchronized code block back to callJpaRepositoryFactoryBeanthegetObjectMethod that was created before gettingrepositoryAnd then join tofactoryBeanObjectCacheAnd return the correspondingbean

summary

Learning from the source code, we found that BeanFactory and FactoryBean are two completely different concepts, but their code is closely related. A FactoryBean is a special bean in the BeanFactory. Because it is also a factory, it can produce its own bean. There is one special thing that needs our attention. If beanName is passed with the prefix ampersand. The transformedBeanName method of BeanFactoryUtils is called, the prefix is removed, and the corresponding bean is retrieved from the Singleton registry. If you can’t find it, there’s a long code to process it. I don’t want to go into that here, but for those who are interested.

BeanPostProcessor and spring BeanFactoryPostProcessor

Both classes end in PostProcessor, the Chinese name for post-processor, which means the operation that takes place after a Bean or BeanFactory is created. PostProcessor is everywhere in the Spring core code.

First let’s take a look at BeanFactoryPostProcessor, a UML diagram. The diagram is simple. BeanFactoryPostProcessor defines a method. The argument is the bean factory you just created. And BeanDefinitionRegistryPostProcessor definition method of parameters is just created good BeanDefinition registry.

We are one of the most representative class ConfigurationClassPostProcessor see when it is called, it did. We the breakpoint is set on its postProcessBeanFactory and postProcessBeanDefinitionRegistry method. The discovery occurs during the refreshContext phase of Spring startup, when the Bean factory has been created. All spring BeanFactoryPostProcessor first call all BeanDefinitionRegistryPostProcessor call again. See PostProcessorRegistrationDelegate invokeBeanFactoryPostProcessors. Will be transferred to the ConfigurationClassPostProcessor twice.

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
		int registryId = System.identityHashCode(registry);
		if (this.registriesPostProcessed.contains(registryId)) {
			throw new IllegalStateException(
					"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
		}
		if (this.factoriesPostProcessed.contains(registryId)) {
			throw new IllegalStateException(
					"postProcessBeanFactory already called on this post-processor against " + registry);
		}
		this.registriesPostProcessed.add(registryId);
    / / core logic in processConfigBeanDefinition () method, is used to handle BeanDefinition registration
		processConfigBeanDefinitions(registry);
}
Copy the code
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		int factoryId = System.identityHashCode(beanFactory);
		if (this.factoriesPostProcessed.contains(factoryId)) {
			throw new IllegalStateException(
					"postProcessBeanFactory already called on this post-processor against " + beanFactory);
		}
		this.factoriesPostProcessed.add(factoryId);
		if (!this.registriesPostProcessed.contains(factoryId)) {
			// BeanDefinitionRegistryPostProcessor hook apparently not supported...
			// Simply call processConfigurationClasses lazily at this point then.
			processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
		}

    // Cglib enhanced proxy for Configuration classes annotated with @Configuration
		enhanceConfigurationClasses(beanFactory);
    // Add a BeanPostProcessor post-processor
		beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}
Copy the code

ConfigurationClassPostProcessor is one of the most important and the most complicated spring post processor, here is not carried out in detail. Look again at the UML diagram of BeanPostProcessor.

Where the two method calls are in AbstractAutowireCapableBeanFactory initializeBean.

Look at a simple example, the above studying ConfigurationClassPostProcessor, we find that it adds a rear bean processors ImportAwareBeanPostProcessor, The following is its postProcessBeforeInitialization method

// If the bean implements ImportAware, call its setImportMetadata method. In this way, the annotated metadata can be retrieved in the program.
public Object postProcessBeforeInitialization(Object bean, String beanName) {
			if (bean instanceof ImportAware) {
				ImportRegistry ir = this.beanFactory.getBean(IMPORT_REGISTRY_BEAN_NAME, ImportRegistry.class);
				AnnotationMetadata importingClass = ir.getImportingClassFor(ClassUtils.getUserClass(bean).getName());
				if(importingClass ! =null) { ((ImportAware) bean).setImportMetadata(importingClass); }}return bean;
}
Copy the code

Above is one of spring’s built-in processors. In practice, we often customize the rear processor as well. A common scenario is to dynamically enhance certain classes.

To be continued, please pay attention to the second part of mastering the Spring Framework for more content