Ps: Bean initialization is so much covered that I have to split it into two parts
- Part 1: Mainly explains the related content of BeanFactory, including the related content of the post-processor
- The next chapter focuses on Bean instantiation
What is Bean??
What is bean? Springbeans are a simple shorthand: classes that are initialized, assembled, and managed by the Spring container, and whose life cycle is governed by Spring.
1, bean configuration mode (familiar friends can skip directly)
(1) XML configuration
XML configuration is an early configuration way, after the emergence of SpringBoot gradually eliminated, configuration items are complex, look chaotic, some partners into the pit for a short time, or even do not have access to XML configuration, a simple demonstration, we see a lively. Create a bean before the first to have a class, SpringBoot can not be created out of thin air, I do not know if you have female tickets, not small friends today lucky, today one person hair a!! Ohhhhhhhhhhhh!!!!!! Open up a GirlFriend using SpringBoot New to stimulate a custom GirlFriend thief.
public class GirlFriend{
private String name;
private Integer age;
private Integer height;
private Integer weight;
private List<String> hobby;
public GirlFriend(a){}
public GirlFriend(String name,Integer age){
this.name = name;
this.age = age; }... GetSet to omit... }Copy the code
Have a girlfriend also need to take Home, and define a Home
public class Home{
privateGirlFriend girlFriend; . GetSet to omit... }Copy the code
1) No-parameter construction
Create an XML file in Resources and call it whatever you want, first-love-girl.xml
<?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"> <! -- Took notes!! XMLNS: a file address for initializing beans XMLNS :xsi: a file address for initializing beans Auxiliary initialization bean xsi:schemaLocation: used for schema documents that declare the target namespace --> <! Create a bean with id: unique representation,class: full path name --> <bean id="girlFriend" class="com.gyx.test.GirlFriend"> <! Assign a value to a propertynameAttribute name:value: injected value --> <property name="name" value="cuiHua"/ > <! -- Boys like girls of eighteen.property name="age" value18 = "" / > <property name="hobby">
<list>
<value< / > reading a bookvalue>
<value> Eat snacks </value>
</list>
</property>
</bean>
<bean id="home" class="com.gyx.test.Home"> <! - the use ofrefTo reference the one already definedbeanObject - > <property name="girlFriend" ref="girlFriend"/ > < /bean>
</beans>
Copy the code
2) Parametric construction
. The repetition above skipped....<! Create a bean with id: unique representation, class: full path name -->
<bean id="girlFriend" class="com.gyx.test.GirlFriend">
<! Index: the position of the argument starts at 0, value: the value of the argument -->
<construcort-arg index="0" value="cuiHua">
<construcort-arg index="1" value="18">
<property name="hobby">
<list>
<value>Reading a book</value>
<value>Eating snacks</value>
</list>
</property>
</bean>. .... is also repeated belowCopy the code
3) Static factory method
With the growth of business, in order to solve the single problem of the majority of male compatriots, manual creation has been unable to meet the demand, set up factories for mass production
I. Define abstract classes
public abstract class GirlFriend{
abstract String getName(a);
}
Copy the code
Ii. Implement abstract classes
The girl
public class Loli extends GirlFriend {
@Override
String getName(a){
returnname; }}Copy the code
The queen
public class Queen extends GirlFriend {
@Override
String getName(a){
returnname; }}Copy the code
Iii. Implement static factories
public class GirlFriendFactory {
@Override
public static GirlFriend getGirlFriend(String type){
if("queen".equals(type)){
return new Queen();
} else if("loli".equals(type)) {
return new Loli();
}else {
return null; }}}Copy the code
Iv. The XML configuration
. The repetition above skipped....<! Create a bean with id: unique representation, class: full pathname, factory-method: factory method -->
<bean id="loli" class="com.gyx.test.GirlFriendFactory" factory-method="getGirlFriend">
<! Pass in parameters -->
<construcort-arg value="queen">
</bean>. .... is also repeated belowCopy the code
4) Example factory method
I. Create an instance factory
public class GirlFriendFactory {
@Override
public GirlFriend getGirlFriend(String type){
if("queen".equals(type)){
return new Queen();
} else if("loli".equals(type)) {
return new Loli();
}else {
return null; }}}Copy the code
Ii. The XML configuration
. The repetition above skipped....<bean name="girlFriendFactory" class="com.gyx.test.GirlFriendFactory">
<! Create a bean with id: unique representation, factory-bean: factory-method: factory-method -->
<bean id="loli" factory-bean="girlFriendFactory" factory-method="getGirlFriend">
<! Pass in parameters -->
<construcort-arg value="loli">
</bean>. .... is also repeated belowCopy the code
(2) Java code configuration of beans
1) @Component annotation configuration Bean (@service, @Controller are the same)
@Component
public class GirlFriend{
private String name;
private Integer age;
private Integer height;
private Integer weight;
private List<String> hobby;
public GirlFriend(a){}
public GirlFriend(String name,Integer age){
this.name = name;
this.age = age; }... GetSet to omit... }Copy the code
2) @bean annotations configure beans
@Configuration
public class BeanConfiguration{
@Bean
public GirlFriend getGirlFriend(a){
return new GirlFriend("cuihua".18); }}Copy the code
3) Configure beans using the FactoryBean interface
@Component
public class MyGirlFriend implements FactoryBean<GirlFriend>{
@Override
public GirlFriend getObject(a) throws Exception{
return newLoli(); }}Copy the code
4) use BeanDefinitionRegistryPostProcessor interface configuration Bean
@Component
public class MyGirlFriend implements BeanDefinitionRegistryPostProcessor{
// Register a bean object
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException{
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition();
rootBeanDefinition.setBeanClass(Queen.class);
registry.registerBeanDefinition("queen",rootBeanDefinition);
}
// This method injects values into bean objects
@Override
public void postProcessBeanFactory(ConfiguraleListableBeanFactory beanFactory) throws BeansException{
// Get the definition of the bean object you just defined
BeanDefinition queen = beanFactory.getBeanDefinition("queen");
// Add attribute values to the object
MutablePropertyValues propertyValues = queen.getPropertyValues();
propertyValues.addPropertyValue("name".Red Wolf); }}Copy the code
5) use ImportBeanDefinitionRegistrar interface configuration Bean
public class MyGirlFriend implements ImportBeanDefinitionRegistrar{
@Override
public void registerBeanDefinition(AnnotationMetadata importingClassMetadata,BeanDefinitionRegistry registry){
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition();
rootBeanDefinition.setBeanClass(Queen.class);
registry.registerBeanDefinition("queen",rootBeanDefinition); }}Copy the code
The bean creation process
In the previous chapter, we learned how to create beans in chapter 9, so how does SpringBoot create girlfriends? No, no, no, no, no. The process of creating and loading beans is encapsulated in the refresh method. This method is commonly referred to as “bean life point · Spring startup key · interview question ·refresh”. I don’t know if you fully understood this before, but it doesn’t matter! Not 998 today, not 99.8! A single article takes you straight to the point where you can fully understand the refresh method without saying much! SpringBoot together in the heart of it!!
Find the location of the refresh method
Step 1: To take care of new friends, we’ll start with the Boot class of SpringBoot and work our way through
@SpringBootApplication
public class Application {
public static void main(String[] args) {
// Enter the run methodSpringApplication.run(Application.class, args); }}Copy the code
Step 2: ConfigurableApplicationContext class
public static ConfigurableApplicationContext run(Class
primarySource, String... args) {
// enter the run method again
return run(newClass<? >[] { primarySource }, args); }Copy the code
Step 3: Enter the run method again
public static ConfigurableApplicationContext run(Class
[] primarySources, String[] args) {
// Continue clicking on the run method
// What is the run constructor doing
// Go ahead and catch up on the first article in this series, the answer is in there
return new SpringApplication(primarySources).run(args);
}
Copy the code
Step 4: Ok! We again SpringBoot heart method, specific comments here at https://blog.csdn.net/qq_34886352/article/details/104949485
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// This name looks similar to the target method
// Context is the context of the application, where many of the configured properties are stored
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
Copy the code
Step 5: The Refresh method is here
private void refreshContext(ConfigurableApplicationContext context) {
// I found it! Dangdang when! The refresh method sits quietly here, unremarkable and in fact deadly
refresh(context);
if (this.registerShutdownHook) {
try {
// This method registers a hook on the JVM to ensure that the container is closed properly when the program is closed
context.registerShutdownHook();
}
catch (AccessControlException ex) {
// Not allowed in some environments.}}}Copy the code
Refresh in the refresh method
Step 6: The first layer of the refresh method
protected void refresh(ApplicationContext applicationContext) {
// Refresh method is not lost for military purposes! Just as he entered, he was confronted by a guard
/ / whether the incoming parameters for AbstractApplicationContext subclasses, if not directly
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
// To perform type force, continue to click refresh method
/ / here will find that there are three implementations, some AbstractApplicationContext class
((AbstractApplicationContext) applicationContext).refresh();
}
Copy the code
Step 7: You can see that Refresh is a boss-level approach! But don’t panic. There are many ways we can take them one by one
@Override
public void refresh(a) throws BeansException, IllegalStateException {
// This method is locked, and only one thread needs to execute the current method at a time
synchronized (this.startupShutdownMonitor) {
// Ready to refresh! Some preparation before the actual construction
/ / step 8
prepareRefresh();
// Get the bean factory
/ / step 9
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Do some configuration for the beanFactory
// Add dependencies to be ignored, classloaders, post-handlers, parsers, etc., and aOP-related post-handlers are also configured here
/ / step 12
prepareBeanFactory(beanFactory);
try {
// Do some post-processing on the BeanFactory in context
/ / by default is an empty implementation, but we will mainly as a web service operation, will go to AnnotationConfigServletWebServerApplicationContext class, don't go the wrong way
// Registers handlers, beans, and configurations related to web requests
/ / step 13
postProcessBeanFactory(beanFactory);
Instantiate and invoke the bean factory-registered post-processor, which must be performed before the singleton bean is created
/ / step 15
invokeBeanFactoryPostProcessors(beanFactory);
// Register the backend handler used for bean creation
/ / step 17
registerBeanPostProcessors(beanFactory);
// Initializes the message source for this context, internationalizing the process
//messageSource is used for internationalization
// Determine if the BeanFactory contains a messageSource, if not, create one
/ / step 19
initMessageSource();
// Initializes the event broadcaster, part of the Spring listener
/ / step 20
initApplicationEventMulticaster();
// Initialize specific beans based on context
/ / if it is a web environment, will enter the ServletWebServerApplicationContext implementation
// This method mainly creates a Web container, such as the Tomcat container embedded in SpringBoot
// We'll skip this for now and parse it in more detail in future updates
onRefresh();
// Register the listener
// Add the listener implementation to the broadcaster
/ / step 21
registerListeners();
// Initialize the singleton bean
// This will be explained in the next article
// This is a very important question
finishBeanFactoryInitialization(beanFactory);
// Clear the cache and send the ContextRefreshedEvent event
/ / step 22
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy the singleton bean that has been created
destroyBeans();
// Change the state of the 'active' property
cancelRefresh(ex);
// Throw an exception
throw ex;
}
finally {
// Delete all caches to prevent too much memory usage, after all, the execution failed, the data is uselessresetCommonCaches(); }}}Copy the code
(1) Preliminary preparation
Step 8: Get ready to refresh! Some preparation before the actual construction
// Some friends version may not be the same as mine, but when you enter it, you find that it is not the same content, do not need to click the same method on the line
protected void prepareRefresh(a) {
// Record the startup time
this.startupDate = System.currentTimeMillis();
// Change the state of the context to active, indicating that the context is about to start busy, do not disturb it
this.closed.set(false);
this.active.set(true);
// In debug mode, some logs will be printed, which will not be read anyway
if (logger.isDebugEnabled()) {
if (logger.isTraceEnabled()) {
logger.trace("Refreshing " + this);
}
else {
logger.debug("Refreshing "+ getDisplayName()); }}// Initialize any placeholder property sources in the context environment
// Initialize the property
// This is version 2.1.0 and this method is empty
initPropertySources();
// Check key attributes. If the required attributes are empty, an exception will be thrown
/ / details view: ConfigurablePropertyResolver# setRequiredProperties
getEnvironment().validateRequiredProperties();
// Initialize earlyApplicationEvents
//SpringBoot listener contents, used to store listener events, to the corresponding location, these events will be fired one by one
/ / specific content see the previous content: https://blog.csdn.net/qq_34886352/article/details/105188150
this.earlyApplicationEvents = new LinkedHashSet<>();
}
Copy the code
The prepareRefresh method actually works the same as the receptionist, arranged as follows:
- Clock in in the morning, record your time, mute your phone, switch it to active, and get ready to start your day
- Check the work schedule, due to the adjustment, this period of time is relatively free, all the work is lost to others
- Roll call, see if all the employees are present, and make sure the required attributes are empty
- Bring out the new visitor register
Check here to teach you how to use the key attribute, how to add a key attribute Actually very simple also, in the first lesson we learned ApplicationContextInitializer interface, actually add key attribute is his hidden little feature
public class TestInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
// Get the program environment from the context
ConfigurableEnvironment environment = applicationContext.getEnvironment();
// Set a key property that needs to be defined in the SpringBoot configuration file Application, otherwise an exception will be thrown
environment.setRequiredProperties("girlFriendName"); }}Copy the code
Strange knowledge increased!
(2) Initialization of BeanFactory
Step 9: Get the Bean factory
protected ConfigurableListableBeanFactory obtainFreshBeanFactory(a) {
/ / the following two methods are implemented by GenericApplicationContext subclass, remember this class view
// Set the bean factory properties
/ / step 10
refreshBeanFactory();
// Get the bean factory
/ / step 11
return getBeanFactory();
}
Copy the code
This method is relatively simple, and it does two things altogether:
- Set the serialization ID of the beanFactory
- To obtain the beanFactory
Step 10: Set the bean factory properties
protected final void refreshBeanFactory(a) throws IllegalStateException {
// Set the checksum property to true to indicate that the refresh has begun
// use the CAS technology (compareAndSet), a thread-safe mechanism to prevent locking, compareAndSet the way, through the CPU layer
// First check if the value is false, if so change to true
if (!this.refreshed.compareAndSet(false.true)) {
throw new IllegalStateException(
"GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
}
// Set the id used for serialization. Default: application
this.beanFactory.setSerializationId(getId());
}
Copy the code
Step 11: Get the bean factory
public final ConfigurableListableBeanFactory getBeanFactory(a) {
/ / this method is very simple and direct access to GenericApplicationContext properties, is the following attributes
// Attribute initialization is done in the constructor, which is very simple
//private final DefaultListableBeanFactory beanFactory;
return this.beanFactory;
}
Copy the code
Step 12: Set up the bean, with some AOP-related content in the middle
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// Set the class loader
beanFactory.setBeanClassLoader(getClassLoader());
// Sets the expression parser to connect to SpEL expressions that may appear in the configuration file
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
// Set the property editor, used to do the property conversion, binding
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// Set the bean's backend handler. This is an important mechanism in SpringBoot, and we will focus on the callback method that executes after the bean is created
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
// Set the interfaces to be ignored for autologie. why ignore these interfaces and put them together with the post-processor
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
// Add a parser dependency to the BeanFactory. When the BeanFactory itself needs to be parsed and dependent, it can point to itself
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
// The following three are also the same, when the need to resolve the dependency to refer to itself
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// Add a post-processor to check whether the bean is a listener
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
The //containsLocalBean method checks all containers of the bean to see if it contains a bean with a specific name
//LOAD_TIME_WEAVER_BEAN_NAME: code weaving is aOP-related and will be covered later
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
// Add a post-processor to handle code weaving
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// Add a zero-hour class loader
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
// Register some default bean objects
// Run the environment's bean object
if(! beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {// If yes, create a singleton bean
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
// The system property bean object
if(! beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) { beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties()); }// The system runtime bean object
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}
Copy the code
To summarize, this seems like a long way to go, but it’s actually pretty dry:
- Set some properties of the BeanFactory
- Several important post-processors have been added
- Set the interface to be ignored for autoloading
- Some default beans are registered manually
Step 13: this method exists in AnnotationConfigServletWebServerApplicationContext class, is the realization of the subclass, see how the name is processing annotation configuration web service context class
@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// This class is not mature enough. Go! Go find his guardian
super.postProcessBeanFactory(beanFactory);
// Whether the base package is set is the scope of scanning annotations
if (this.basePackages ! =null && this.basePackages.length > 0) {
this.scanner.scan(this.basePackages);
}
// This is also the same, to determine whether to set up the annotated class to scan
if (!this.annotatedClasses.isEmpty()) {
this.reader.register(ClassUtils.toClassArray(this.annotatedClasses)); }}Copy the code
Step 14: This method exists in ServletWebServerApplicationContext class, also is the parent class AnnotationConfigServletWebServerApplicationContext class, without annotation configuration information context class
@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// Add a post-processor so that web application beans can get aware to the text
beanFactory.addBeanPostProcessor(
new WebApplicationContextServletContextAwareProcessor(this));
// Autowire ignores objects of type ServletContextAware
beanFactory.ignoreDependencyInterface(ServletContextAware.class);
}
Copy the code
(3) Use BeanFactory to register the bean definition
First, we need to understand two interfaces, which will help us read the source code later:
- BeanDefinitionRegistryPostProcessor: Bean definition registry post-processor, which can be used to register and delete bean definitions, At the same time can also modify the implementation method of the bean attribute value postProcessBeanDefinitionRegistry bean definitions (registration) and postProcessBeanFactory method (injection bean properties)
- BeanFactoryPostProcessor: a bean’s post-processor that modifies the bean’s property values. Implementation method postProcessBeanFactory method (injecting bean properties)
Step 15: Instantiate and invoke the bean factory-registered backend handler, which must be executed sequentially if the order is specified
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
/ / getBeanFactoryPostProcessors method, can obtain the bean factory post processor, post processor is added by initialization and listener, specific can point method, and then find the method of adding attributes, watching the method call
/ / initialize the injected class called ConfigurationWarningsApplicationContextInitializer ApplicationContextInitializer interface is achieved, is the first article content we spoke, The working principle of ApplicationContextInitializer interface
/ / listener class called ConfigFileApplicationListener, the contents of the second article, inspect the previous articles
/ / have a look at the below invokeBeanFactoryPostProcessors method, this method is very long, more than 100 lines, but it doesn't matter, the principle is very simple, we watch together
/ / step 16
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
// It checks for the presence of Aop, and if so, it adds the relevant post-processor for subsequent weaving
// This is a follow-up Aop related content, which is not discussed here
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(newContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); }}Copy the code
Step 16: call the bean factory rear processor parameter description: the beanFactory: used to create the instantiation of the bean factory object beanFactoryPostProcessors: current post processor in this factory for bean plant (strengthen)
public static void invokeBeanFactoryPostProcessors( ConfigurableListableBeanFactory beanFactory, List
beanFactoryPostProcessors)
{
//processedBeans hold beans that need to be processed first, objects that implement the PriorityOrdered or Ordered interface,
// To prevent these objects from being executed repeatedly, the guest officer looks back and explains later
Set<String> processedBeans = new HashSet<>();
// Determine whether beanFactory belongs to BeanDefinitionRegistry
//BeanDefinitionRegistry has the following functions
//1. Register the bean as a key-value. The key is beanName and the value is beanDefinition.
//2. Get or remove beanDefiniation according to beanName
//3. Check whether beanDefinition exists according to beanName
if (beanFactory instanceof BeanDefinitionRegistry) {
// Perform type conversion
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
// Processing is subdivided here
RegularPostProcessors are used to store normal post-processors
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
//registryProcessors is used to store the bean registration-related processors
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
// Loop the post-processor and categorize them
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
// The way to determine whether to register the associated post-handler for the bean is simple
/ / directly determine whether direct or indirect BeanDefinitionRegistryPostProcessor interface is realized
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
// Type the post-processor
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
/ / all realized BeanDefinitionRegistryPostProcessor interface classes, all need to implement postProcessBeanDefinitionRegistry this method
// When SpringBoot starts at this point, the implementation classes can retrieve the bean-defined registry
// BeanDefinitionRegistry has all bean definitions according to the previous comments. Add bean objects, delete bean objects in this step
// This is how the fourth method of configuring beans in Java code works
registryProcessor.postProcessBeanDefinitionRegistry(registry);
// categorize into the corresponding collection
registryProcessors.add(registryProcessor);
}
else {
// In addition to the bean registration related backend handler, is the normal handler, directly through the else classificationregularPostProcessors.add(postProcessor); }}/ / currentRegistryProcessors stored in order of priority in the bean definition registry of post processor
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
// Get the name of the bean by type from the bean factory
// First argument: query the type used by beanName
// The second argument: true: lookup from all beans, false: lookup from singleton beans
// The third argument: it is easy to understand whether to use the caching mechanism
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true.false);
// Iterate over the obtained bean to define the backend handler for the registry
for (String ppName : postProcessorNames) {
// Checks whether the current rear processor implements the PriorityOrdered interface, and returns true if it does
// It is necessary to specify the PriorityOrdered interface and Ordered interface
//PriorityOrdered is a subclass of Ordered, which sets the priority of calls to PriorityOrdered, and always calls the class that implements PriorityOrdered with a higher priority than Ordered
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
/ / the current bean instantiation, and deposit to currentRegistryProcessors getBean method below details
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
// Add them to processedBeans and process them firstprocessedBeans.add(ppName); }}/ / will currentRegistryProcessors according to priority
sortPostProcessors(currentRegistryProcessors, beanFactory);
// Add these bean definition registry afterprocessors to registryProcessors (where all bean registry-related afterprocessors are stored)
registryProcessors.addAll(currentRegistryProcessors);
// This method calls the methods of the objects in the collection in turn
/ / forget postProcessBeanDefinitionRegistry method friend, full text search, with detailed explanation
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
// Finally empty the collection
currentRegistryProcessors.clear();
// Get the side Bean definition registry post-processor again
// The difference is that objects that implement the PriorityOrdered interface are handled instead of objects that implement the Ordered interface
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true.false);
// Here, as above, separate the implementation of the PriorityOrdered and Ordered interfaces
for (String ppName : postProcessorNames) {
// Attention!! This time you get an object that implements the Ordered interface
if(! processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) { currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); processedBeans.add(ppName); }}// Same sort
sortPostProcessors(currentRegistryProcessors, beanFactory);
// Add the same, the objects in the collection registryProcessors are already sorted
registryProcessors.addAll(currentRegistryProcessors);
/ / call postProcessBeanDefinitionRegistry method
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
/ / then empty currentRegistryProcessors
currentRegistryProcessors.clear();
/ / in the end, some BeanDefinitionRegistryPostProcessor may not achieve PriorityOrdered interfaces or Ordered
// These objects are called directly through a loop, regardless of the order of execution
/ / when all BeanDefinitionRegistryPostProcessor after the execution, reiterate to false
boolean reiterate = true;
while (reiterate) {
reiterate = false;
// Get the side Bean definition registry post-processor again
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true.false);
// All loops are judged and executed
for (String ppName : postProcessorNames) {
/ / processedBeans method initially created collection, used to perform before BeanDefinitionRegistryPostProcessor object
if(! processedBeans.contains(ppName)) { currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); processedBeans.add(ppName); reiterate =true; }}// It is the same as the one above
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
}
// All right!! Here, all BeanDefinitionRegistryPostProcessor object is called
/ / the above treatment is BeanDefinitionRegistryPostProcessor interface
// The BeanFactoryPostProcessor interface is a factoryProcessor interface
// All that was actually done was the registration logic, and the post-callback to the real bean factory is just beginning
/ / invokeBeanFactoryPostProcessors cycle call postProcessBeanFactory method of collection objects
// Objects in registryProcessors and regularPostProcessors must implement the BeanFactoryPostProcessor interface
// The postProcessBeanFactory method must be implemented
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
}
else {
// This else is entered when the bean factory is not BeanDefinitionRegistry
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}
// This gets the beanName of the backend processor for all bean factories
// Why do I get it again? Because when performing BeanDefinitionRegistryPostProcessor is are more likely to sign up for a common bean plant in the post processor
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true.false);
// store all rear processors that implement the PriorityOrdered interface
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
// Stores all postordered processors that implement the Ordered interface
List<String> orderedPostProcessorNames = new ArrayList<>();
// Store a post-processor for which neither interface is implemented
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
// Categorize the rear processors
for (String ppName : postProcessorNames) {
if (processedBeans.contains(ppName)) {
//processedBeans holds the BeanName of the post-processor that has been executed, which can be used to determine whether it has been executed
If yes, skip this step
}
else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
// Separate objects that implement the PriorityOrdered interface, instantiate them, and store them in the corresponding collection
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
// Separate the objects that implement the Ordered interface and place the BeanName in the corresponding collection
orderedPostProcessorNames.add(ppName);
}
else {
// The rest are naturally objects that are not implemented by either interfacenonOrderedPostProcessorNames.add(ppName); }}// Same as before! First order
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
// Then execute in order, but this time with the postProcessBeanFactory method
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
// Then it is the turn of the object that implements the Ordered interface
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
// Finally, the object with neither interface implemented
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
// Clear the metadata cache in the bean factory. The getBean method generates the cache
beanFactory.clearMetadataCache();
}
Copy the code
To summarize, the long way to do this is to do two things:
- Call BeanDefinitionRegistryPostProcessor the implementation of the object, the water in the container to add a new bean definition
- Call the implementation object of the BeanFactoryPostProcessor to add properties to these bean definitions
(4) Bean post-processor
Step 17: Register the bean’s backend handler
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
/ / PostProcessorRegistrationDelegate is used to process the post processor dedicated tools
// Invoke the registration method step 18
PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}
Copy the code
Step 18: A post-processor parameter review to actually start registering beans! BeanFactory: the bean’s factory class, bean’s container applicationContext: the application’s context, containing the application’s environment information, and so on
public static void registerBeanPostProcessors( ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
// Get the bean factory's post-processor
BeanPostProcessor = BeanPostProcessor = BeanPostProcessor
// Fetch the bean's post-processor from all beanDefinitions
// So it is not the post-processor that was added earlier with the addBeanPostProcessor method
// The getBeanNamesForType method returns only the bean name, not the instance object
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true.false);
// Add a unique post-processor BeanPostProcessorChecker
/ / rear BeanPostProcessorChecker is bean processors a detector
// During the instantiation of a bean, all bean post-handlers are applied to the bean
// When I say "application", it doesn't have to do anything. The backend processor might find a bean that isn't the target type and skip it
// But if the post-processor is not working properly on the current bean, the BeanPostProcessorChecker will detect it and flag it
// We are counting the number of beans, which is one of the conditions to determine the correct operation of the post-processor
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
// Add BeanPostProcessorChecker to the post-processor container
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
// store a post-processor that implements the priorityOrdered interface
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
Deposit / / rear MergedBeanDefinitionPostProcessor type of processor, special post processor
List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
// Stores the beanName of the ordered postprocessor that implements the ordered interface
List<String> orderedPostProcessorNames = new ArrayList<>();
// Stores the beanName of a postordered processor that does not implement the ordered interface
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
// Iterate through all the back processors
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
// post-processor that implements the priorityOrdered interface, enter here
The handler is instantiated directly
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
// Add the corresponding container
priorityOrderedPostProcessors.add(pp);
/ / MergedBeanDefinitionPostProcessor is a special processor, he would be to merge the definition of a bean
if (pp instanceof MergedBeanDefinitionPostProcessor) {
// Add the corresponding containerinternalPostProcessors.add(pp); }}else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
// A post-processor that implements the Ordered interface, entering here
orderedPostProcessorNames.add(ppName);
}
else {
// No postprocessor implements Ordered and priorityOrdered interfacesnonOrderedPostProcessorNames.add(ppName); }}// Sort backend processors that implement the priorityOrdered interface by priority
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
/ / registered post processor, cycle, add the rear priorityOrderedPostProcessors processor to the rear of the BeanFactory processor in the container
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
/ / and then to realize the Ordered the rear of the interface processor, instantiated, and isolated MergedBeanDefinitionPostProcessor
// Holds an instance object of a postordered processor that implements the ordered interface
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>();
// Loop through the previously saved beanName
for (String ppName : orderedPostProcessorNames) {
// instantiate the post-processor
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
// Store it in a container
orderedPostProcessors.add(pp);
/ / determine whether for MergedBeanDefinitionPostProcessor (for merger bean definition of special post processor) types of objects
if (pp instanceof MergedBeanDefinitionPostProcessor) {
// Add to the corresponding containerinternalPostProcessors.add(pp); }}/ / sorting
sortPostProcessors(orderedPostProcessors, beanFactory);
// Will register the afterprocessor with the BeanFactory
registerBeanPostProcessors(beanFactory, orderedPostProcessors);
// Now start processing, no postprocessor implements ordered interface nor priorityOrdered interface
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
// Do the basic routine again
for (String ppName : nonOrderedPostProcessorNames) {
// instantiate the post-processor
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
// Store it in a container
nonOrderedPostProcessors.add(pp);
/ / determine whether for MergedBeanDefinitionPostProcessor (for merger bean definition of special post processor) types of objects
if (pp instanceof MergedBeanDefinitionPostProcessor) {
// Add to the corresponding containerinternalPostProcessors.add(pp); }}// Register the afterprocessor directly with the BeanFactory without sorting
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
/ / the rear handle MergedBeanDefinitionPostProcessor types of processors
/ / to rear MergedBeanDefinitionPostProcessor type of processor for sorting
sortPostProcessors(internalPostProcessors, beanFactory);
// Will register the afterprocessor with the BeanFactory
registerBeanPostProcessors(beanFactory, internalPostProcessors);
// The post-processor has been sorted and instantiated as required
// You also need to add a post-processor at the end of all post-processors to find out if the bean is a listener
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
Copy the code
(5) Some extended functions of SpringBoot
Step 19: initialize the messageSource for this context, messageSource is used for internationalization
protected void initMessageSource(a) {
// Get the BeanFactory
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// Check whether there is a MessageSource in BeanFactory
if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
// Instantiate the bean object of the message source
this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
// Determine if there is a multi-layer message source
if (this.parent ! =null && this.messageSource instanceof HierarchicalMessageSource) {
/ / strong, HierarchicalMessageSource for a multilayer sources
HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
if (hms.getParentMessageSource() == null) {
// If no parent class is set for the message, the parent message source is obtained and assignedhms.setParentMessageSource(getInternalParentMessageSource()); }}if (logger.isTraceEnabled()) {
logger.trace("Using MessageSource [" + this.messageSource + "]"); }}else {
// DelegatingMessageSource is basically the utility class that calls the parent message source, if there is no parent message source, nothing is being processed
DelegatingMessageSource dms = new DelegatingMessageSource();
// Set the parent message source
dms.setParentMessageSource(getInternalParentMessageSource());
// Set the message source
this.messageSource = dms;
// Register the singleton bean
beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
if (logger.isTraceEnabled()) {
logger.trace("No '" + MESSAGE_SOURCE_BEAN_NAME + "' bean, using [" + this.messageSource + "]"); }}}Copy the code
Although the object name inside is very obscure, in fact, just do a national initialization work
Step 20: Initialize the broadcaster
protected void initApplicationEventMulticaster(a) {
/ / get the BeanFactory
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// Determine whether the bean contains the broadcaster
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
// Instantiate the broadcaster and assign a value
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isTraceEnabled()) {
logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]"); }}else {
// Create a default broadcaster
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
// instantiate and assign to BeanFactory
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isTraceEnabled()) {
logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]"); }}}Copy the code
Step 21: Add the listener implementation to the broadcaster
protected void registerListeners(a) {
// Get all listeners and add them to the broadcaster
// Initialize the broadcaster in step 20
// Listener initialization and registration were explained in great detail in the previous article, but are not covered here
for(ApplicationListener<? > listener : getApplicationListeners()) { getApplicationEventMulticaster().addApplicationListener(listener); }// Gets the beanName of the listener type bean object, but these objects cannot be instantiated here because we need to let them be processed through the post-processor
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true.false);
for (String listenerBeanName : listenerBeanNames) {
// Add it to the container and cache it
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}
// There is an early broadcast call
// Since Spring's listener mechanism has not been created before, it is possible that the container has already triggered events that will be cached in earlyApplicationEvents
// Now the listener is ready to execute the cached event
// Get earlier events
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
// Clear out the earlier events
this.earlyApplicationEvents = null;
// Execute the earlier event you just fetched, which is normally empty
if(earlyEventsToProcess ! =null) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
// Broadcast eventsgetApplicationEventMulticaster().multicastEvent(earlyEvent); }}}Copy the code
Step 22: Clear the cache and send the ContextRefreshedEvent event
protected void finishRefresh(a) {
// Be aware of the cache in context
clearResourceCaches();
// Initialize the lifecycle processing component
initLifecycleProcessor();
// Start the lifecycle processing component (lifecycle component)
getLifecycleProcessor().onRefresh();
// Broadcast the ContextRefreshedEvent event
publishEvent(new ContextRefreshedEvent(this));
// The display view of the bean, which is not the point here, is just an additional feature that is not discussed at the moment
LiveBeansView.registerApplicationContext(this);
}
Copy the code