Spring-InitializingBean接口执行初始化流程

401 阅读2分钟

InitializingBean 是Spring中一个接口、就单单一个待实现的方法

 public interface InitializingBean {
   void afterPropertiesSet() throws Exception;
 }

例子

 public class TestConfig implements InitializingBean {
     @Override
     public void afterPropertiesSet() throws Exception {
         System.out.println("bean初始化!!!");
     }
 }

applicatio.xml

 <?xml version="1.0" encoding="UTF8"?>
 <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
         https://www.springframework.org/schema/beans/spring-beans.xsd">
     <bean id="testConfig" class="com.wei.config.TestConfig"/>
 </beans>

Test.java

 public class Test {
     public static void main(String[] args) {
         ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
                 "applicationContext.xml");
     }
 }

输出结果

1645773367541.png

执行大概流程

可以看到ClassPathXmlApplicationContext构造

 public ClassPathXmlApplicationContext(
       String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
       throws BeansException {
     super(parent);
     setConfigLocations(configLocations);
     if (refresh) {
       refresh();
     }
 }

具体方法流程、对应的是方法中的方法、一个个点使用Ctrl+鼠标左键点击点进去就能看到具体实现流程、或碰到接口方法时使用Ctrl+alt+b进入到该接口方法具体的方法实现中

 refresh()->
 finishBeanFactoryInitialization(beanFactory)->
 getBean(weaverAwareName)->
 getBeanFactory().getBean(name)->
 doGetBean(name, null, null, false)->
 createBean(beanName, mbd, args)->
 doCreateBean(beanName, mbdToUse, args)->
 initializeBean(beanName, exposedObject, mbd)->
 invokeInitMethods(beanName, wrappedBean, mbd)->
 ((InitializingBean) bean).afterPropertiesSet();

最后在AbstractAutowireCapableBeanFactory类中invokeInitMethods()方法中调用了重写的afterPropertiesSet()方法!

 protected void invokeInitMethods(String beanName, final 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 + "'");
     }
     // 使用了Spring Security就走这边
     if (System.getSecurityManager() != null) {
       try {
         AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
           ((InitializingBean) bean).afterPropertiesSet();
           return null;
         }, getAccessControlContext());
       }
       catch (PrivilegedActionException pae) {
         throw pae.getException();
       }
     }
     else {
       // 这就是调用afterPropertiesSet()方法
       ((InitializingBean) bean).afterPropertiesSet();
     }
   }
   //  这块地方就是在bean中配置了init-method并指定类中的方法就会执行指定的方法
   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);
     }
   }
 }

 <bean id="testConfig" class="com.wei.config.TestConfig" init-method="testInit"/>

TestConfig.java

 public class TestConfig implements InitializingBean {
     @Override
     public void afterPropertiesSet() throws Exception {
         System.out.println("bean初始化!!!");
     }
     public void testInit(){
         System.out.println("b--***********************");
     }
 }

输出结果

1645776891195.png

如果bean不是单例的情况下初始方法会执行多遍

可以执行初始方法的几种方式

  • 实现InitializingBean接口重写afterPropertiesSet()方法

  • 在bean中指定销毁方法

    •  <bean id="testConfig" class="com.wei.config.TestConfig" init-method="cs" />
      
  • 或使用注解Bean的方式、使用ClassPathXmlApplicationContext是加载是创建不出来的bean的、要使用AnnotationConfigApplicationContext加载这个配置类

    •  @Bean(initMethod = "xx")
      

    注意的就是bean必须是单例的、否则初始方法被使用时都会执行一遍

  • 或者使用@PostConstruct标记一个方法为初始化方法、会在上面两种方法之前执行、在InitDestroyAnnotationBeanPostProcessor类中postProcessBeforeInitialization()方法中metadata.invokeInitMethods(bean, beanName);方法通过反射调用注解标注的方法!

参考:www.cnblogs.com/weiqihome/p…