If you find the content helpful, give it a thumbs up and encourage you to update 😂.

The content of this article is from “Xiao Ma Ge on Spring core Programming ideas”, the summary of notes after reading, suitable for leisure time

Patterns and types of dependency injection

Dependency injection patterns

Manual mode – Configuration or programming to schedule injection rules in advance

  • XML resource configuration meta information
  • Java annotations configure meta information, such as @AutoWired, @Resource
  • API configuration meta information

Automatic mode – The implementer provides a way to rely on automatic correlation, following built-in injection rules

  • Autowiring (automatic binding)

Type of dependency injection

Dependency injection type Example for configuring metadata
A Setter method  
The constructor
field @Autowired User user; 
methods @Autowired public void user(User user) { … } 
The callback interface class MyBean implements BeanFactoryAware { … }

Pros and cons of constructor and Setter injection

Benefits of using constructor injection:

  1. Guarantee dependency immutable (final keyword)
  2. Ensures that dependencies are not empty (saves us checking them)
  3. Ensure that the client code is fully initialized when it is returned
  4. Circular dependencies are avoided
  5. Improved code reusability

Conclusion: If you have to use a dependency, use constructor injection. Setter injection is better for optional dependencies, and constructor injection keeps the thread safe during construction

A pattern for automatic binding (Autowiring)

model instructions
no The default value, Autowiring, is not active and requires you to manually specify dependency injection objects.
byName Do a dependency lookup based on the name of the injected property as the Bean name and set the object to that property.
byType Looks up as a dependency type based on the type of the injected property and sets the object to that property.
constructor Special byType for constructor arguments.

Deferred dependency lookup, deferred dependency injection

The Bean deferred depends on the lookup interface

  • org.springframework.beans.factory.ObjectFactory
  • org.springframework.beans.factory.ObjectProvider

Bean deferred dependency injection is also one of these two:

  • Use API ObjectFactory to delay injection
  • Using API ObjectProvider to delay injection (recommended)

Qualifier injection @qualifier

  • Qualified by Bean name
  • By grouping

Post-processor that implements annotations such as @autoWired and @Resource

  • AutowiredAnnotationBeanPostProcessor
    • Handle @autowired and @Value annotations
    • In postProcessMergedBeanDefinition approach for automatic injection of meta information to encapsulate injection element information
    • Implement property and method injection in the postProcessProperties method
  • CommonAnnotationBeanostProcessor annotations (life cycle is in the implementation of)
    • (Conditional activation) handles JSR-250 annotations such as @postconstruct etc

The source of Spring beans

Depend on the source of the lookup

source Configuring metadata
Spring BeanDefinition
@Bean public User user(){… }
BeanDefinitionBuilder
singleton API implementation

The source of dependency injection

source Configuring metadata
Spring BeanDefinition
@Bean public User user(){… }
BeanDefinitionBuilder
singleton API implementation
Non-spring container-managed objects
Externalize the configuration as a source of dependency

The Spring container manages and floats objects

source Configuring metadata Life cycle management Configuring meta Information Usage scenarios
Spring BeanDefinition is is There are Dependency lookup, dependency injection
singleton is no There is no Dependency lookup, dependency injection
ResolvableDependency no no There is no Dependency injection

Spring BeanDefinition as the dependency source

  • Metadata: BeanDefinition
  • Registration:
    • Name: beandefinitionRegistration #registerBeanDefinition(String,BeanDefinition)
    • The naming: BeanDefinitionReaderUtils# registerWithGeneratedName (AbstractBeanDefinition, Be anDefinitionRegistry)
    • Configuration mode of Class: AnnotatedBeanDefinitionReader# register (Class)…
  • Type: delayed and non-delayed
  • Order: Bean life cycle order is in the order of registration
  • For example:
    • implementationImportBeanDefinitionRegistrar
    • implementationBeanDefinitionRegistryPostProcessor

Singleton as source of dependency

  • elements
    • Source: External plain Java objects (not necessarily POJOs)
    • Registration: SingletonBeanRegistry# registerSingleton
  • limit
    • No lifecycle management
    • Lazy initialization beans cannot be implemented

Non-spring container-managed objects as dependency sources

  • elements
    • Registration: ConfigurableListableBeanFactory# registerResolvableDependency
  • limit
    • No lifecycle management
    • Lazy initialization beans cannot be implemented
    • Unable to find by dependency

The difference between registerResolvableDependency and registerSingleton: If the injected type is dependencyType, the autowiredValue is injected and the relationship between the injected type and the injected value is stored in the map. This is used to solve the problem of autoroing an interface that has multiple implementation classes already in IOC because Spring does not know which implementation class to inject into it.

Externalize the configuration as a source of dependency

  • elements
    • Type: Unconventional Spring object dependency source
  • limit
    • No lifecycle management
    • Lazy initialization beans cannot be implemented
    • Unable to find by dependency

Spring relies on the process of processing

Spring dependency handling is part of dependency injection, which means that during injection we parse the dependency of the object and use reflection to perform assignment injection.

  • Entry – DefaultListableBeanFactory# resolveDependency
  • DependencyDescriptor – DependencyDescriptor
  • Since the candidate set binding processors – AutowireCandidateResolver

Bean properties of filled populateBean method will eventually go DefaultListableBeanFactory# resolveDependency method, finally will still go AbstractBeanFactory# getBean method to obtain a bean

How to solve the problem of injecting Prototype scoped beans into singleton beans

In most application scenarios, most of the beans in the container are singletons. When a singleton bean needs to collaborate with another singleton bean or a non-singleton bean needs to collaborate with another non-singleton bean, it is common to handle dependencies by defining one bean as a property of the other bean. Problems arise when beans have different life cycles. It may be that on each method call of A, it is assumed that singleton Bean A needs to use non-singleton (prototype) Bean B. The container creates singleton bean A only once, so it only has one chance to set the properties. The container cannot provide bean A with A brand new instance of Bean B every time A method call is made. The solution is to give up some control rollovers. By implementing the ApplicationContextAware interface, bean A can take the context of the container and every time Bean A needs Bean B, Request a (usually newly created) instance of Bean B by calling the getBean(“B”) method of the container context.

Use the ApplicationContextAware callback interface

public class CommandManager implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    public Object process(Map commandState) {
        // grab a new instance of the appropriate Command
        Command command = createCommand();
        // set the state on the (hopefully brand new) Command instance
        command.setState(commandState);
        return command.execute();
    }

    protected Command createCommand(a) {
        // notice the Spring API dependency!
        return this.applicationContext.getBean("command", Command.class);
    }

    public void setApplicationContext( ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext; }}Copy the code

But this approach is not desirable because the business code uses the internal Spring context, which is coupled to the Spring Framework

Methods to inject

Lookup method injection is the ability of a container to override methods on a container-managed bean and return lookup results for another named bean in the container. The lookup usually involves a prototype bean. The Spring framework dynamically generates subclasses that override this method by using bytecode generation in the CGLIB library. Method Injection conditions:

  • In order for this dynamic subclass to work, the Spring container subclass is not availablefinalModifier and override methods are also not availablefinalModification.
  • Unit testing a class with abstract methods requires that you create a subclass of that class and apply it to itabstractMethod to implement.
  • Component scanning also requires concrete methods, which require concrete classes to support.
  • A further key limitation is that lookup methods do not work with factory methods, especially in configuration classes@BeanMethod, because the container is not responsible for creating instances in this case, you cannot dynamically create run-time generated subclasses.

In a client class that contains an injected method (in this case CommandManager), the injected method is required to have the following signature:

<public|protected> [abstract] <return-type> theMethodName(no-arguments);
Copy the code

If the method is abstract, a dynamically generated subclass implements the method. Otherwise, dynamically generated subclasses override concrete methods defined in the original class. Annotated version implementation:

public abstract class CommandManager {

    public Object process(Object commandState) {
        Command command = createCommand();
        command.setState(commandState);
        return command.execute();
    }

    @Lookup("myCommand")
    protected abstract Command createCommand(a);
}
Copy the code

XML implementation:

<! --a stateful bean deployed as a prototype (non-singleton) -->
<bean id="myCommand" class="fiona.apple.AsyncCommand" scope="prototype"> <! -- inject dependencies here as required --> </bean> <! -- commandProcessor uses statefulCommandHelper --> <bean id="commandManager" class="fiona.apple.CommandManager">
    <lookup-method name="createCommand" bean="myCommand"/>
</bean>
Copy the code

The difference between a static @bean method and an instance @bean method

Set to static because of a cyclical problem with bean definitions:

  • If it is non-static, the build of the bean is handled depending on the bean declaring the class.
  • If it is static, it is removed from the implementation and becomes a bean in its own right, so you can optionally mark the bean as static if you need to initialize it or pre-initialize it.

Details in ConfigurationClassBeanDefinitionReader# loadBeanDefinitionsForBeanMethod method, as follows:

if (metadata.isStatic()) {
    // static @Bean method
    beanDef.setBeanClassName(configClass.getMetadata().getClassName());
    beanDef.setFactoryMethodName(methodName);
}
else {
    // instance @Bean method
    beanDef.setFactoryBeanName(configClass.getBeanName());
    beanDef.setUniqueFactoryMethodName(methodName);
}
Copy the code

The timing of processing of the @bean method

Details please see ConfigurationClassPostProcessor class = > ConfigurationClassParser

How do I implement dependency injection without injecting the Spring container?

To “lighten the load” on the Spring container, “manually” fine control the Bean components in Spring. Some parsers don’t need to be in the container at all. What components do you need for the container to do the injection for you, but you don’t need to put them in yourself

@Configuration
@EnableWebMvc
public class WebMvcConfig extends WebMvcConfigurerAdapter {

    @Autowired
    private ApplicationContext applicationContext;
    
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        CurrUserArgumentResolver resolver = new CurrUserArgumentResolver();
        // Use factories to inject the required components into objects outside the containerapplicationContext.getAutowireCapableBeanFactory().autowireBean(resolver); argumentResolvers.add(resolver); }}Copy the code

This posture skills is to use the AutowireCapableBeanFactory clever finished to external object can, even if he is able to not container Bean, also can free injection, the ability to use container Bean (the @autowired annotation can be used as the same ~), This approach is the least invasive.