This is the 8th day of my participation in Gwen Challenge

Following up on the life of the Spring IoC Bean (PART 1)

1. Bean instantiation with BeanWrapper

When implemented internally, the container uses a “policy pattern” to determine how to initialize bean instances. The corresponding bean instance can usually be initialized or subclassed dynamically by reflection or CGLIB dynamic bytecode. By default, the container is CglibSubclassingInstantiationStrategy internal use. Container as long as the information obtained according to the corresponding bean definitions BeanDefinition instantiation, combining CglibSubclassingInstantiationStrategy and different type of bean definitions, you can return to instantiate an object instance. However, there are some “embellishments” in the way of return. Instead of returning the constructed object instance directly, we wrap the constructed object instance in a BeanWrapper and return the corresponding BeanWrapper instance.

This concludes the first step.

BeanWrapper interface is usually in the Spring framework for internal use, it has an implementation class org. Springframework. Beans. BeanWrapperImpl. Its purpose is to “wrap” a bean and then perform operations on the “wrapped” bean, such as setting or getting the corresponding property values of the bean. Returning the BeanWrapper instance instead of the original object instance after the first step is for the second step “setting object properties”. Using BeanWrapper is convenient for manipulating bean instances without the hassle of manipulating objects directly using the Java reflection API.

2. Various Aware interfaces

When the object is instantiated and the associated properties and dependencies are set, the Spring container checks whether the current object instance implements a set of interface definitions ending in the Aware name. If so, the dependencies specified in these Aware interface definitions are injected into the current object instance.

1. org.springframework.beans.factory.beannameaware: if the Spring container inspection to the current object implements this interface defines the object instance bean beanName Settings to the current object instance.

2. org.springframework.beans.factory.beanclassloaderaware: if the Spring container inspection to the current object implements the interface will load current corresponding bean this into the current object instance. Default will be used to load org. Springframework. Util. ClassUtils this class.

3. org.springframework.beans.factory.beanfactoryaware: if the Spring container inspection to the current object implements this interface, the BeanFactory container itself will be set to the current object instance. In this way, the current object instance has a reference to a BeanFactory container and can access objects within the container as needed.

The above interfaces are only for containers of type BeanFactory. For containers of type ApplicationContext, there are also several Aware interfaces. However, the implementation principle for detecting these interfaces and setting their dependencies is the BeanPostProcessor approach.

4. org.springframework.context.resourceloaderaware: set current ApplicationContext itself to the object instance. This gives the current object instance a reference to its ApplicationContext container.

5. org.springframework.context.applicationeventpublisheraware: ApplicationContext as a container at the same time also realized ApplicationEventPublisherAware interface, in this way, it can be used as ApplicationEventPublisher. So, if the current object implements this interface, it will inject itself into the current object.

6. org.springframework.context.messagesourceaware:applicationcontext as a container at the same time also realized the MessageSource interface to provide international support. So, if the current object implements this interface, it will inject itself into the current object.

7. org.springframework.context.applicationcontextaware: will inject itself to the current object instance.

3.BeanPostProcessor

The concepts of BeanPostProcessor and BeanFactoryPostProcessor are easily confused. But just remember that BeanPostProcessor is in the object instantiation phase, and BeanFactoryPostProcessor is in the container startup phase.

This interface declares two methods that execute at two different times, as defined in the code below:

public interface BeanPostProcessor{
    Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
    Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
Copy the code

The two methods correspond to pre-processing and post-processing respectively. Both methods of the BeanPostProcessor pass in references to the original object instance, which makes it easy to extend the behavior of the container’s object instantiation process, and we can do almost anything with the object instance passed in.

A common scenario for using BeanPostProcessor is to work with a tag interface implementation class, or to provide a proxy implementation for the current object. The Aware interfaces that ApplicationContext corresponds to in the figure above are actually handled by BeanPostProcessor. When the instantiation of each object in the ApplicationContext is preprocessed by the BeanPostProcessor, ApplicationContext containers will be detected before registration to the container ApplicationContextAwarePorcessor the BeanPostProcessor implementation class, Then call its postProcessBeforeInitialization () method, check and set up the Aware related dependency. ApplicationContextAwareProcessor postProcessorBeforeInitialization () code is as follows:

public Object postProcessBeforeInitialization(Object bean, String beanName) throw BeansException {
    if (bean instanceof ResourceLoaderAware){
        ((ResourceLoaderAware)bean).setResourceLoader(this.applicationContext);
    }
    if (bean instanceof ApplicationEventPublisherAware){
        ((ApplicationEventPublisherAware)bean).setApplicationEventPublisher(this.applicationContext);
    }
    if (bean instanceof MessageSourceAware){
        ((MessageSourceAware)bean).setMessageSource(this.applicationContext);
    }
    if (bean instanceof ApplicationContextAware){
        ((ApplicationContextAware)bean).setApplicationContext(this.applicationContext);
    }
    return bean;
}
Copy the code

In addition to checking the tag interface to apply custom logic, you can do more with the current object instance through the BeanPostProcessor. Such as replacing the current object instance or bytecode enhancement of the current object instance. Spring’s AOP makes more use of BeanPostProcessor to generate corresponding proxy objects for objects.

Here is an example of a BeanPostProcessor usage scenario: If all the IFXNewsListener implementation classes in the system need to obtain the corresponding server connection password from a certain location, and the password stored in the system is encrypted, then the IFXNewsListener sends the password to the news server for connection authentication, first needs to decrypt the obtained password in the system. We use BeanPostProcessor technology to decrypt all implementation classes of IFXNewsListener in a unified manner.

Step 1: Annotate the implementation class to be decrypted

public interface PasswordDecodable{
    String getEncodedPassword(a);
    void setDecodedPassword(String password);
}
Copy the code
public class DowJonesNewsListener implements IFXNewsListener.PasswordDecodeable{
    privateString password; .public String getEncodedPassword(a){
        return this.password;
    }
    public void setDecodedPassword(String password){
        this.password = password; }}Copy the code

Step 2: Implement the appropriate BeanPostProcessor to process the qualified Bean instances. The PasswordDecodable interface declaration is used to distinguish object instances to be processed.

public class PasswordDecodePostProcessor implements BeanPostProcessor{
    public Object postProcessAfterInitialization(Object object, String beanName) throws BeansException{
        return object;
    }
    public Object postProcessBeforeInitialization(Object object, String beanName) throws BeansException{
        if (object instanceof PasswordDecodable){
            String encodedPassword = (PasswordDecodable)object.getEncodedPassword();
            String decodedPassword = decodePassword(encodedPassword);
            (PasswordDecodable)object.setDecodedPassword(decodedPassword);
        }
        return object;
    }
    private String decodePassword(String encodedPassword){
        // Implement decoding logic.returnencodedPassword; }}Copy the code

Step 3: Register your custom BeanPostProcessor with the container

Note that there is actually a special type of BeanPostProcessor that is not mentioned, which executes at a different time than the usual BeanPostProcessor.

Org. Springframework. Beans. Factory. Config. InstantiationAwareBeanPostProcessor interface in the instantiation of objects can lead to a “short circuit” the effect is similar to the circuit. In fact, not all bean definitions registered in the Spring container instantiate that flowchart from the previous bean. Before all of the steps, the bean is instantiated object before the container will first check whether the container is registered BeanPostProcessor InstantiationAwareBeanPostProcessor type. If so, the first to use the corresponding InstantiationAwareBeanPostProcessor to construct an object instance. After the construction is successful, the constructed object instance is returned directly instead of continuing with the “normal process.” This is why it may cause a “short circuit”.

4. InitializingBean and init – method

Org. Springframework. Beans. Factory. InitializingBean is inside the container is widely using the life cycle of an object identifier of the interface, which are defined as follows:

public interface InitializingBean{
    void afterPropertiesSet(a) throws Exception;
}
Copy the code

This interface is very simple to define. The purpose of this interface is to check whether the current object implements the InitializingBean interface after the object instantiation process has called “preprocessing by BeanPostProcessor”. If so, Its afterPropertiesSet() method is called to further adjust the state of the object instance.

Although this interface is widely used within Spring, it would seem intrusive to actually have our business objects implement it. So, Spring also provides another way to specify custom object initialization operations, using the init-method property of

during XML configuration.

5. DisposableBean and destroy – method

In parallel with the InitializingBean and init-Method used for custom initialization of objects, DisposableBean and Destroy-Method provide the object with the opportunity to perform custom destruction logic. The most common use of this feature is to register a database connection pool in the Spring container, which should be closed after the system exits to free resources.

However, these custom object destruction logic are not executed immediately after the object instance has been initialized and the associated callback methods have been registered. Once the callback method is registered, the returned object instance is in use, and the associated custom destruction logic is performed only if the object instance is no longer in use. So, we need to tell the container at what point in time to execute the custom destruction method of the object.

For the BeanFactory container, we need to call destroySingletons() provided by ConfigurableBeanFactory to destroy all instances of singleton-type objects managed in the container before the independent application’s main program exits. If destroySingletons() cannot be called at the appropriate time, then all object instances that have implemented the DisposableBean interface, or beans that have declared destroy-method to define their corresponding object instances, their custom object destruction logic will be null and void, and will not be executed at all!

The same is true for the ApplicationContext container. But AbstractApplicationContext provides us with registerShutdownHook () method, the method using standard at the bottom of the Runtime class of addShutdownHook () method to invoke the corresponding bean object destruction of logic, This ensures that the custom destruction logic for these instances of singleton-type bean objects will be executed before the Java VIRTUAL machine exits.

At this point, the bean has finished its “glorious” life in the container.