In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-26 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
This article mainly introduces the order of @ PostConstruct, afterPropertiesSet and init-method. It is very detailed and has some reference value. If you are interested, you must finish it.
@ PostConstruct, init-method, afterPropertiesSet () execution order
To know the order in which @ PostConstruct, init-method, and afterPropertiesSet () are executed, all you have to do is figure out when they were called and who called them.
Program version: Spring Boot 2.3.5.RELEASE
Prepare the material to be verified:
Public class Foo implements InitializingBean {@ Override public void afterPropertiesSet () throws Exception {System.out.println ("afterPropertiesSet ()");} @ PostConstruct public void init () {System.out.println ("@ PostConstruct");} private void initMethod () {System.out.println ("initMethod ()") } @ Configurationpublic class FooConfiguration {@ Bean (initMethod = "initMethod") public Foo foo () {return new Foo ();}}
Execute the startup class, and you can see the output in the console:
@ PostConstruct
AfterPropertiesSet ()
InitMethod ()
The order of execution is @ PostConstruct, afterPropertiesSet (), init-method
The next step is to follow the source code to see why it is in this order.
When the method of @ PostConstruct annotation is called by whom
First, make a breakpoint in init (), and then start the project as debug to get the following call stack:
Init:23, Foo (com.xurk.init.foo) invoke0:-1, NativeMethodAccessorImpl (sun.reflect) invoke:62, NativeMethodAccessorImpl (sun.reflect) invoke:43, DelegatingMethodAccessorImpl (sun.reflect) invoke:498, Method (java.lang.reflect) invoke:389, InitDestroyAnnotationBeanPostProcessor$LifecycleElement (org.springframework.beans.factory.annotation) invokeInitMethods:333, InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata (org.springframework.beans.factory.annotation) postProcessBeforeInitialization:157, InitDestroyAnnotationBeanPostProcessor (org.springframework.beans.factory.annotation) applyBeanPostProcessorsBeforeInitialization:415, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support) initializeBean:1786 AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support) doCreateBean:594, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support) createBean:516, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support) lambda$doGetBean$0:324, AbstractBeanFactory (org.springframework.beans.factory.support) getObject:-1, 2103763750 (org.springframework.beans.factory.support.AbstractBeanFactory$$Lambda$169) getSingleton:234, DefaultSingletonBeanRegistry (org.springframework.beans.factory.support) doGetBean:322, AbstractBeanFactory (org.springframework.beans.factory.support) getBean:202, AbstractBeanFactory (org.springframework.beans.factory.support) preInstantiateSingletons:897 DefaultListableBeanFactory (org.springframework.beans.factory.support) finishBeanFactoryInitialization:879, AbstractApplicationContext (org.springframework.context.support) refresh:551, AbstractApplicationContext (org.springframework.context.support) refresh:143, ServletWebServerApplicationContext (org.springframework.boot.web.servlet.context) refresh:758, SpringApplication (org.springframework.boot) refresh:750, SpringApplication (org.springframework.boot) refreshContext:405, SpringApplication (org.springframework.boot) run:315, SpringApplication (org.springframework.boot) run:1237, SpringApplication (org.springframework.boot) run:1226 SpringApplication (org.springframework.boot) main:14, InitApplication (com.xurk.init)
From the top down, skip the method of using sun.reflect and go to line 6.
Public void invoke (Object target) throws Throwable {ReflectionUtils.makeAccessible (this.method); this.method.invoke (target, (Object []) null);}
Obviously, a method of an object is being called through reflection, and this "some object" is the instance object of the Foo that we define.
So when is the method assigned here?
Invoke (...) The full path is:
Org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.LifecycleElement#invoke
And LifecycleElement has one and only one constructor that displays the declaration and takes parameters, and the parameter to be passed into the constructor is invoke (.) The Method object used.
The next step is to find out who is in new LifecycleElement.
So locate to:
Org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor#buildLifecycleMetadata
Private LifecycleMetadata buildLifecycleMetadata (final Class clazz) {if (! AnnotationUtils.isCandidateClass (clazz, Arrays.asList (this.initAnnotationType, this.destroyAnnotationType)) {return this.emptyLifecycleMetadata;} List initMethods = new ArrayList (); List destroyMethods = new ArrayList (); Class targetClass = clazz; do {final List currInitMethods = new ArrayList (); final List currDestroyMethods = new ArrayList () ReflectionUtils.doWithLocalMethods (targetClass, method-> {if (this.initAnnotationType! = null & & method.isAnnotationPresent (this.initAnnotationType)) {LifecycleElement element = new LifecycleElement (method); currInitMethods.add (element); if (logger.isTraceEnabled ()) {logger.trace ("Found init method on class [" + clazz.getName () + "]:" + method) }} if (this.destroyAnnotationType! = null & & method.isAnnotationPresent (this.destroyAnnotationType)) {currDestroyMethods.add (new LifecycleElement (method)); if (logger.isTraceEnabled ()) {logger.trace ("Found destroy method on class [" + clazz.getName () + "]:" + method) }); initMethods.addAll (0, currInitMethods); destroyMethods.addAll (currDestroyMethods); targetClass = targetClass.getSuperclass ();} while (targetClass! = null & & targetClass! = Object.class); return (initMethods.isEmpty () & & destroyMethods.isEmpty ()? This.emptyLifecycleMetadata: new LifecycleMetadata (clazz, initMethods, destroyMethods);}
Lines 15-26 determine whether there is a comment on the method by reflection, and if so, add it to a collection, which is finally used to build the LifecycleMetadata instance.
Here, because what we are looking for is the assigned content, all we have to do is pay attention to the write-related content when using IDE for lookup.
At this point, it is known that set is done in the constructor of CommonAnnotationBeanPostProcessor, that is, values are assigned when an instance of CommonAnnotationBeanPostProcessor is created, and CommonAnnotationBeanPostProcessor is a subclass of InitDestroyAnnotationBeanPostProcessor.
Also, the setInitAnnotationType called in the CommonAnnotationBeanPostProcessor constructor is actually the method of its parent class, which actually assigns a value to the initAnnotationType field of the instance of InitDestroyAnnotationBeanPostProcessor.
At this point, it is clear that buildLifecycleMetadata (...) It is @ PostConstruct that is judged in.
Go back to buildLifecycleMetadata (...) and see the doWithLocalMethods (...) it uses. The realization of.
Public static void doWithLocalMethods (Class clazz, MethodCallback mc) {Method [] methods = getDeclaredMethods (clazz, false); for (Method method: methods) {try {mc.doWith (method);} catch (IllegalAccessException ex) {throw new IllegalStateException ("Not allowed to access method'" + method.getName () + ":" + ex);}
Quite simply, all the methods of the class are obtained by reflection, and then the method of a function interface is called. The implementation of this function interface is to determine whether the method is marked by @ PostConstruct, and if so, put it into a collection called currInitMethods.
As you may be aware of here, @ PostConstruct can label multiple methods, and because the reflection gets the methods according to the declaration order, the currInitMethods is ArrayList, the order between the two is the same.
Well, the method annotated by @ PostConstruct has been found and put into the collection and will be used to build LifecycleMetadata instances.
BuildLifecycleMetadata (...) Method returns an LifecycleMetadata instance, which contains all the Method instances annotated by @ PostConstruct from the Class instance passed in. Next, we will see who is calling buildLifecycleMetadata (...). Method, see how it works?
Traced back to findLifecycleMetadata (...) While findLifecycleMetadata (...) Several more calls have been made.
Look at the earliest method call stack and find postProcessBeforeInitializatio (...). Who called it again?
Init:23, Foo (com.xurk.init.foo) invoke0:-1, NativeMethodAccessorImpl (sun.reflect) invoke:62, NativeMethodAccessorImpl (sun.reflect) invoke:43, DelegatingMethodAccessorImpl (sun.reflect) invoke:498, Method (java.lang.reflect) invoke:389, InitDestroyAnnotationBeanPostProcessor$LifecycleElement (org.springframework.beans.factory.annotation) invokeInitMethods:333, InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata (org.springframework.beans.factory.annotation) postProcessBeforeInitialization:157, InitDestroyAnnotationBeanPostProcessor (org.springframework.beans.factory.annotation) applyBeanPostProcessorsBeforeInitialization:415, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support) initializeBean:1786 AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
Following the method call stack, we come to
Org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization
Overridepublic 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;}
In this method, traverse the BeanPostProcessors set and execute the postProcessBeforeInitialization (...) of each BeanPostProcessor. Method.
* * so when was the content in getBeanPostProcessors () put in? What are the contents? * * it can be found through AnnotationConfigUtils and CommonAnnotationBeanPostProcessor, so I won't repeat it here.
Find applyBeanPostProcessorsBeforeInitialization (...) The caller, come to
Org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean
Protected Object initializeBean (String beanName, Object bean, @ Nullable RootBeanDefinition mbd) {if (System.getSecurityManager ()! = null) {AccessController.doPrivileged ((PrivilegedAction) ()-> {invokeAwareMethods (beanName, bean); return null;}, getAccessControlContext ());} else {invokeAwareMethods (beanName, bean);} Object wrappedBean = bean; if (mbd = = null | |! mbd.isSynthetic ()) {wrappedBean = applyBeanPostProcessorsBeforeInitialization (wrappedBean, beanName) } try {invokeInitMethods (beanName, wrappedBean, mbd);} catch (Throwable ex) {throw new BeanCreationException ((mbd! = null?) Mbd.getResourceDescription (): null), beanName, "Invocation of init method failed", ex);} if (mbd = = null | |! mbd.isSynthetic ()) {wrappedBean = applyBeanPostProcessorsAfterInitialization (wrappedBean, beanName);} return wrappedBean;}
As the name implies, Bean is initialized in this method. Is the process that you must go through before being injected, where the method execution marked by @ PostConstruct has been completed. As for who calls this method, you can check the call stack for yourself.
The call of init-method, afterPropertiesSet ()
Careful friends may have found that in initializeBean (...) There is a call to an invokeInitMethods (...) The way.
Protected void invokeInitMethods (String beanName, Object bean, @ Nullable RootBeanDefinition mbd) throws Throwable {boolean isInitializingBean = (bean instanceof InitializingBean); if (isInitializingBean & & (mbd = = null | |! mbd.isExternallyManagedInitMethod ("afterPropertiesSet")) {if (logger.isTraceEnabled ()) {logger.trace ("Invoking afterPropertiesSet () on bean with name'" + beanName + ")) } if (System.getSecurityManager ()! = null) {try {AccessController.doPrivileged ((PrivilegedExceptionAction) ()-> {((InitializingBean) bean) .afterPropertiesSet (); return null;}, getAccessControlContext ());} catch (PrivilegedActionException pae) {throw pae.getException () }} else {((InitializingBean) bean) .afterPropertiesSet ();}} if (mbd! = null & & bean.getClass ()! = NullBean.class) {String initMethodName = mbd.getInitMethodName () If (StringUtils.hasLength (initMethodName) & & (isInitializingBean & & "afterPropertiesSet" .equals (initMethodName)) & &! mbd.isExternallyManagedInitMethod (initMethodName)) {invokeCustomInitMethod (beanName, bean, mbd);}}
BeanDefinition is an abstraction defined by Bean. Similar to the existence of a Class class in Java to describe a class that contains all kinds of information about the Bean that you define.
In line 4, determine whether it is InitializingBean or not, and if so, do a type override, and then call afterPropertiesSet ().
On line 26, get the name of the custom initialization method, and then call invokeCustomInitMethod on line 30 to complete the execution.
Determine the order of protected Object initializeBean (String beanName, Object bean, @ Nullable RootBeanDefinition mbd) {if (System.getSecurityManager ()! = null) {AccessController.doPrivileged ((PrivilegedAction) ()-> {invokeAwareMethods (beanName, bean); return null;}, getAccessControlContext ());} else {invokeAwareMethods (beanName, bean);} Object wrappedBean = bean If (mbd = = null | |! mbd.isSynthetic ()) {wrappedBean = applyBeanPostProcessorsBeforeInitialization (wrappedBean, beanName);} try {invokeInitMethods (beanName, wrappedBean, mbd);} catch (Throwable ex) {throw new BeanCreationException ((mbd! = null?) Mbd.getResourceDescription (): null), beanName, "Invocation of init method failed", ex);} if (mbd = = null | |! mbd.isSynthetic ()) {wrappedBean = applyBeanPostProcessorsAfterInitialization (wrappedBean, beanName);} return wrappedBean;}
InitializeBean (...) Method, execute applyBeanPostProcessorsBeforeInitialization (...) first. Executing invokeInitMethods (...).
While applyBeanPostProcessorsBeforeInitialization (...) The method marked by @ PostConstruct, invokeInitMethods (...), is executed. AfterPropertiesSet () and the custom initialization method are executed, and afterPropertiesSet () is executed before the custom initialization method.
So the order of execution between them is:
@ PostConstruct > afterPropertiesSet () > initMethod ()
The above is all the content of the article "what is the order of @ PostConstruct, afterPropertiesSet and init-method". Thank you for reading! Hope to share the content to help you, more related knowledge, welcome to follow the industry information channel!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.