It has been several months since I last wrote Spring source code parsing. The main reason is that the Spring source code parsing class article is very difficult to write, unlike my previous posts on CAS source code, AQS source code, LinkedBlockingQueue, etc. These are just a few core methods to analyze. The code is not too long, like the more complex AQS source code is also two done, although AQS source code also a lot of things can not be regarded as one hundred percent of the understanding, but the core idea should still be understood. Parsing finished sense of achievement is also full, after writing the blog, looking at a large section of text, the in the mind is also very happy: ha ha ha, the original JDK source code can also read, but also can write out. But Spring source is different, if and source analysis of previous articles as line by line to parsing, you may write down a blog, a small small small methods couldn’t finish analysis, even if analysis is completed, also highlight the key, but the Spring source code parsing or to continue, just as your study notes.
Today we are going to look at the life cycle of Spring beans. Of course, this blog is just a bird’s eye view. It will not do too much source code analysis, or even just post code. You still have to be skeptical, maybe my analysis is wrong.
I don’t know if Spring officially has a clear definition or resolution of the Bean life issue, but Spring In Action and most of the blogs circulating In the market go something like this:
- Instantiate the Bean object. The Bean object is very low-level and cannot be used because the most basic properties are not set. Even the Autowired annotation is not parsed.
- Fill the properties. At this point, the Bean object is almost complete, meaning that the Autowired annotation has been parsed and dependency injection has been completed;
- If the Bean implements the BeanNameAware interface, the setBeanName method is called;
- If the Bean implements the BeanClassLoaderAware interface, the setBeanClassLoader method is called;
- If the Bean implements the BeanFactoryAware interface, call the setBeanFactory method;
- Call the BeanPostProcessor postProcessBeforeInitialization method;
- If the Bean implements the InitializingBean interface, call the afterPropertiesSet method;
- If the Bean defines an init-method method, the Bean’s init-method method is called;
- Call the BeanPostProcessor postProcessAfterInitialization method; At this point, the Bean is ready and remains in the context of the application until it is destroyed;
- If the application context has been destroyed, the destroy method will be called if the Bean implements the DisposableBean interface, and also if the Bean defines destory-method and declares the destruction method.
To verify the above logic, try an experiment:
StudentService = new; studentService = new; studentService = new; studentService = new; SetBeanName prints studentService to see if the Bean has been injected. This validates when the Bean has been injected. Nothing more than a common Bean) :
public class SpringBean implements InitializingBean, DisposableBean, BeanNameAware, BeanFactoryAware, BeanClassLoaderAware {
public SpringBean() {
System.out.println("SpringBean constructor :" + studentService);
System.out.println("SpringBean constructor");
}
@Autowired
StudentServiceImpl studentService;
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("afterPropertiesSet");
}
@Override
public void destroy() throws Exception {
System.out.println("destroy");
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
System.out.println("setBeanClassLoader");
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("setBeanFactory");
}
@Override
public void setBeanName(String name) {
System.out.println("setBeanName:" + studentService);
System.out.println("setBeanName");
}
public void initMethod() {
System.out.println("initMethod");
}
public void destroyMethod() {
System.out.println("destroyMethod"); }}Copy the code
To define a BeanPostProcessor, to the rewriting of the two methods in judgment, if the incoming beanName springBean to print:
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if(beanName.equals("springBean")) {
System.out.println("postProcessBeforeInitialization");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if(beanName.equals("springBean")) {
System.out.println("postProcessAfterInitialization");
}
returnbean; }}Copy the code
Define a configuration class that does the automatic scanning, but the SpringBean is manually registered and declares initMethod and destroyMethod:
@Configuration
@ComponentScan
public class AppConfig {
@Bean(initMethod = "initMethod",destroyMethod = "destroyMethod")
public SpringBean springBean() {
returnnew SpringBean(); }}Copy the code
Finally, there is the startup class:
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext =
new AnnotationConfigApplicationContext(AppConfig.class);
annotationConfigApplicationContext.destroy();
}
Copy the code
Running results:
SpringBean constructor: Null SpringBean constructorsetBeanName:com.codebear.StudentServiceImpl@31190526
setBeanName
setBeanClassLoader
setBeanFactory
postProcessBeforeInitialization
afterPropertiesSet
initMethod
postProcessAfterInitialization
destroy
destroyMethod
Copy the code
As can be seen, the test results are in complete agreement with the above analysis.
This is the popular Spring life cycle.
Maybe you memorized these conclusions when you were going through an interview, and now I’m going to lead you through them. Follow me.
First of all, we came to AnnotationConfigApplicationContext constructor:
/ / can know, depending on the type of parameter can be introduced into multiple annotatedClasses actually, but the problem is less public AnnotationConfigApplicationContext (Class <? >... AnnotatedClasses) {/ / calls a no-parameter constructor, will be invoked GenericApplicationContext superclass constructor / / the superclass constructor is to initialize DefaultListableBeanFactory inside, And assigned to the beanFactory / / this class constructor, initialize a reader: AnnotatedBeanDefinitionReaderread, a scanner ClassPathBeanDefinitionScanner scanner / / the usefulness of the scanner is not very big, it is only in our external call manually. The scan method is useful, such as the conventional way won't use this scanner object (); // Passing in a traditional Configuration class // passing in a bean (although no one would normally do this) // As you will see later, Spring calls the traditional Configuration class with @Configuration the FULL Configuration class. The Configuration classes without @Configuration are called Lite Configuration classes, and the ones without @Configuration are called ordinary Bean Register (annotatedClasses). / / set the refresh (); }Copy the code
Enter the refresh method, refresh method has a small finishBeanFactoryInitialization method, this method is used to instantiate the lazy loading singleton beans, This is where our beans are created (of course I’m talking about the vast majority of cases here) :
finishBeanFactoryInitialization(beanFactory);
Copy the code
We again into finishBeanFactoryInitialization this method, there is a the beanFactory. PreInstantiateSingletons () method:
/ / initialize all the lazy loading list in the beanFactory preInstantiateSingletons ();Copy the code
Let’s try to click on it again, and at this point you’ll see that this is an interface, but fortunately it only has one implementation class, so we can get to its unique implementation, Implementation class is org. Springframework. Beans. Factory. Support. DefaultListableBeanFactory, there is a loop, Bean’s cycle was created to us, we find the getBean method:
getBean(beanName);
Copy the code
There’s a branch, so if the Bean is a FactoryBean, so if the Bean is not a FactoryBean, so the good thing is that whether it’s a FactoryBean or not, it still calls the getBean method, so we can click on it without hesitation, and when we click on it, you’ll see, This is a facade method that calls the doGetBean method directly:
return doGetBean(name, null, null, false);
Copy the code
Go back in, go deeper and deeper, get closer to what we’re looking for. It’s a little complicated here, but with me here, I can tell you straight away, where are we going to go next? Are we going to go in
if(mbd.isSingleton()) {// The second argument type in getSingleton is ObjectFactory<? > is a functional interface that does not execute immediately, but instead calls getObject of the ObjectFactory in the //getSingleton method. CreateBean sharedInstance = getSingleton(beanName, () -> {try {returncreateBean(beanName, mbd, args); } catch (BeansException ex) { destroySingleton(beanName); throw ex; }}); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); }Copy the code
The createBean method is the interface, but don’t panic, this interface has only one implementation class, so it is nothing. The implementation class is org. Springframework. Beans. Factory. Support. AbstractAutowireCapableBeanFactory.
There are a lot of things that are done in this implementation method that we won’t look at, but I’ll just show you where those lifecycle callbacks are defined.
Object beanInstance = doCreateBean(beanName, mbdToUse, args); // Create bean, coreif (logger.isDebugEnabled()) {
logger.debug("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
Copy the code
Digging deeper into the doCreateBean method, this method does a bunch of things again, but the good news is that we’ve found what we’re looking for.
Create an instance
The first is to create an instance, located in:
instanceWrapper = createBeanInstance(beanName, mbd, args); // Create an instance of the bean. The coreCopy the code
Fill attribute
The second is the fill property, located in:
populateBean(beanName, mbd, instanceWrapper); // Fill property, fry chicken importantCopy the code
Below the fill property is a line of code:
exposedObject = initializeBean(beanName, exposedObject, mbd);
Copy the code
Go deeper.
Callbacks to the Aware series interface
The callbacks to the Aware series of interfaces are in the invokeAwareMethods method in initializeBean:
invokeAwareMethods(beanName, bean);
Copy the code
private void invokeAwareMethods(final String beanName, final Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
ClassLoader bcl = getBeanClassLoader();
if (bcl != null) {
((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
}
}
if(bean instanceof BeanFactoryAware) { ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this); }}}Copy the code
BeanPostProcessor postProcessBeforeInitialization method
BeanPostProcessor in initializeBean postProcessBeforeInitialization method
if(mbd == null || ! mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); }Copy the code
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
Copy the code
afterPropertiesSet init-method
AfterPropertiesSet Init-Method is located in the initializeBean
invokeInitMethods(beanName, wrappedBean, mbd);
Copy the code
AfterPropertiesSet (); init-method (); afterPropertiesSet ();
((InitializingBean) bean).afterPropertiesSet();
Copy the code
invokeCustomInitMethod(beanName, bean, mbd);
Copy the code
BeanPostProcessor postProcessAfterInitialization method
BeanPostProcessor in initializeBean postProcessAfterInitialization method
if(mbd == null || ! mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); }Copy the code
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
Copy the code
Of course, in actual development, no one should destroy the Spring application context, so the remaining two destroyed callbacks are not to be found.
This is the life cycle of a Spring Bean that is widely known, and I have led you to various callbacks and hooks, but I think this is not the full life cycle of a Spring Bean, just a simplified life cycle.