Initialization of Spring----- refresh()

Initialization of Spring

Surprisingly, Spring is no stranger to the core framework in Java, a point that interviewers often ask, and the source code is also the most beautiful framework. The core is IOC and AOP. IOC is simply a container that manages everything together. AOP is dynamic and adds some enhancements when you execute the methods in these beans. Spring is also powerful because of its compatibility, where containers are an important process for loading beans when they are initialized.

There are several ways to initialize Spring IOC

  • ClassPathXmlApplicationContext Class Path Load
ApplicationContext act = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
  • FileSystemXmlApplicationContext File System Load
ApplicationContext act = new FileSystemXmlApplicationContext("src/main/resources/applicationContext.xml");
  • AnnotationConfigApplicationContext Annotation Scan Get
ApplicationContext ioc =
		new AnnotationConfigApplicationContext("com.itcast.pojo");
  • GenericGroovyApplicationContext Gets Metadata from Groovy
		GenericGroovyApplicationContext context = new GenericGroovyApplicationContext("SpringConfig.groovy");

Get based on XML configuration, annotation scan, Groovy

Method of Initializing Containers

Each class point that gets into the container comes to the same method, this.refresh(); This method is the core of initialization

public AnnotationConfigApplicationContext(String... basePackages) {
        this();
        this.scan(basePackages);
        this.refresh();
    }

We'll follow up

public void refresh() throws BeansException, IllegalStateException {
        synchronized(this.startupShutdownMonitor) {
            this.prepareRefresh(); // 1.
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory(); // 2. 
            this.prepareBeanFactory(beanFactory); // 3. 

            try {
                this.postProcessBeanFactory(beanFactory);  // 4. 
                this.invokeBeanFactoryPostProcessors(beanFactory); // 5. 
                this.registerBeanPostProcessors(beanFactory);  // 6.
                this.initMessageSource();  // 7.
                this.initApplicationEventMulticaster(); // 8.
                this.onRefresh();   // 9 .
                this.registerListeners();  // 10.
                this.finishBeanFactoryInitialization(beanFactory); // 11. 
                this.finishRefresh();  //11.
            } catch (BeansException var9) {
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
                }

                this.destroyBeans();
                this.cancelRefresh(var9);
                throw var9;
            } finally {
                this.resetCommonCaches();
            }

        }
    }

Next we'll dissect what we've done for each method

1. prepareRefresh()

protected void prepareRefresh() {
        this.startupDate = System.currentTimeMillis();
        this.closed.set(false);
        this.active.set(true);
        if (this.logger.isDebugEnabled()) {
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Refreshing " + this);
            } else {
                this.logger.debug("Refreshing " + this.getDisplayName());
            }
        }

        this.initPropertySources();
        this.getEnvironment().validateRequiredProperties();
        if (this.earlyApplicationListeners == null) {
            this.earlyApplicationListeners = new LinkedHashSet(this.applicationListeners);
        } else {
            this.applicationListeners.clear();
            this.applicationListeners.addAll(this.earlyApplicationListeners);
        }

        this.earlyApplicationEvents = new LinkedHashSet();
    }

Apart from some methods of printing logs, the three most important are

  • initPropertySources(); Initialize some property settings, where empty implementations are left for subclass extensions
  • getEnvironment().validateRequiredProperties(); Create environment objects, save attribute values, check the validity of attributes, and so on
  • earlyApplicationEvents = new LinkedHashSet(); Save some early events in the container.
    To summarize:
    1. Environment object created and prepared
    2. Environment is to inject attributes or provide key-value pair information

2. obtainFreshBeanFactory()

 protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        this.refreshBeanFactory();
        return this.getBeanFactory();
    }

The simpler way to do this is to create and refresh the BeanFactory and return it
refreshBeanFactory();: The implementation is implemented by GenericApplicationContext when this class is loaded
Bean factories are created in the construction method. The actual method simply refreshes the initial value, setting an id for the bean factory

this.beanFactory = new DefaultListableBeanFactory();

getBeanFactory(); Is to return this bean factory

In particular, BeanFactory is responsible for bean s creation, dependency injection and initialization
There are also many BeanFactory member variables that play an important role.

Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap(256);

This is one of the member variables, and Bean Definition is one of the most important ones that defines the characteristics, initialization, dependencies, destruction methods of beans, and so on.
To summarize:
1. This step is used to create and refresh BeanFactory
2. Bean Factory is responsible for beans creation, dependency injection and initialization
3. BeanDefinition defines Bean's characteristics, initialization, dependencies, destruction methods, and so on.
4. BeanDefinition comes from many sources, including XML, configuration classes, component scanning, and programming additions.

3. prepareBeanFactory(beanFactory)

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        beanFactory.setBeanClassLoader(this.getClassLoader());
        beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
        beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, this.getEnvironment()));
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
        beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
        beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
        beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
        beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
        beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
        beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
        beanFactory.registerResolvableDependency(ResourceLoader.class, this);
        beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
        beanFactory.registerResolvableDependency(ApplicationContext.class, this);
        beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
        if (beanFactory.containsBean("loadTimeWeaver")) {
            beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
            beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
        }

        if (!beanFactory.containsLocalBean("environment")) {
            beanFactory.registerSingleton("environment", this.getEnvironment());
        }

        if (!beanFactory.containsLocalBean("systemProperties")) {
            beanFactory.registerSingleton("systemProperties", this.getEnvironment().getSystemProperties());
        }

        if (!beanFactory.containsLocalBean("systemEnvironment")) {
            beanFactory.registerSingleton("systemEnvironment", this.getEnvironment().getSystemEnvironment());
        }

    }

This step is to pass in the object created by the Bean Factory and initialize it.

  • Set up class loader for BeanFactory, support expression parser
  • Add part of BeanPostProcessor [ApplicationContextAwareProcessor]
  • Set interface EnviromentAware to ignore automatic assembly
  • Resolve auto-assembly, we can auto-inject into any other component
  • Add BeanPostProcessor
  • Add compile-time AspectJ
  • Add some available components to Bean Factory

summary

  1. Perfect BeanFactory
  2. StandardBeanExpressionResolver to resolve SpEL
  3. ResourceEditorRegistrar registers the type converter's and applies the Enviroment of the ApplicationContext to complete the ${} resolution
  4. Special bean s refer to BeanFactory and ApplicationContext registering them through registerResolvable Dependency
  5. ApplicationContextAwareProcessor to resolve Aware interfaces

4. postProcessBeanFactory(beanFactory)

 protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    }

Provide an empty implementation, leave it to subclass extensions, use it to register new Scope s, and improve BeanFactory on the Web
This reflects the template method pattern.

5. invokeBeanFactoryPostProcessors(beanFactory)

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, this.getBeanFactoryPostProcessors());
        if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean("loadTimeWeaver")) {
            beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
            beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
        }

    }

BeanFactoryPostProcessor: The postprocessor of BeanFactory, which executes after the BeanFactory label is initialized, has two interfaces: BeanFactoryPostProcessor, BeanDefinitionRegistryPostProcessor

Execute invokeBeanFactoryPostProcessors method

  • Get all BeanDefinitionRegistryPostProcessor
    • Executes the PriorityOrdered priority interface, executes the Ordered interface, and executes the other
  • Get all BeanFactoryPostProcessor
    • Executes the PriorityOrdered priority interface, executes the Ordered interface, and executes the other

Summary:
1. beanFactory's postprocessor, acting as an extension point for beanFactory, can be used to complement and modify BeanDefinition
2. Configuration ClassPostProcessor is used to parse @ Configuration, @Import, @ Bean, @PropertyResource
3. ${} in PropertyResourcePlaceHolderConfiguration

6. registerBeanPostProcessors(beanFactory)

protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
    }
  • This step is to continue to find the bean postprocessor from the beanFactory and add it to the beanPostProcessors collection
  • The Bean's post processor, acting as an extension point for the Bean, can instantiate and initialize the Bean's dependency injection.
    • AutowiredAnnotationBeanPostProcessor features are: parse @Autowired, @Value annotation
    • CommonAnnotationBeanPostProcessor features are: resolving @Resource, @PostConstruct, @PreDestroy
    • AnnotationAwareAspectJAutoProxyCreator features:Automatically create proxy for target bean s that match the tangent

7. initMessageSource()

protected void initMessageSource() {
        ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();
        if (beanFactory.containsLocalBean("messageSource")) {
            this.messageSource = (MessageSource)beanFactory.getBean("messageSource", MessageSource.class);
            if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
                HierarchicalMessageSource hms = (HierarchicalMessageSource)this.messageSource;
                if (hms.getParentMessageSource() == null) {
                    hms.setParentMessageSource(this.getInternalParentMessageSource());
                }
            }

            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Using MessageSource [" + this.messageSource + "]");
            }
        } else {
            DelegatingMessageSource dms = new DelegatingMessageSource();
            dms.setParentMessageSource(this.getInternalParentMessageSource());
            this.messageSource = dms;
            beanFactory.registerSingleton("messageSource", this.messageSource);
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("No 'messageSource' bean, using [" + this.messageSource + "]");
            }
        }

    }
  • This step is to add messageSource members to the ApplicationContext for Internationalization
  • Go to the beanFactory to find a bean named messageSource, if not, provide an empty MessageSource implementation

8. initApplicationEventMulticaster()

protected void initApplicationEventMulticaster() {
        ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();
        if (beanFactory.containsLocalBean("applicationEventMulticaster")) {
            this.applicationEventMulticaster = (ApplicationEventMulticaster)beanFactory.getBean("applicationEventMulticaster", ApplicationEventMulticaster.class);
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
            }
        } else {
            this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
            beanFactory.registerSingleton("applicationEventMulticaster", this.applicationEventMulticaster);
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("No 'applicationEventMulticaster' bean, using [" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
            }
        }

    }
  • This step adds the event broadcaster member, applicationContextEventMulticaster, to the ApplicationContext
  • Its purpose is to publish events to listeners
  • Go to beanFactory to find a bean named applicationEventMulticaster as event broadcaster, if not, a default event broadcaster will be created
  • You can then call ApplicationContext.publishEvent (event object) to publish events

9. onRefresh()

protected void onRefresh() throws BeansException {
    }
  • This step is an empty implementation, left to subclass extensions
    • Subclasses in SpringBoot prepare the WebServer here, the embedded web container
  • Reflects the template method design pattern

10 . registerListeners()

  • This step finds the event listener in several ways and adds it to the applicationEventMulticaster
  • Event listeners, as the name implies, receive events published by event broadcasters from the following sources
    • Preprogrammed
    • Beans from containers
    • Resolution from @EventListener
  • To implement an event listener, simply implement the ApplicationListener interface by overriding the onApplicationEvent (E) method

11 .finishBeanFactoryInitialization(beanFactory)

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
        if (beanFactory.containsBean("conversionService") && beanFactory.isTypeMatch("conversionService", ConversionService.class)) {
            beanFactory.setConversionService((ConversionService)beanFactory.getBean("conversionService", ConversionService.class));
        }

        if (!beanFactory.hasEmbeddedValueResolver()) {
            beanFactory.addEmbeddedValueResolver((strVal) -> {
                return this.getEnvironment().resolvePlaceholders(strVal);
            });
        }

        String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
        String[] var3 = weaverAwareNames;
        int var4 = weaverAwareNames.length;

        for(int var5 = 0; var5 < var4; ++var5) {
            String weaverAwareName = var3[var5];
            this.getBean(weaverAwareName);
        }

        beanFactory.setTempClassLoader((ClassLoader)null);
        beanFactory.freezeConfiguration();
        beanFactory.preInstantiateSingletons();
    }
  • This step will complement the members of the beanFactory and initialize all non-delayed single beans
  • ConvrsionService is also a set of conversion mechanisms that complement the PropertyEditor
  • embeddedValueResolvers, an inline value parser, is used to parse ${} in @Value, borrowing the functionality of Environment
  • singletonObjects is the singleton pool, caching all singleton objects
    • Objects are created in three phases, each with a different bean postprocessor involved to extend functionality

12. finishRefresh()

protected void finishRefresh() {
        this.clearResourceCaches();
        this.initLifecycleProcessor();
        this.getLifecycleProcessor().onRefresh();
        this.publishEvent((ApplicationEvent)(new ContextRefreshedEvent(this)));
        LiveBeansView.registerApplicationContext(this);
    }
  • This step adds a lifecycle eProcessor member to the ApplicationContext to control the bean s in the container that need lifecycle management
  • Use it if there is a bean in the container named lifecycle eProcessor, otherwise a default life cycle manager is created
  • With the life cycle manager ready, you can
    • Calling context start triggers all start implementations of LifeCycle interface bean s
    • Calling stop of context triggers all stop implementations of LifeCycle interface bean s
  • Publish ContextRefreshed event, complete refresh execution

summary

Keywords: Java Spring Back-end Framework source code

Added by edkellett on Sun, 31 Oct 2021 22:34:23 +0200