【Spring】Bean的LifeCycle(生命周期)

菜瓜:水稻,上次說Bean的LifeCycle,還沒講完

水稻:啥?說人話?

菜瓜:spring,bean,生命周期

水稻:。。。那你真的是很棒棒哦!。。。bean生命周期的話,從BeanFactory、ApplicationContext和FactoryBean開始說起

  • 我們知道(你不一定知道)BeanFactory是Spring訪問Bean容器的根接口,源碼的註釋: “The root interface for accessing a Spring bean container.”
  • 而ApplicationContext繼承自BeanFactory,也就是說它具有BeanFactory的屬性和方法,並進一步完善(繼承其他的接口)
  • FactoryBean跟前兩個關係就不怎麼大了,它是spring提供給用戶創建bean的口子,有一些bean創建過程複雜,或者依賴第三方包等(Mybatis-Spring中),可交給用戶自己創建

菜瓜:嗯。。陷入沉思。。(欲言又止)

水稻:講理論不給代碼就是耍流氓

  • package com.vip.qc.postprocessor;
    
    import org.springframework.beans.factory.FactoryBean;
    import org.springframework.stereotype.Component;
    
    /**
     * @author QuCheng on 2020/6/15.
     */
    @Component("fb")
    public class FactoryBeanT implements FactoryBean<FactoryBeanT.CustomBean> {
    
        public FactoryBeanT() {
            System.out.println("實現FactoryBean接口的類自身被放在IOC一級緩存的容器裏面,getObject的對象是在另一個緩存對象中");
        }
    
        @Override
        public CustomBean getObject() {
            return new CustomBean();
        }
    
        @Override
        public Class<?> getObjectType() {
            return CustomBean.class;
        }
    
        static class CustomBean {
            public CustomBean() {
                System.out.println("自定義bean");
            }
        }
    }
    
    測試方法
    @Test
    public void testTransa() {
        BeanFactory context = new AnnotationConfigApplicationContext(ComponentScanD.class);
        System.out.println("factoryBean : " + context.getBean("fb"));
        System.out.println("&factoryBean : " + context.getBean("&fb"));
    }

    測試結果

      實現FactoryBean接口的類自身被放在IOC一級緩存的容器裏面,getObject的對象是在另一個緩存對象中
      自定義bean
      factoryBean : com.vip.qc.postprocessor.FactoryBeanT$CustomBean@214b199c
      &factoryBean : com.vip.qc.postprocessor.FactoryBeanT@20d3d15a

菜瓜:懂了,BeanFactory是Spring的核心–容器,ApplicationContext則是包裹容器的上下文,豐富容器的功能(資源加載,事件驅動等)。FactoryBean也是Spring擴展性的提現

水稻:WC,你這個總結提到了精髓。就是擴展性:如果BeanFactory是核心思想,那麼其他的上下文,後置處理器,還是Aware接口等等,都是為了實現擴展

菜瓜:鋪墊說完了,開始生命周期唄

水稻:這次咱們反過來先看源碼,再看實驗,再總結

  • BeanFactory源碼註釋 – 定義了實現的生命周期
  •  * @author Rod Johnson
     * @author Juergen Hoeller
     * @author Chris Beams
     * @since 13 April 2001
     * @see BeanNameAware#setBeanName
     * @see BeanClassLoaderAware#setBeanClassLoader
     * @see BeanFactoryAware#setBeanFactory
     * @see org.springframework.context.ResourceLoaderAware#setResourceLoader
     * @see org.springframework.context.ApplicationEventPublisherAware#setApplicationEventPublisher
     * @see org.springframework.context.MessageSourceAware#setMessageSource
     * @see org.springframework.context.ApplicationContextAware#setApplicationContext
     * @see org.springframework.web.context.ServletContextAware#setServletContext
     * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization
     * @see InitializingBean#afterPropertiesSet
     * @see org.springframework.beans.factory.support.RootBeanDefinition#getInitMethodName
     * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization
     * @see DisposableBean#destroy
     * @see org.springframework.beans.factory.support.RootBeanDefinition#getDestroyMethodName
     */
    public interface BeanFactory {
  • BeanFactory源碼實現類
  • public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory
    
    protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
            if (System.getSecurityManager() != null) {
                AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                    invokeAwareMethods(beanName, bean);
                    return null;
                }, getAccessControlContext());
            }
            else {
                // BeanNameAware BeanFactoryAware ...
                invokeAwareMethods(beanName, bean);
            }
    
            Object wrappedBean = bean;
            if (mbd == null || !mbd.isSynthetic()) {
                // BeanPostProcessor Before  @PostConstruct
                wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
            }
    
            try {
                // initMethod InitializingBean接口
                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()) {
                // BeanPostProcessor after
                wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
            }
    
            return wrappedBean;
        }
  • 實驗代碼
  • package com.vip.qc.postprocessor;
    
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.config.BeanDefinition;
    import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
    import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
    import org.springframework.stereotype.Component;
    
    /**
     * @author QuCheng on 2020/6/14.
     */
    @Component
    public class BeanFactoryPostProcessorT implements BeanFactoryPostProcessor {
    
        public static final String BEAN_NAME = "initializingBeanT";
    
        @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
            BeanDefinition initializingBeanT = beanFactory.getBeanDefinition(BEAN_NAME);
            System.out.println("BeanFactoryPostProcessor bean " + initializingBeanT.getBeanClassName());
        }
    }
    
    
    
    package com.vip.qc.postprocessor;
    
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.config.BeanPostProcessor;
    import org.springframework.stereotype.Component;
    
    /**
     * @author QuCheng on 2020/6/14.
     */
    @Component
    public class BeanPostProcessorT implements BeanPostProcessor {
    
        public static final String BEAN_NAMET = "initializingBeanT";
    
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            if (BEAN_NAMET.equals(beanName)) {
                InitializingBeanT processorT = ((InitializingBeanT) bean);
                System.out.println("BeanPostProcessor BeforeInitialization " + processorT);
            }
            return bean;
        }
    
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            if (BEAN_NAMET.equals(beanName)){
                InitializingBeanT processorT = ((InitializingBeanT) bean);
                System.out.println("BeanPostProcessor AfterInitialization " + processorT);
            }
            return bean;
        }
    
    }
    
    
    package com.vip.qc.postprocessor;
    
    import org.springframework.beans.factory.BeanNameAware;
    import org.springframework.beans.factory.DisposableBean;
    import org.springframework.beans.factory.InitializingBean;
    import org.springframework.stereotype.Component;
    
    import javax.annotation.PostConstruct;
    import javax.annotation.PreDestroy;
    
    /**
     * @author QuCheng on 2020/6/14.
     */
    @Component
    public class InitializingBeanT implements BeanNameAware, InitializingBean, DisposableBean {
    
        public InitializingBeanT() {
            System.out.println("init無參構造 execute");
        }
    
        @PostConstruct
        public void postConstruct() {
            System.out.println("@PostConstruct  execute");
        }
    
        @PreDestroy
        public void preDestroy() {
            System.out.println("@PreDestroy  execute");
        }
    
        @Override
        public void afterPropertiesSet() {
            System.out.println("InitializingBean afterPropertiesSet --> " + this.toString());
        }
    
        @Override
        public void setBeanName(String name) {
            System.out.println("BeanNameAware : " + name);
        }
    
        @Override
        public void destroy() {
            System.out.println("destroy");
        }
    }
    
    
    測試代碼
        @Test
        public void testLifeCycle() {
            AbstractApplicationContext applicationContext = new AnnotationConfigApplicationContext(ComponentScanD.class);
            applicationContext.close();// 這裏不關閉容器的話,註銷bean的方法會看不到打印
        }

    測試結果

      BeanFactoryPostProcessor bean com.vip.qc.postprocessor.InitializingBeanT
      init無參構造 execute
      BeanNameAware : initializingBeanT
      BeanPostProcessor BeforeInitialization com.vip.qc.postprocessor.InitializingBeanT@15bb6bea
      @PostConstruct execute
      InitializingBean afterPropertiesSet –> com.vip.qc.postprocessor.InitializingBeanT@15bb6bea
      BeanPostProcessor AfterInitialization com.vip.qc.postprocessor.InitializingBeanT@15bb6bea
      @PreDestroy execute
      destroy

菜瓜:實現什麼的不重要,接口才是爸爸呀,BeanFactory定義好了生命周期,下面的實現也只是實現罷了

水稻:哈哈,你說的對,一流的公司賣標準

菜瓜:這裏怎麼沒看到循環依賴的處理啊

水稻:是的。這裏的源碼我只截取了bean初始化完成之後的接口調用。循環依賴的處理在它前面。來來來,繼續剛

菜瓜:剛不了剛不了,你一下子搞這麼多玩意給我看,我哪看得完

水稻:您歇着,下次您什麼時候想了解我再給您說

 

總結

  • BeanFactory已經定義了整個的生命周期,子類只是負責實現,demo演示也只是為了證實。我們更應該關注更上層的東西 
  • ApplicationContext是對容器更精細化的包裝,提供了更完善的功能
  • FactoryBean是Spring擴展性的提現,可供用戶自己定義創建bean。擴展性提煉的很好

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※別再煩惱如何寫文案,掌握八大原則!

網頁設計最專業,超強功能平台可客製化

您可能也會喜歡…