Spring framework IOC ApplicationContext

  From the perspective of UML relationship, ApplicationContext and BeanFactory have both inheritance relationship and association relationship

stay As mentioned in, many ApplicationContext implementations refer to a DefaultListableBeanFactory object and delegate bean management operations to it. The following is a code excerpted from GenericApplicationContext and its parent class, mainly to let you feel its relationship with DefaultListableBeanFactory

public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {

	private final DefaultListableBeanFactory beanFactory;

    public GenericApplicationContext() {
		this.beanFactory = new DefaultListableBeanFactory();
	}

	public GenericApplicationContext(DefaultListableBeanFactory beanFactory) {
		Assert.notNull(beanFactory, "BeanFactory must not be null");
		this.beanFactory = beanFactory;
	}

    @Override
	public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {

		this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
	}

    @Override
	public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
		return this.beanFactory.getBeanDefinition(beanName);
	}

    //From parent class
	public Object getBean(String name) throws BeansException {
		assertBeanFactoryActive();
		return getBeanFactory().getBean(name);
	}

    //From parent class
    public <T> Map<String, T> getBeansOfType(@Nullable Class<T> type) throws BeansException {
		assertBeanFactoryActive();
		return getBeanFactory().getBeansOfType(type);
	}

    //From parent class
	public boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
		assertBeanFactoryActive();
		return getBeanFactory().isSingleton(name);
	}
}
    

Therefore, it can be said that ApplicationContext is based on BeanFactory. In addition, it also provides many enterprise level features. From the perspective of service object, BeanFactory serves Spring, and ApplicationContext serves developers. In almost all applications, we will directly use ApplicationContext instead of BeanFactory

We remove the part about BeanFactory from the ancestor class of ApplicationContext, and the rest is the enterprise level functional features it provides

EnvironmentCapable: there is only one getEnvironment() method, which returns an Environment object. There are a lot of Environment contents, and a single chapter will be opened later. Here is a brief introduction. The Environment integrates two key features, profiles and configuration management (both of which are configuration management in essence)

profile is used to determine whether a beanDefinition and configuration file will be loaded into the spring container. Before loading beanDefinition and configuration file, the container will determine whether the active profiles contain the profiles corresponding to the current beanDefinition and whether they can match the suffix keywords of the current configuration file. If yes, it will be loaded, otherwise it will not be loaded. Applicable to multi environment differentiated scenarios

For applications, configuration management is undoubtedly very important, including the management of properties files, jvm parameters, system environment variables, servlet context parameters and so on. Environment implements configuration management by integrating PropertySources components. PropertySources maintains a set of PropertySources. System environment variables, jvm parameters and each user-defined property file eventually correspond to a PropertySource object, and all configured reading operations will be delegated to it

ApplicationEventPublisher: provides the ability to publish events, including spring internal events and user-defined events. Spring publishes corresponding events in some key stages of container startup and shutdown, so that applications can listen to events (used together with ApplicationListener) and handle them accordingly. For example, ContextRefreshedEvent will be published in the final stage of container startup, contextcloseedevent will be published when container stops, and many applications will listen to them for initialization, resource release Gracefully close the work. In addition, it is also very simple to customize event publishing and monitoring through this mechanism, which is equivalent to saving you the workload of implementing observer mode

ResourcePatternResolver: in Resource As described in the article, it provides the ability to load resources (load a single resource or load all qualified resources in the form of wildcards)

MessageSource: provides i18n style message access

Let's look at the descendants of ApplicationContext

ConfigurableApplicationContext: it provides the ability to configure ApplicationContext to facilitate user expansion, such as addbeanfactorypost processor, addApplicationListener, setApplicationStartup, setParent. These methods are well-known and will not be explained

AbstractApplicationContext: as an abstract implementation of ApplicationContext, it implements many general logic with template method pattern, and reserves many methods to allow subclass coverage. include:

  • All methods inherited from the beanfactory system (all delegated to the beanfactory reference held by the subclass, which is usually DefaultListableBeanFactory),
  • The methods corresponding to the above enterprise level features, such as publishevent (publishing events in the form of broadcast through applicationeventmulticast) and getresources (using pathmatching resourcepatternresolver, you can load any resource that meets the wildcard)
  • The container startup method refresh is very important and contains a lot of content. A single chapter will be opened later

AbstractApplicationContext subclass is divided into two factions: whether it is refreshable or not. Refreshable indicates that it supports repeated calls to refresh (container startup) methods. Each refresh will gracefully destroy the old BeanFactory and replace it with a new BeanFactory

//Excerpt from AbstractRefreshableApplicationContext
@Override
protected final void refreshBeanFactory() throws BeansException {
	if (hasBeanFactory()) {
		destroyBeans();
		closeBeanFactory();
	}
	try {
		DefaultListableBeanFactory beanFactory = createBeanFactory();
		beanFactory.setSerializationId(getId());
		customizeBeanFactory(beanFactory);
		loadBeanDefinitions(beanFactory);
		this.beanFactory = beanFactory;
	}
	catch (IOException ex) {
		throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
	}
}
//Excerpt from GenericApplicationContext
@Override
protected final void refreshBeanFactory() throws IllegalStateException {
	//Only one refresh is allowed through the status bit control
    if (!this.refreshed.compareAndSet(false, true)) {
		throw new IllegalStateException(
				"GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
	}
	this.beanFactory.setSerializationId(getId());
}

Regardless of whether it is refreshable or not, the three implementations of GenericXmlApplicationContext, FileSystemXmlApplicationContext and ClassPathXmlApplicationContext are similar. XmlBeanDefinitionReader is used to load beanDefinition from xml files. The difference between FileSystemXmlApplicationContext and ClassPathXmlApplicationContext is that FileSystemResource and ClassPathXmlApplicationContext are used respectively ClassPathResource represents xml resources, while GenericXmlApplicationContext is more flexible. You can construct it directly through Resource or xml path. No matter where the xml source is, it can be loaded as a Resource

public static void main(String[] args) throws IOException {
	ApplicationContext applicationContext1 = new FileSystemXmlApplicationContext("D:\\code\\spring\\spring-introduction\\src\\main\\resources\\bean.xml");
	System.out.println("applicationContext1.getBean===>" + applicationContext1.getBean("user"));

	ApplicationContext applicationContext2 = new ClassPathXmlApplicationContext("bean.xml");
	System.out.println("applicationContext2.getBean===>" + applicationContext2.getBean("user"));

	ApplicationContext applicationContext3 = new GenericXmlApplicationContext("classpath:bean.xml");
	System.out.println("applicationContext3.getBean===>" + applicationContext3.getBean("user"));

	ApplicationContext applicationContext4 = new GenericXmlApplicationContext("file:D:\\code\\spring\\spring-introduction\\src\\main\\resources\\bean.xml");
	System.out.println("applicationContext4.getBean===>" + applicationContext4.getBean("user"));

	Resource[] resources = new PathMatchingResourcePatternResolver().getResources("classpath:bean.xml");
	//Construct GenericXmlApplicationContext through Resource
	ApplicationContext applicationContext5 = new GenericXmlApplicationContext(resources);
	System.out.println("applicationContext5.getBean===>" + applicationContext5.getBean("user"));
}
##resources/demo.xml
<?xml version="1.0" encoding="UTF-8"?>
<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="user" class="com.example.spring.entity.User" >
      <property name="id" value="001"/>
      <property name="name" value="zhang san"/>
   </bean>
</beans>

AnnotationConfigApplicationContext: use Component class (usually the class annotated with @ Configuration, also supports @ Component and @ Inject annotation in JSR-330 standard) as input to load beanDefinition

@Configuration
public class AnnotationApplicationContextDemo {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AnnotationApplicationContextDemo.class);
        System.out.println(applicationContext.getBean("userName"));
    }

    @Bean
    public String userName() {
        return "bobo";
    }
}

In the actual development scenario, the java config class usually does not only contain @ Bean annotations (especially the main configuration class of the project), but also @ ComponentScan, @ PropertySource, @ Import and other annotations. In addition to the annotations on these java config classes, there are also annotations such as @ Component, @ Autowired, @ Value, @ Resource, @ Inject, @ PostConstruct, @ PreDestroy @EventListener and other annotations for common classes. The processing logic for these annotations is the core of the container startup process. Understanding these is very helpful for us to understand the IOC container

When AnnotationConfigApplicationContext is instantiated, an annotationdbeandefinitionreader instance will be created and maintained. When instantiated, the latter will call the AnnotationConfigUtils#registerAnnotationConfigProcessors method to register the postprocessors related to various annotation processing (including BeanFactoryPostProcessor and BeanPostProcessor), These postprocessors are responsible for the processing logic of the above annotations. For example, ConfigurationClassPostProcessor is responsible for @ Bean, @ ComponentScan, @ PropertySource, @ Import, which are annotations related to java config class, and AutowiredAnnotationBeanPostProcessor is responsible for @ Autowired, @ Value, @ Inject, which are annotations related to dependency injection

Tags: Spring

Posted on Wed, 01 Dec 2021 14:17:34 -0500 by jtmathome