Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What is the execution sequence and principle of spring initialization method

2025-02-27 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/01 Report--

This article mainly explains "what is the execution order and principle of spring initialization method". The content of the article is simple and clear, and it is easy to learn and understand. Please follow the editor's train of thought to study and learn "what is the execution sequence and principle of spring initialization method".

The execution order of initialization methods in Spring first looks at its order / * call order init2 (PostConstruct Note)-- > afterPropertiesSet (InitializingBean API)-- > init3 (init-method configuration) * / public class Test implements InitializingBean {public void init3 () {System.out.println ("init3");} @ PostConstruct public void init2 () {System.out.println ("init2") } @ Override public void afterPropertiesSet () throws Exception {System.out.println ("afterPropertiesSet");}} configuration

Through running, we find that the order of execution is init2 (PostConstruct annotation)-> afterPropertiesSet (InitializingBean interface)-> init3 (init-method configuration). But why in this order? We can draw a conclusion by analyzing its source code.

First of all, when parsing the configuration file, when you encounter a context:annotation-config/ custom tag, you will call its custom parser. Where is this custom parser? It is configured in the spring.handlers of spring-context

Http\: / / www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler Let's go to this class to see public class ContextNamespaceHandler extends NamespaceHandlerSupport {@ Override public void init () {registerBeanDefinitionParser ("property-placeholder", new PropertyPlaceholderBeanDefinitionParser ()); registerBeanDefinitionParser ("property-override", new PropertyOverrideBeanDefinitionParser ()); registerBeanDefinitionParser ("annotation-config", new AnnotationConfigBeanDefinitionParser ()); registerBeanDefinitionParser ("component-scan", new ComponentScanBeanDefinitionParser ()) RegisterBeanDefinitionParser ("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser ()); registerBeanDefinitionParser ("spring-configured", new SpringConfiguredBeanDefinitionParser ()); registerBeanDefinitionParser ("mbean-export", new MBeanExportBeanDefinitionParser ()); registerBeanDefinitionParser ("mbean-server", new MBeanServerBeanDefinitionParser ());}} We see annotation-config

All we care about is this tag, so let's go into the AnnotationConfigBeanDefinitionParser class and look at its parse method

Public BeanDefinition parse (Element element, ParserContext parserContext) {Object source = parserContext.extractSource (element); / / Obtain bean definitions for all relevant BeanPostProcessors. Set processorDefinitions = AnnotationConfigUtils.registerAnnotationConfigProcessors (parserContext.getRegistry (), source); / / Register component for the surrounding element. CompositeComponentDefinition compDefinition = new CompositeComponentDefinition (element.getTagName (), source); parserContext.pushContainingComponent (compDefinition); / / Nest the concrete beans in the surrounding component. For (BeanDefinitionHolder processorDefinition: processorDefinitions) {parserContext.registerComponent (new BeanComponentDefinition (processorDefinition));} / / Finally register the composite component. ParserContext.popAndRegisterContainingComponent (); return null;} Let's focus on this line of code Set processorDefinitions = AnnotationConfigUtils.registerAnnotationConfigProcessors (parserContext.getRegistry (), source)

We tracked it in (omitting some code that we don't care about)

Public static Set registerAnnotationConfigProcessors (BeanDefinitionRegistry registry, Object source) {... / / Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor. If (jsr250Present & &! registry.containsBeanDefinition (COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition (CommonAnnotationBeanPostProcessor.class); def.setSource (source); beanDefs.add (registerPostProcessor (registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));}.}

A CommonAnnotationBeanPostProcessor class is registered in this method, which is the basis on which our @ PostConstruct annotation works.

During the instantiation of bean, the doCreateBean method of the AbstractAutowireCapableBeanFactory class is called, in which there is a place to call the initializeBean method

Let's look directly at the initializeBean method protected Object initializeBean (final String beanName, final Object bean, RootBeanDefinition mbd) {if (System.getSecurityManager ()! = null) {AccessController.doPrivileged (new PrivilegedAction () {@ Override public Object run () {invokeAwareMethods (beanName, bean); return null;}}, getAccessControlContext ()) } else {invokeAwareMethods (beanName, bean);} Object wrappedBean = bean; if (mbd = = null | |! mbd.isSynthetic ()) {/ / call @ PostConstruct method annotation wrappedBean = applyBeanPostProcessorsBeforeInitialization (wrappedBean, beanName); / / ①} try {/ / call afterPropertiesSet and init-method local 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;}

Take a look at the ① line first and enter the applyBeanPostProcessorsBeforeInitialization method

Public Object applyBeanPostProcessorsBeforeInitialization (Object existingBean, String beanName) throws BeansException {Object result = existingBean; for (BeanPostProcessor beanProcessor: getBeanPostProcessors ()) {result = beanProcessor.postProcessBeforeInitialization (result, beanName); if (result = = null) {return result;}} return result;}

We still remember a previously registered class CommonAnnotationBeanPostProcessor, in which this class indirectly implements the BeanPostProcessor interface, so here we will call the postProcessBeforeInitialization method of the CommonAnnotationBeanPostProcessor class, which itself does not implement this method, but its parent class InitDestroyAnnotationBeanPostProcessor implements the method of postProcessBeforeInitialization, where this method implements the method annotated with @ PostConstruct on the target class.

/ / get the method annotated with @ PostConstruct on the target class and call public Object postProcessBeforeInitialization (Object bean, String beanName) throws BeansException {LifecycleMetadata metadata = findLifecycleMetadata (bean.getClass ()); try {metadata.invokeInitMethods (bean, beanName);} catch (InvocationTargetException ex) {throw new BeanCreationException (beanName, "Invocation of init method failed", ex.getTargetException ()) } catch (Throwable ex) {throw new BeanCreationException (beanName, "Failed to invoke init method", ex);} return bean;}

Then take a look at the line of ② in the initializeBean method. First, determine whether the target class implements InitializingBean. If so, call the afterPropertiesSet method of the target class, and then call its method if init-method is configured.

Protected void invokeInitMethods (String beanName, final Object bean, RootBeanDefinition mbd) throws Throwable {/ / 1, call afterPropertiesSet method boolean isInitializingBean = (bean instanceof InitializingBean); if (isInitializingBean & & (mbd = = null | |! mbd.isExternallyManagedInitMethod ("afterPropertiesSet")) {if (logger.isDebugEnabled ()) {logger.debug ("Invoking afterPropertiesSet () on bean with name'" + beanName + ")) } if (System.getSecurityManager ()! = null) {try {AccessController.doPrivileged (new PrivilegedExceptionAction () {@ Override public Object run () throws Exception {((InitializingBean) bean) .afterPropertiesSet (); return null }, getAccessControlContext ();} catch (PrivilegedActionException pae) {throw pae.getException ();}} else {((InitializingBean) bean) .afterPropertiesSet () Calling init-method method if (mbd! = null) {String initMethodName = mbd.getInitMethodName (); if (initMethodName! = null & &! (isInitializingBean & & "afterPropertiesSet" .equals (initMethodName)) & &! mbd.isExternallyManagedInitMethod (initMethodName)) {invokeCustomInitMethod (beanName, bean, mbd);}

At this point, the parsing of the order of initialization method calls for Spring is over.

Classic example of spring loading sequence

To borrow log4j2, add a record to the database, which requires the help of thread environment variables for special fields. One of the fields needs to be inserted after the specific information is queried in the database, and the loading order is encountered with the help of the Dao layer of Spring MVC.

Solution

The reference article for the scheme for inserting log4j2 into the database:

You need to perform log insert operations (such as binding to a thread with a level of insert, logger.insert ()) with the environment variable user_info.

The solution to environment variables:

Interceptor:

@ Componentpublic class LogInterceptor implements HandlerInterceptor {/ * parameters to be recorded in log * / public static final String USER_INFO= "user_info"; @ Override public boolean preHandle (HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object arg) throws Exception {String userName = LoginContext.getCurrentUsername (); ThreadContext.put (USER_INFO, getUserInfo ()) @ Override public void afterCompletion (HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object arg, Exception exception) throws Exception {ThreadContext.remove (USER_INFO);}

URL configuration that needs to be intercepted:

@ Configurationpublic class LogConfigurer implements WebMvcConfigurer {String [] logUrl = new String [] {"/ * *",} String [] excludeUrl = new String [] {"/ * * / * .js", "/ * * / * .css", "/ * * / * .jpg", "/ * * / * .svg", "/ * * / * .woff", "/ * * / * .eot", "/ * * / * .ttf", "/ * * / * .less", "/ favicon.ico" "/ license/lackofresource", "/ error"} / * register an interceptor * * @ return HpcLogInterceptor * / @ Bean public LogInterceptor setLogBean () {return new LogInterceptor ();} @ Override public void addInterceptors (InterceptorRegistry reg) {/ / intercepted objects will enter this class to determine InterceptorRegistration registration = reg.addInterceptor (setLogBean ()) / / add paths to intercept and paths not to intercept registration.addPathPatterns (logUrl) .intercepdePathPatterns (excludeUrl);}}

The following needs to be optimized:

The problem is how to get the information. The original plan is:

Query the information from the database through Dao userDao and populate it.

The problem is that userDao cannot be injected in the @ Autowired way.

Reason:

The caller SpringBoot does not complete initialization, resulting in the dao layer being null every time it is called.

So the final approach is as follows:

@ Componentpublic class LogInterceptor implements HandlerInterceptor {/ * parameters to be recorded in log * / public static final String USER_INFO= "user_info"; @ Resource (name = "jdbcTemplate") private JdbcTemplate jdbcTemplate; @ Override public boolean preHandle (HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object arg) throws Exception {String userName = LoginContext.getCurrentUsername (); ThreadContext.put (USER_INFO, getUserInfo ()) } @ Override public void afterCompletion (HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object arg, Exception exception) throws Exception {ThreadContext.remove (USER_INFO);} public String getUserInfo (String userName) {String sqlTemplate = "select user_info from Test.test_user where user_name =?"; List userInfo= new ArrayList (); userInfo= jdbcTemplate.query (sqlTemplate, preparedStatement-> {preparedStatement.setString (1, userName)) }, new SecurityRoleDtoMapper (); if (userInfo.size () = = 0) {return Constants.HPC_NORMAL_USER;} return userInfo.get (0) } Thank you for reading, the above is the content of "what is the execution order and principle of spring initialization method". After the study of this article, I believe you have a deeper understanding of the execution sequence and principle of spring initialization method, and the specific use needs to be verified in practice. Here is, the editor will push for you more related knowledge points of the article, welcome to follow!

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.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report