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