In this article, we will focus on the functions of classes that are often seen in Spring source code. There will be some code explanations in the middle, and the specific source code for each module will be written in a later article

BeanDefinition

The BeanDefinition holds information about our Bean. XML configuration 2.@Bean 3.@Component Spring generates BeanDefinition like object storage class information for spring production beans to use after reading bean configuration information. We can also generate a bean directly using beanDefinition.

    public static void main(String[] args) {
         AnnotationConfigApplicationContext applicationContext = 
                    new AnnotationConfigApplicationContext();
         // Get the beanDefinition object
         AbstractBeanDefinition beanDefinition = 
                    BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
         // Write the bean that needs to be produced
         beanDefinition.setBeanClass(People.class);
         // Register with the Spring container
         applicationContext.registerBeanDefinition("myBean",beanDefinition);
         // Refresh the container
         applicationContext.refresh();
         / / get a bean
         System.out.println(applicationContext.getBean(People.class));
         System.out.println(applicationContext.getBean("myBean"));
    }
     
    / / the result
    //spring.bean.People@1ce92674
    //spring.bean.People@1ce92674
Copy the code

BeanDefinitionReader

As the name implies, this class reads the class configuration. It has many implementation classes, such as XmlBeanDefinitionReader, which reads mode configurations

XmlBeanDefinitionReader


      
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd" default-autowire="byName">
    <bean id="people" class="spring.bean.People"/>
</beans>
Copy the code
    public static void main(String[] args) {
      AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
      / / create beanDefinitionReader
      XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
      // Loading beans into applicationContext from an XML file returns the number of beans read
      int i = beanDefinitionReader.loadBeanDefinitions("applicationContext.xml");
      System.out.println(i);
    }
    / / the result
    / / 1
Copy the code

AnnotatedBeanDefinitionReader

Note that this class does not parse classes decorated with @beans,@Component annotations, etc. Instead, it parses the configuration of classes that need to be loaded, such as @scope, @lazy

    @Scope("prototype")
    public class People {}Copy the code
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        / / create beanDefinitionReader
        AnnotatedBeanDefinitionReader beanDefinitionReader = new AnnotatedBeanDefinitionReader(applicationContext);
        // Loading beans into applicationContext from an XML file returns the number of beans read
        beanDefinitionReader.registerBean(People.class);
        applicationContext.refresh();
        System.out.println(applicationContext.getBean("people"));
        System.out.println(applicationContext.getBean("people"));
    }
    / / the result
    // spring.bean.People@5ae50ce6
    // spring.bean.People@6f96c77

Copy the code

* people. class sets its scope to prototype. It can be seen from the result that the two People objects are really different

ClassPathBeanDefinitionScanner

Parsing @Component with package scan annotations (@bean annotations don’t bei scan)

package spring.bean;
import org.springframework.stereotype.Component;
@Component
public class People {}Copy the code
    public static void main(String[] args) {
       AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
       ClassPathBeanDefinitionScanner classPathBeanDefinitionScanner = new ClassPathBeanDefinitionScanner(applicationContext);
       classPathBeanDefinitionScanner.scan("spring.bean");
       applicationContext.refresh();
       System.out.println(applicationContext.getBean(People.class));
    }
    / / the result
    // spring.bean.People@74fe5c40
Copy the code

BeanFactory

There are many kinds of the BeanFactory in the Spring, in this paper, it is the core of the implementation class DefaultListableBeanFactory explanation DefaultListableBeanFactory realized many interface has many functions

  • AliasRegistry: Supports aliases. One name can correspond to multiple aliases
  • BeanDefinitionRegistry: You can register, save, remove, or retrieve a BeanDefinition
  • BeanFactory: You can get bean objects based on their name, type, and alias
  • SingletonBeanRegistry: Singleton beans can be registered and obtained directly
  • SimpleAliasRegistry: It is a class that implements the functionality defined in the AliasRegistry interface and supports alias functionality
  • ListableBeanFactory: To get the beanNames of all BeanDefinitions, you can get the beanNames of a type, you can get the beanNames of a type, you can get the beanNames of a type {type: Mapping of the corresponding Bean}
  • HierarchicalBeanFactory: Adds the ability to get the parent BeanFactory to the BeanFactory
  • DefaultSingletonBeanRegistry: it is a class, has realized the SingletonBeanRegistry interface, has the direct registration, obtain a singleton Bean function
  • ConfigurableBeanFactory: HierarchicalBeanFactory and SingletonBeanRegistry, Added setting the parent BeanFactory, class loader (which means you can specify a class loader to load classes), and setting Spring An EL expression parser (indicating that the BeanFactory can parse EL expressions), a type conversion service (indicating that the BeanFactory can do type conversion), a BeanPostProcessor (indicating that the BeanFactory supports a Bean’s post-processor), You can merge BeanDefinitions, you can destroy a Bean, and so on
  • The function of FactoryBeanRegistrySupport: support the FactoryBean
  • AutowireCapableBeanFactory: is it inherited the BeanFactory directly, on the basis of the BeanFactory, support in the process of creating Bean that can be carried out on the Bean automatic assembly
  • AbstractBeanFactory: Implements the ConfigurableBeanFactory interface, inherited FactoryBeanRegistrySupport, the function of the BeanFactory already very full, but not available automatic assembling and beanNames
  • ConfigurableListableBeanFactory: inherited ListableBeanFactory, AutowireCapableBeanFactory, ConfigurableBeanFactory
  • AbstractAutowireCapableBeanFactory: inherited AbstractBeanFactory, realized AutowireCapableBeanFactory, has the function of automatic assembly
  • DefaultListableBeanFactory: Inherited AbstractAutowireCapableBeanFactory, realized ConfigurableListableBeanFactory interface and BeanDefinitionRegistry interface, So DefaultListableBeanFactory function is very powerful

Through the above analysis, we can know that we can do many things by DefaultListableBeanFactory

    AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
    beanDefinition.setBeanClass(People.class);
    DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
    / / register BeanDefinition
    beanFactory.registerBeanDefinition("people", beanDefinition);
    // Register an alias
    beanFactory.registerAlias("people"."people1");
    / / register BeanPostProcessor
    beanFactory.addBeanPostProcessor(new LubanBeanPostProcessor());
    // Get the Bean object
    System.out.println(beanFactory.getBean("people1"));
    // Get beanNames by type
    System.out.println(beanFactory.getBeanNamesForType(People.class));
Copy the code

ApplicationContext

ApplicationContext is an interface that can be thought of as a special BeanFactory

  • HierarchicalBeanFactory: Has the ability to get the parent BeanFactory
  • ListableBeanFactory: Has the ability to get beanNames
  • ResourcePatternResolver: a resource loader that can fetch multiple resources (file resources, etc.) at once
  • EnvironmentCapable: Runtime environment can be obtained (runtime environment functionality is not set)
  • ApplicationEventPublisher: has the function of the broadcast events (without adding the function of the event listener)
  • MessageSource: Has internationalization capabilities

Here are two of the more important implementation classes

AnnotationConfigApplicationContext

  • ConfigurableApplicationContext: Inherited the ApplicationContext interface, increased, add event listener, add spring BeanFactoryPostProcessor, set up the Environment, to obtain ConfigurableListableBeanFactory etc. Function.
  • AbstractApplicationContext: ConfigurableApplicationContext interface is realized
  • GenericApplicationContext: Inherited AbstractApplicationContext, realized BeanDefinitionRegistry interface, has the function of all ApplicationContext, and can be registered BeanDefinition, Note that this class has an attribute (DefaultListableBeanFactory the beanFactory)
  • AnnotationConfigRegistry: You can individually register a class as BeanDefinition (processing @Configuration annotations on that class, processing @Bean annotations) and scan it.
  • AnnotationConfigApplicationContext: inherited GenericApplicationContext, realized AnnotationConfigRegistry interface, has the function of all of the above.

ClassPathXmlApplicationContext

It is also inherited AbstractApplicationContext, but relative to the AnnotationConfigApplicationContext, no AnnotationConfigApplicationContext powerful, For example, BeanDefinition can’t be registered

internationalization

Define a MessageSource

    @Bean
    public MessageSource messageSource(a) {
        ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
        // Set the language configuration file prefix such as messages-en_cn and messages-en
        messageSource.setBasename("messages");
        return messageSource;
    }
Copy the code

use

    // Outputs the information in the corresponding language configuration file
    annotationConfigApplicationContext.getMessage("test".null.new Locale("en_CN"))
Copy the code

Resource to load

ApplicationContext also has resource loading capabilities. For example, you can use ApplicationContext directly to retrieve the contents of a file

    
    Resource resource = annotationConfigApplicationContext.getResource("file://D:\\IdeaProjects\\spring-framework\\zzf\\src\\main\\java\\com\\zzf\\entity\\People.java");
    System.out.println(resource.contentLength());

  
Copy the code

The classpath to obtain

    Resource resource = annotationConfigApplicationContext.getResource("classpath:com/zzf/entity/People.class");
    System.out.println(resource.contentLength());
Copy the code

Get multiple at once

    Resource[] resources = annotationConfigApplicationContext.getResources("classpath:com/zzf/service/*.class");
    for (Resource resource : resources) {
        System.out.println(resource.contentLength());
    }
Copy the code

Get the runtime environment

    // Get the operating system environment allowed by the JVM
    annotationConfigApplicationContext.getEnvironment().getSystemEnvironment();
    // Get some attributes of the JVM itself, including those set by -d
    annotationConfigApplicationContext.getEnvironment().getSystemProperties();
    // You can also get attributes directly from an environment or properties file
    annotationConfigApplicationContext.getEnvironment().getProperty("xxx")
Copy the code

Event publishing

Define an event listener

    @Bean
    public ApplicationListener applicationListener(a) {
        return new ApplicationListener() {
            @Override
            public void onApplicationEvent(ApplicationEvent event) {
                System.out.println("An event was received."); }}; }// Publish events
    annotationConfigApplicationContext.publishEvent("XXX");
Copy the code

Publish event

Type conversion

PropertyEditor

A type conversion utility class provided in the JDK

    public class StringToPeoplePropertyEditor extends PropertyEditorSupport implements PropertyEditor {
        @Override
        public void setAsText(String text) throws IllegalArgumentException {
            People people = new People();
            people.setName(text);
            this.setValue(people); }}Copy the code
    StringToPeoplePropertyEditor propertyEditor = new StringToPeoplePropertyEditor();
    propertyEditor.setAsText("1");
    People value = (People) propertyEditor.getValue();
    System.out.println(value);
Copy the code

Register PropertyEditor in Spring

        @Bean
        public CustomEditorConfigurer customEditorConfigurer(a) {
            CustomEditorConfigurer customEditorConfigurer = newCustomEditorConfigurer(); Map<Class<? >, Class<? extends PropertyEditor>> propertyEditorMap =new HashMap<>();
            // Add a custom converter
            propertyEditorMap.put(People.class, StringToPeoplePropertyEditor.class);
            customEditorConfigurer.setCustomEditors(propertyEditorMap);
            return customEditorConfigurer;
        }
Copy the code
    @Component
    public class PeopleService {
        /* * sets "true" to the name of people */
        @Value("true")
        People test;
    
        public void test(a) { System.out.println(test); }}Copy the code

ConversionService

A type conversion service provided in Spring, which is more powerful than PropertyEditor

    // Define the converter
    public class StringToPeopleConverter implements ConditionalGenericConverter {
    
        @Override
        public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
            return sourceType.getType().equals(String.class) && targetType.getType().equals(People.class);
        }
    
        @Override
        public Set<ConvertiblePair> getConvertibleTypes(a) {
            return Collections.singleton(new ConvertiblePair(String.class, People.class));
        }
    
        @Override
        public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
            People people = new People();
            people.setName((String)source);
            returnpeople; }}Copy the code
    // Normal use
    DefaultConversionService conversionService = new DefaultConversionService();
    conversionService.addConverter(new StringToPeopleConverter());
    People value = conversionService.convert("1", People.class);
    System.out.println(value);
Copy the code

Inject ConversionService into Spring

    @Bean
    public ConversionServiceFactoryBean conversionService(a) {
        ConversionServiceFactoryBean conversionServiceFactoryBean = new ConversionServiceFactoryBean();
        conversionServiceFactoryBean.setConverters(Collections.singleton(new StringToPeopleConverter()));
        return conversionServiceFactoryBean;
    }
Copy the code

TypeConverter

Integrates the functions of PropertyEditor and ConversionService for internal use in Spring

    SimpleTypeConverter typeConverter = new SimpleTypeConverter();
    typeConverter.registerCustomEditor(People.class, new StringToPeoplePropertyEditor());
    People value = typeConverter.convertIfNecessary("1", People.class);
    System.out.println(value);
Copy the code

BeanPostProcessor

The Bean’s post-processor, which can interfere with the creation of each Bean, is a property of the BeanFactory, as detailed in the Bean lifecycle article.

BeanFactoryPostProcessor

The Bean factory’s post-handler is a property that belongs to the ApplicationContext. After the ApplicationContext instantiates a BeanFactory, You can use BeanFactoryPostProcessor to continue processing the BeanFactory. The BeanFactory can be set indirectly by the BeanFactoryPostProcessor. For example, CustomEditorConfigurer is a BeanFactoryPostProcessor. It allows you to add a custom PropertyEditor to the BeanFactory.

FactoryBean

Allows programmers to customize an object to become a Bean by placing it indirectly into the Spring container via FactoryBean. So what’s the difference between it and @bean? Because @bean can also customize an object to be a Bean. The difference is that FactoryBean is much more powerful, because you can implement other interfaces in Spring by defining an XxFactoryBean class. For example, if you implement the BeanFactoryAware interface, So you can get the Bean factory in your XxFactoryBean and do more with the Bean factory than you can with @bean.