BeanPostProcessor Bean's post processor

test environment

  • JDK 1.8
  • Spring 5.2.13.RELEASE

What is the use of BeanPostProcessor

BeanPostProcessor is an extended interface provided by the Spring IOC container.

public interface BeanPostProcessor {
    
    
	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    
    
		return bean;
	}
	@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    
    
		return bean;
	}
}

Before and after Spring modifies and instantiates Beans, programmers can interfere with the generation of certain Beans.

Demo

Create three classes, namely User.java, Persion.javaand UserProcessor.java.

import org.springframework.stereotype.Component;

@Component
public class User {
    
    
    private String name;

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }
}

class Persion {
    
    
}
import org.springframework.stereotype.Component;

/**
 * 只用于BeanPostProcessor更改User返回bean类型操作
 */
@Component
public class UserProcessor {
    
    
}

Create a scan class ScanConfig.javato provide Spring scan injection Bean configuration operations.

import org.springframework.context.annotation.ComponentScan;

/**
 * 只扫描  beanPostProcessors  包下的 Bean
 */
@ComponentScan("beanPostProcessors")
public class ScanConfig {
    
    
}

Create BeanPostProcessorTest.javaand implement BeanPostProcessor 接口:

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

/**
 * 一个 BeanPostProcessor 的干扰测试类
 */
@Component
public class BeanPostProcessorTest implements BeanPostProcessor {
    
    

    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    
    
        return null;
    }

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    
    
    	// 由于两个类上加了 @Component ,为了测试区分,当发现是 UserProcessor 对象时,则将bean改掉!
        if("userProcessor".equalsIgnoreCase(beanName)){
    
    
            return new Persion();
        }
        // 其他照旧
        return null;
    }
}

Create a test class and write test code:

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Test {
    
    
    public static void main(String[] args) {
    
    
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ScanConfig.class);
        System.out.println(applicationContext.getBean("user",User.class));

        System.out.println(applicationContext.getBean("userProcessor",UserProcessor.class));
    }
}

operation result

Insert picture description here

to sum up

Since 干扰类no Userinterfering operation was caused to the generation of the class, applicationContext.getBean("user",User.class)no exception was obtained.

However, after constructing the UserProcessorinstantiated bean operation, the instantiated object of its bean is changed to new Persion(), resulting applicationContext.getBean("userProcessor",UserProcessor.class)in the type of instantiated object obtained cannot correspond!

Exception in thread "main" org.springframework.beans.factory.BeanNotOfRequiredTypeException: 
Bean named 'userProcessor' is expected to be of type 'beanPostProcessors.
UserProcessor' but was actually of type 'beanPostProcessors.Persion'

Expect to get userProcessorthe type of the bean name beanPostProcessors.UserProcessor,
but the actual type is beanPostProcessors.Persion.

Demo2 sets the value of certain properties (similar to @Value)

Customize an annotation @XJand mark it on the attribute that needs to be modified. At the same time, given the data value, get the corresponding attribute value in the test class.
Create custom annotations:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME) // 运行时生效
@Target(ElementType.FIELD) //只能用于属性上
public @interface XJ {
    
    

    String value() default "";
}

Create the class that needs to be modified:

import org.springframework.stereotype.Component;

@Component
public class User {
    
    
	
	// 添加自定义注解,并给定其值
    @XJ("xiangjiao")
    private String name;

    public void test(){
    
    
        System.out.println(name);
    }
}

Create an implementation class that affects the post-processing class of the bean in the Spring container:

package BeanPostProcessor2;

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

import java.lang.reflect.Field;

@Component
public class BeanPostProcessorVo implements BeanPostProcessor {
    
    
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    
    
        return null;
    }

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    
    
        // 当此时的bean是 User.class时
        if("user".equalsIgnoreCase(beanName)){
    
    
            // 获取class反射对象
            Class<?> clazz = bean.getClass();
            // 遍历本类其中的属性,如果是获取父类,则是 clazz.getFields()
            for (Field field : clazz.getDeclaredFields()) {
    
    
                // 如果该属性上包含  自定义注解信息
                if (field.isAnnotationPresent(XJ.class)) {
    
    
                    // 拿到注解对象
                    XJ annotation = field.getAnnotation(XJ.class);
                    // 拿到注解中设置的数据
                    String value = annotation.value();
                    // 将数据设置至属性中
                    field.setAccessible(true);
                    try {
    
    
                        field.set(bean,value);
                    } catch (IllegalAccessException e) {
    
    
                        e.printStackTrace();
                    }
                }
            }
        }
        return bean;
    }
}

Write scanning class:

package BeanPostProcessor2;

import org.springframework.context.annotation.ComponentScan;

@ComponentScan("BeanPostProcessor2")
public class ScanConfig {
    
    
}

Write the test class:

package BeanPostProcessor2;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Test {
    
    
    public static void main(String[] args) {
    
    
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ScanConfig.class);
        User user = applicationContext.getBean("user", User.class);
        user.test();
    }
}

Run log:
Insert picture description here

Code reference

github code Demo
github code Demo2

Guess you like

Origin blog.csdn.net/qq_38322527/article/details/114261896
Recommended