Spring container overview

Overview of the Spring Container

  • Container overview
    • BeanFactory
    • ApplicationContext
  • BeanFactory
    • Attributes & amp; Method Introduction
      • FACTORY_BEAN_PREFIX
      • getBean
      • getBeanProvider
        • ObjectFactory
        • [Java SPI (Service Provider Interface) mechanism](https://blog.csdn.net/CHENFU_ZKK/article/details/130828504)
        • ObjectProvider
      • containsBean
      • isSingleton
      • isPrototype
      • isTypeMatch
      • getType
      • getAliases
  • secondary interface
    • HierarchicalBeanFactory
    • Autowire CapableBeanFactory
    • ListableBeanFactory
  • quote

Container overview

Container overview The Ioc container in Spring can be roughly divided into two types:

  • BeanFactory
  • ApplicationContext

BeanFactory

BeanFactory is the most basic IoC container, which provides the basic functions required by an IoC container. XmlBeanFactory is one of its implementations.

BeanFactory adopts the lazy initialization strategy by default, that is, when the container starts, the initialization of the bean is not completed, and only when the instance of the bean is called, the initialization operation will be completed and dependency injection will be performed.

For example the following code:

XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("beans.xml"));
User user = factory. getBean(User. class);

The advantage of this design is that the container starts quickly, because there are fewer things to do.

ApplicationContext

ApplicationContext is implemented on the basis of BeanFactory. It has all the functions of BeanFactory and can be regarded as an advanced container.
ApplicationContext provides functions such as event publishing and internationalization on the basis of BeanFactory.
At the same time, there is a big difference between ApplicationContext and BeanFactory that ApplicationContext will complete the initialization of all beans when the container starts, which means that the container starts for a long time and has high requirements for system resources.

For example, the following piece of code:

ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");

BeanFactory

The inheritance diagram of BeanFactory is very large and can be viewed in IDEA

public interface BeanFactory {<!-- -->
    String FACTORY_BEAN_PREFIX = " &";
    Object getBean(String name) throws BeansException;
    <T> T getBean(String name, Class<T> requiredType) throws BeansException;
    Object getBean(String name, Object... args) throws BeansException;
    <T> T getBean(Class<T> requiredType) throws BeansException;
    <T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
    <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);
    <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);
    boolean containsBean(String name);
    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
    boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
    boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
    boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
    @Nullable
    Class<?> getType(String name) throws NoSuchBeanDefinitionException;
    @Nullable
    Class<?> getType(String name, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException;
    String[] getAliases(String name);
}

BeanFactory mainly provides some query methods related to Bean.

Introduction to Attributes & Methods

FACTORY_BEAN_PREFIX

This is the FactoryBean prefix defined

getBean

There are five getBean methods. When obtaining a bean, you can specify the name of the bean, the type of the bean, or both, which is easy to understand. There is also an args parameter in the two overloaded methods, args is the parameter needed to get the bean, if you use this method to configure parameters for the bean, you need to set the scope of the bean to prototype, which means that every time you get a bean Bean initialization is performed only when the time comes (otherwise the configured parameters will not take effect).

getBeanProvider

Used to obtain the provider of the specified Bean, you can see that it returns an ObjectProvider, which extends from ObjectFactory and has been provided since Spring 4.3.

ObjectFactory

The class is defined as follows

@FunctionalInterface
public interface ObjectFactory<T> {<!-- -->
    T getObject() throws BeansException;
}

ObjectFactory is somewhat similar to FactoryBean. The difference is that there is only one getObject method in ObjectFactory, which can return an Object instance. ObjectFactory is similar to FactoryBean, but the implementation of the latter is usually defined in the BeanFactory as an SPI instance, and the implementation of this class is usually injected into other beans as an API.

Java SPI (Service Provider Interface) mechanism

The Java SPI (Service Provider Interface) mechanism is a mechanism for realizing dynamic service registration and discovery. It allows components to be dynamically added, removed, and serviced at runtime, increasing application flexibility and scalability.

The core of the Java SPI mechanism is interface-based registration and search. When a class implements an interface, it can register itself with the corresponding service provider. The service provider is responsible for maintaining all registered implementation classes and providing a unified access point.

The Java SPI mechanism is usually used in the development of frameworks and libraries. For example, the BeanFactory and ApplicationContext interfaces in the Spring framework use the SPI mechanism to manage Bean instances. Through the SPI mechanism, we can dynamically add or remove Bean instances without modifying the original code, so as to achieve a more flexible configuration method.

In short, the Java SPI mechanism is a very powerful dynamic service registration and discovery mechanism, which can help us manage and use various components and services more conveniently.

ObjectProvider

The class is defined as follows

public interface ObjectProvider<T> extends ObjectFactory<T>, Iterable<T> {<!-- -->
    //Return the bean of the specified type, if it does not exist in the container, throw NoSuchBeanDefinitionException; if there are multiple beans of this type in the container, throw NoUniqueBeanDefinitionException
    T getObject(Object... args) throws BeansException;
    //If the bean of the specified type is registered in the container, return the bean instance, otherwise return null
    @Nullable
    T getIfAvailable() throws BeansException;
    //If there is only one bean of the specified type in the container, return the bean instance, and return null if it does not exist; if there are multiple beans of this type in the container, throw NoUniqueBeanDefinitionException
    @Nullable
    T getIfUnique() throws BeansException;
    // Provided after Spring 5.0, returns the iterator of the specified type of Bean
    @Override
    default Iterator<T> iterator() {<!-- -->
        return stream().iterator();
    }
    // convert to Stream
    default Stream<T> stream() {<!-- -->
        throw new UnsupportedOperationException("Multi element access not supported");
    }
    default Stream<T> orderedStream() {<!-- -->
        throw new UnsupportedOperationException("Ordered element access not supported");
    }
}

So what is it good for?
Starting from Spring 4.3, when injecting xxxDao into xxxService, if the construction method has only one parameter, you don’t need to add @Autowired annotation, but if xxxDao is null, it will cause xxxService initialization failure, which can be solved by ObjectProvider:

@Service
public class UserService {<!-- -->
    private UserDao userDao;

    public UserService(ObjectProvider<UserDao> userDao) {<!-- -->
        this.userDao = userDao.getIfUnique();
    }

    @Override
    public String toString() {<!-- -->
        return "UserService{" +
                "userDao=" + userDao +
                '}';
    }
}

containsBean

Determine whether a bean is contained in the container.

isSingleton

Determine whether a Bean is a singleton.

isPrototype

Determine whether a Bean is a prototype.

isTypeMatch

Returns whether a bean with the specified name matches the specified type.

getType

Returns the data type corresponding to the bean with the specified name.

getAliases

Returns the bean’s alias.

This is all the methods defined in BeanFactory. You can see that they are basically container-related query methods. Next, they will be implemented in various implementation classes of BeanFactory.

Secondary interface

As the top-level definition in the IoC container, BeanFactory does not inherit any interface, we can call it a first-level interface, and there are three interfaces directly inherited from BeanFactory, we call it a second-level interface.

HierarchicalBeanFactory

HierarchicalBeanFactory inherits from BeanFactory, defines the factory hierarchy, and extends two methods based on it:

public interface HierarchicalBeanFactory extends BeanFactory {<!-- -->
    BeanFactory getParentBeanFactory();
    boolean containsLocalBean(String name);
}
  • The getParentBeanFactory method returns the parent factory of the Bean factory, realizing factory hierarchy.
  • The containsLocalBean method determines whether the local factory contains this Bean.

HierarchicalBeanFactory has a sub-interface ConfigurableBeanFactory, ConfigurableBeanFactory interface inherits from HierarchicalBeanFactory and SingletonBeanRegistry, where SingletonBeanRegistry defines the definition and acquisition method of singleton Bean. In other words, ConfigurableBeanFactory has both factory layering and singleton processing functions. At the same time, the object obtained by getParentBeanFactory in HierarchicalBeanFactory is also configured in ConfigurableBeanFactory.

AutowireCapableBeanFactory

AutowireCapableBeanFactory inherits from BeanFactory, which extends the functionality of autowiring.

This interface inherits from BeanFactory. On the basis of BeanFactory, it provides operations such as Bean creation, configuration, injection, and destruction. Sometimes when we need to manually inject beans, we can consider implementing this interface. An important application of AutowireCapableBeanFactory in Spring Security is ObjectPostProcessor

public interface AutowireCapableBeanFactory extends BeanFactory {<!-- -->
    int AUTOWIRE_NO = 0;
    int AUTOWIRE_BY_NAME = 1;
    int AUTOWIRE_BY_TYPE = 2;
    int AUTOWIRE_CONSTRUCTOR = 3;
    @Deprecated
    int AUTOWIRE_AUTODETECT = 4;
    String ORIGINAL_INSTANCE_SUFFIX = ".ORIGINAL";
    <T> T createBean(Class<T> beanClass) throws BeansException;
    Object createBean(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;
    void autowireBean(Object existingBean) throws BeansException;
    Object autowire(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;
    void autowireBeanProperties(Object existingBean, int autowireMode, boolean dependencyCheck) throws BeansException;
    Object configureBean(Object existingBean, String beanName) throws BeansException;
    Object initializeBean(Object existingBean, String beanName) throws BeansException;
    void applyBeanPropertyValues(Object existingBean, String beanName) throws BeansException;
    Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException;
    Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException;
    void destroyBean(Object existingBean);
    <T> NamedBeanHolder<T> resolveNamedBean(Class<T> requiredType) throws BeansException;
    Object resolveBeanByName(String name, DependencyDescriptor descriptor) throws BeansException;
    @Nullable
    Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName) throws BeansException;
    @Nullable
    Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
            @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException;
}
  • Five constants define five different assembly strategies: no autowiring, autowiring by name, autowiring by type, autowiring by constructor, and an expired constant.

  • ORIGINAL_INSTANCE_SUFFIX is the suffix agreed when initializing the given name of the instance, which will be added to the full path of the class, for example: com.mypackage.MyClass.ORIGINAL.

  • The createBean method is used to create a Bean instance;

  • The autowire* method is used to complete the automatic assembly;

  • configureBean is used to configure Bean;

  • initializeBean is used to initialize the Bean;

  • applyBeanPropertyValues applies the BeanDefinition of the specified bean to an existing Bean

  • applyBeanPostProcessorsBeforeInitialization/applyBeanPostProcessorsAfterInitialization call the Bean’s post-processor;

  • The destroyBean method is used to destroy the Bean;

  • The resolve* methods are used to resolve the Bean.

ListableBeanFactory

ListableBeanFactory inherits from BeanFactory, and this interface can list all instances that the factory can produce.

public interface ListableBeanFactory extends BeanFactory {<!-- -->
    boolean containsBeanDefinition(String beanName);
    int getBeanDefinitionCount();
    String[] getBeanDefinitionNames();
    String[] getBeanNamesForType(ResolvableType type);
    String[] getBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit);
    String[] getBeanNamesForType(@Nullable Class<?> type);
    String[] getBeanNamesForType(@Nullable Class<?> type, boolean includeNonSingletons, boolean allowEagerInit);
    <T> Map<String, T> getBeansOfType(@Nullable Class<T> type) throws BeansException;
    <T> Map<String, T> getBeansOfType(@Nullable Class<T> type, boolean includeNonSingletons, boolean allowEagerInit) throws BeansException;
    String[] getBeanNamesForAnnotation(Class<? extends Annotation> annotationType);
    Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType) throws BeansException;
    @Nullable
    <A extends Annotation> A findAnnotationOnBean(String beanName, Class<A> annotationType) throws NoSuchBeanDefinitionException;
}
  • containsBeanDefinition: Determine whether the container contains a Bean definition.
  • getBeanDefinitionCount: Get the number of BeanDefinition. getBeanDefinitionCount and
  • containsBeanDefinition has low execution efficiency and should be used with caution.
  • getBeanDefinitionNames: Get the names of all Beans.
  • getBeanNamesForType: Returns the BeanName of the specified type.
  • getBeansOfType: Returns the name and Bean Map of the specified class (multiple instances of the same type of Bean may exist).
  • getBeanNamesForAnnotation: Get the specified BeanName according to the annotation.
  • getBeansWithAnnotation: Get the specified BeanName and Bean Map according to the annotation.
  • findAnnotationOnBean: Find the specified bean according to the specified beanName and annotation type.

ListableBeanFactory has an implementation interface ConfigurableListableBeanFactory, which is a master of the interfaces introduced above. ConfigurableListableBeanFactory inherits from ListableBeanFactory, AutowireCapableBeanFactory and ConfigurableBeanFactory. It can be seen that the functions of the three secondary interfaces are integrated, and it includes all the current methods of the BeanFactory system. These methods are implemented in DefaultListableBeanFactory.

Cite

  1. Container overview of Spring source code series