测试环境
- JDK 1.8
- Spring 5.2.13.RELEASE
BeanPostProcessor 有什么用
BeanPostProcessor是Spring IOC容器给我们提供的一个扩展接口。
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;
}
}
在Spring针对Bean做修饰和实例化前后,可供程序员对某些Bean的生成做干扰操作。
Demo
创建三个类,分别是User.java
、Persion.java
和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 {
}
创建扫描类ScanConfig.java
,提供Spring扫描注入Bean的配置操作。
import org.springframework.context.annotation.ComponentScan;
/**
* 只扫描 beanPostProcessors 包下的 Bean
*/
@ComponentScan("beanPostProcessors")
public class ScanConfig {
}
创建BeanPostProcessorTest.java
,实现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;
}
}
创建测试类,编写测试代码:
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));
}
}
运行结果
总结
由于干扰类
并未对User
类的生成造成干扰操作,所以获取applicationContext.getBean("user",User.class)
无异常。
但是在构建UserProcessor
实例化bean操作后,将其bean的实例化对象更改为new Persion()
,导致applicationContext.getBean("userProcessor",UserProcessor.class)
获取到的实例化对象的类型无法对应!
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'
期待获取bean名称为
userProcessor
的类型为beanPostProcessors.UserProcessor
,
但其实际类型却是beanPostProcessors.Persion
。
Demo2 设置某些属性的值(类似 @Value)
自定义一个注解@XJ
,标注至需要修饰的属性上,同时给定数据值,在测试类中获取对应的属性值。
创建自定义注解:
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 "";
}
创建需要修饰的类:
import org.springframework.stereotype.Component;
@Component
public class User {
// 添加自定义注解,并给定其值
@XJ("xiangjiao")
private String name;
public void test(){
System.out.println(name);
}
}
创建影响Spring容器中bean的后置处理类的实现类:
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;
}
}
编写扫描类:
package BeanPostProcessor2;
import org.springframework.context.annotation.ComponentScan;
@ComponentScan("BeanPostProcessor2")
public class ScanConfig {
}
编写测试类:
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();
}
}
运行日志: