テスト環境
- JDK 1.8
- 春5.2.13。リリース
BeanPostProcessorの用途は何ですか
BeanPostProcessorは、SpringIOCコンテナーによって提供される拡張インターフェースです。
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の生成を妨害する可能性があります。
デモ
すなわち、三つのクラスを作成し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'
取得できると期待
userProcessor
の種類Bean名を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();
}
}
実行ログ: