Spring classic extended interface application: BeanPostProcessor

Note: A new summary of basic ideas will be completed in April and May.

1. Summary of basic knowledge of BeanPostProcessor

BeanPostProcessor is a bean-level processor that is used to customize bean instances after bean instantiation and initialization, such as attribute verification, unified processing of custom beans, etc.

Two methods are defined in the BeanPostProcessor interface:

  • The postProcessBeforeInitialization method applies BeanPostProcessor to a given bean instance before any bean initialization callback (such as the afterPropertiesSet method of the InitializingBean interface, a custom initialization method), and its return value can be the bean itself or its wrapper class.

  • The postProcessAfterInitialization method is called after the bean callback initialization method.

Implementation process: registration - execution of postProcessBeforeInitialization - execution of postProcessAfterInitialization

If we want to complete bean instantiation, configuration and other initialization methods in the Spring container, we must add some own logic processing before and after. We need to define one or more BeanPostProcessor interface implementation classes and then register them in the Spring IoC container.

Illustration of the instantiation process of Bean in Spring:

 Notice:

1. Both methods in the interface must return the incoming bean and cannot return null. If null is returned, then we will not get the target through the getBean method.

2. BeanFactory and ApplicationContext treat bean post-processors slightly differently. The ApplicationContext will automatically detect all beans that implement the BeanPostProcessor interface in the configuration file, register them as post-processors, and then call it when the container creates the bean. Therefore, deploying a post-processor is not the same as deploying other beans. There is no difference. When implemented using BeanFactory, the bean post-processor must be explicitly registered through code. The registration method is defined in the ConfigurableBeanFactory interface in the IoC container inheritance system.

/**  
 * Add a new BeanPostProcessor that will get applied to beans created  
 * by this factory. To be invoked during factory configuration.  
 * <p>Note: Post-processors submitted here will be applied in the order of  
 * registration; any ordering semantics expressed through implementing the  
 * {@link org.springframework.core.Ordered} interface will be ignored. Note  
 * that autodetected post-processors (e.g. as beans in an ApplicationContext)  
 * will always be applied after programmatically registered ones.  
 * @param beanPostProcessor the post-processor to register  
 */    
void addBeanPostProcessor(BeanPostProcessor beanPostProcessor);

Also, don't mark the BeanPostProcessor as lazy initialized. Because if you do this, the Spring container will not register them and the custom logic will not be applied. If you use the 'default-lazy-init' attribute in the definition of the <beans /> element, make sure that each of your BeanPostProcessor tags is 'lazy-init="false"'.

2. Analysis of practical application of BeanPostProcessor

There are many practical application scenarios of the BeanPostProcessor interface in the Spring framework. Here are some examples:

  1. Property injection : By implementing the BeanPostProcessor interface, you can perform custom injection of Bean properties after the Bean is instantiated and before initialization. For example, you can modify or assign values ​​to the properties of the Bean in the postProcessBeforeInitialization method of BeanPostProcessor to achieve customized requirements for property injection.
  2. AOP preprocessing : You can perform AOP-related preprocessing on the Bean after the Bean is instantiated and before initialization by implementing the BeanPostProcessor interface. For example, you can dynamically generate a proxy object for the Bean in the postProcessBeforeInitialization method of BeanPostProcessor to implement AOP aspect-oriented functions.
  3. Customized initialization logic : You can implement customized initialization logic for the Bean during the Bean initialization phase by implementing the BeanPostProcessor interface. For example, you can perform some initialization operations, such as data initialization, resource loading, etc., in the postProcessAfterInitialization method of BeanPostProcessor.
  4. Data verification : You can verify the data in the Bean after the Bean is initialized by implementing the BeanPostProcessor interface. For example, you can verify the data in the Bean in the postProcessAfterInitialization method of BeanPostProcessor to ensure the legality and integrity of the data.
  5. Resource recycling : By implementing the BeanPostProcessor interface, the resources in the Bean can be recycled before the Bean is destroyed. For example, you can perform operations such as releasing and closing resources in the postProcessBeforeDestruction method of BeanPostProcessor to ensure reasonable release of resources.

It should be noted that when implementing the BeanPostProcessor interface, you need to handle the Bean life cycle carefully to avoid introducing unnecessary side effects and potential problems. When using the BeanPostProcessor interface, you should carefully consider whether you really need to customize the Bean, as well as the timing and method of processing based on specific needs.

3. Practical application display

(1) Attribute injection

By implementing the BeanPostProcessor interface, you can perform custom injection of Bean properties after the Bean is instantiated and before initialization. For example, you can modify or assign values ​​to the properties of the Bean in the postProcessBeforeInitialization method of BeanPostProcessor to achieve customized requirements for property injection.

Define MyBeanPostProcessor to implement the BeanPostProcessor interface and override two of its methods postProcessBeforeInitialization and postProcessAfterInitialization.

In the postProcessBeforeInitialization method, custom injection of attributes is performed on the MyBean type Bean, realizing the customized requirements for attribute injection (this is just a simple example, the processing logic in actual applications may be more complex, and customized processing is performed according to specific needs. .)

package org.zyf.javabasic.springextend.beanpostprocessorext;

import lombok.Data;

/**
 * @author yanfengzhang
 * @description
 * @date 2023/4/16  23:54
 */
@Data
public class MyBean {
    private String myProperty;

    public void doSomething(){
        System.out.println("MyBean.doSomething()执行,myProperty="+myProperty);
    }
}

In actual applications, MyBean can be a business object, such as a business logic implementation class, a data access object, etc., depending on your business needs. MyBean is just a placeholder. You can define and name your own Bean type according to your actual business needs and the naming convention of business objects. In actual applications, you need to replace MyBean with the class name of the business object you actually use in order to perform corresponding processing in MyBeanPostProcessor.

Configuration example

To use this custom BeanPostProcessor, you need to register it in the Spring container. There are two ways:

via configuration file

<!-- 配置文件中的注册方式 -->
<bean class="org.zyf.javabasic.springextend.beanpostprocessorext.MyBeanPostProcessor" />

Configuring classes through Java

package org.zyf.javabasic.springextend.beanpostprocessorext;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author yanfengzhang
 * @description
 * @date 2023/4/16  23:58
 */
@Configuration
public class MyAppConfig {
    @Bean
    public MyBeanPostProcessor myBeanPostProcessor() {
        return new MyBeanPostProcessor();
    }
}

Code display

package org.zyf.javabasic.springextend.beanpostprocessorext;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

/**
 * @author yanfengzhang
 * @description
 * @date 2023/4/16  23:53
 */
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // 在 Bean 初始化前的处理逻辑
        if (bean instanceof MyBean) {
            MyBean myBean = (MyBean) bean;
            // 对 MyBean 的属性进行自定义注入
            myBean.setMyProperty("自定义属性");
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        // 在 Bean 初始化后的处理逻辑
        return bean;
    }
}

In this way, the Spring container will call the postProcessBeforeInitialization method in MyBeanPostProcessor before instantiating and initializing the bean to implement custom processing of property injection. It should be noted that MyBeanPostProcessor needs to be registered as a Bean in the Spring container in order to be recognized by the Spring container and execute its logic.

Our verification code is as follows:

package org.zyf.javabasic;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.zyf.javabasic.springextend.beanpostprocessorext.MyBean;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

/**
 * 描述:启动入口类
 *
 * @author yanfengzhang
 * @date 2019-12-19 18:11
 */
@SpringBootApplication
@ComponentScan(basePackages = {"org.zyf.javabasic"})
@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
@EnableSwagger2
public class ZYFApplication {

    public static void main(String[] args) {

        ApplicationContext context = SpringApplication.run(ZYFApplication.class, args);

        // 使用 MyBean
        MyBean myBean = context.getBean(MyBean.class);
        myBean.doSomething(); // 调用 MyBean.doSomething() 方法
    }

    @Bean
    public MyBean myBean(){
        return new MyBean();
    }
}

Please pay attention to the following display in the specific return

 (2) AOP preprocessing

You can perform AOP-related preprocessing on the Bean after the Bean is instantiated and before initialization by implementing the BeanPostProcessor interface. For example, you can dynamically generate a proxy object for the Bean in the postProcessBeforeInitialization method of BeanPostProcessor to implement AOP aspect-oriented functions.

Reference links:

1. Spring Practical Series (3) - The Magical Use of BeanPostProcessor_Qinghong Piaoyu's Blog-CSDN Blog

Guess you like

Origin blog.csdn.net/xiaofeng10330111/article/details/130190804