本文内容如有错误、不足之处,欢迎技术爱好者们一同探讨,在本文下面讨论区留言,感谢。
文章目录
简述
Processor 中文翻译:处理器、加工机,这里 Processor 只是一种实现类描述其功能具有处理能力。
在 Spring 中,有两个核心 Processor 接口:BeanPostProcessor 和 BeanFactoryPostProcessor ;
在 Spring Boot 中, 有个核心 Processor 接口: EnvironmentPostProcessor;
通过阅读 Spring 源码可以学习到许多设计和类命名上的知识,不但可以帮助学习 Spring 框架,而且也可以帮助学习优秀编码习惯。
自定义Processor类
在实际开发过程中,并没有约定的一种 Processor 必然要实现的模式,它只是表示这个类的功能是有做处理一些其他功能。下面举个例子说明:
SmsProcessor.java
@Component(value = "smsProcessor")
public class SmsProcessor {
@Autowired
private JmsMessagingTemplate jmsTemplate;
@Autowired
@Qualifier("verCodeService")
private SmsSender smsSender;
public void sendSmsToQueue(Destination destination, final String message){
jmsTemplate.convertAndSend(destination, message);
}
@JmsListener(destination="sms.queue")
public void doSendSmsMessage(String text){
JSONObject jsonObject = JSON.parseObject(text);
smsSender.sendSms(jsonObject.getString("mobile") , jsonObject.getString("tplId"),jsonObject.getString("vercode"));
}
}
用来处理消息的处理类,主要功能是发送消息到队列,和从队列获取消息进行处理功能。
原理
其实,Processor 没有什么原理,主要原理就是这个翻译上:处理机、加工机。
下面介绍一下 Spring 和 Spring Boot 中的核心 Processor 类的原理,帮助理解 Spring 的设计思路。
Spring 中的 Processor
Spring 设计时考虑的设计模式的开闭原则,因此提供了大量的扩展接口,其中就有 BeanPostProcessor 和 BeanFactoryPostProcessor 。
作用:
- BeanPostProcessor : 对容器中的 Bean 进行后处理,增强 Bean 的功能
- BeanFactoryPostProcessor :对 Spring 容器本身进行后处理,增强容器的功能
区别:
- BeanPostProcessor 执行顺序在 BeanFactoryPostProcessor 之后
- BeanPostProcessor 是 Spring 容器加载 Bean 的定义文件并且实例化 Bean 之后,在容器执行 InitializingBean 之前执行的。
- BeanFactoryPostProcessor 是 Spring 容器加载 Bean 的定义文件之后,在执行 Bean 实例化之前执行的。
BeanFactoryPostProcessor 流程图如下:
BeanPostProcessor 流程图如下
BeanPostProcessor 接口源码
public interface BeanPostProcessor {
/**
* Bean 初始化执行之前
* @param bean 处理的bean实例
* @param beanName bean的名称
* @return Object bean的实例
*/
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
/**
* Bean 初始化执行之后
* @param bean 处理的bean实例
* @param beanName bean的名称
* @return Object bean的实例
*/
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
在每个 bean 加载过程中,spring 会调用所有实现 BeanPostProcessor 接口的类方法,一般实现的逻辑都是:
- 判断 bean 的类型,筛选要处理的 bean
- 针对选出的 bean 执行相应逻辑
每个实现 BeanPostProcessor 接口的类的调用顺序是通过实现 Ordered 来定义先后顺序:
Ordered 接口源码:
public interface Ordered {
int HIGHEST_PRECEDENCE = -2147483648;
int LOWEST_PRECEDENCE = 2147483647;
int getOrder();
}
在 Spring 框架中,实现的不是 Ordered 接口,而是 PriorityOrdered 接口:
public interface PriorityOrdered extends Ordered {
}
PriorityOrdered 除了继承 Ordered 接口外,没有做其他处理操作,这里是一个设计理念,通过类名来构造方便理解和维护的代码。
BeanFactoryPostProcessor 接口源码
public interface BeanFactoryPostProcessor {
/**
* 标准初始化后,修改应用上下文的内部beanFactory,根据需要进行修改,对容器进行处理。
* 修改 bean 的配置元信息
* @param beanFactory 应用上下文 bean 工厂
* @throws org.springframework.beans.BeansException Beans 异常
*/
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
实现 BeanFactoryPostProcessor 接口的类,逻辑和 BeanPostProcessor 相似,同时也是需要实现 PriorityOrdered 接口。
Spring 实现类
实现 BeanFactoryPostProcessor
序号 | 类名 | 作用 |
---|---|---|
0 | PropertyPlaceholderConfigurer | 属性占位符配置器 |
1 | PropertyOverrideConfigurer | 重写占位符配置器 |
2 | CustomAutowireConfigurer | 自定义自动装配的配置器 |
3 | AutowiredAnnotationBeanPostProcessor | 自动装配的配置器 |
4 | CustomScopeConfigurer | 自定义作用域的配置器 |
实现 BeanPostProcessor
序号 | 类名 | 作用 |
---|---|---|
0 | CommonAnnotationBeanPostProcessor | 支持@Resource注解的注入 |
1 | RequiredAnnotationBeanPostProcessor | 支持@Required注解的注入 |
2 | AutowiredAnnotationBeanPostProcessor | 支持@Autowired注解的注入 |
3 | PersistenceAnnotationBeanPostProcessor | 支持@PersistenceUnit和@PersistenceContext注解的注入 |
4 | ApplicationContextAwareProcessor | 为bean注入ApplicationContext等容器对象 |
Spring Boot 中的 Processor
使用这个进行配置文件的集中管理,而不需要每个项目都去配置配置文件,自定义属性加载和转换到 Environment 中,然后访问这些属性,这些配置是系统级别的配置,相当于容器的基础使用配置。
实现 EnvironmentPostProcessor, 自定义环境后处理类,意味着在将各种环境属性暴露给容器中的bean之前对其进行操作,例如:增加一个环境属性表示,需要特定的类(用户Bean)是否进行特定的工作(打印出用户Bean信息)。
执行时间:在 Spring 上下文构建之前执行。
EnvironmentPostProcessor 接口源码
public interface EnvironmentPostProcessor {
/**
* 处理 environment
* @param environment 需要处理的容器环境 environment
* @param application 环境所属的应用程序
*/
void postProcessEnvironment(ConfigurableEnvironment environment,
SpringApplication application);
}
Spring Boot 实现类
实现 EnvironmentPostProcessor
序号 | 类名 | 作用 |
---|---|---|
0 | CloudFoundryVcapEnvironmentPostProcessor | 云构建环境处理 |
1 | ConfigFileApplicationListener | 支持 配置文件监听 |
2 | SpringApplicationJsonEnvironmentPostProcessor | 支持 spring 应用上下文 JSON环境 |
注意:
- 实现 EnvironmentPostProcessor 接口的同时需要实现 Ordered 排序接口,也可以实现 PriorityOrdered 接口。
- EnvironmentPostProcessor 的实现类必须要在 META-INF/spring.factories 文件中去注册,并且注册的是全类名。
例子
下面的例子首先给出 Spring 框架是如何实现,然后给出自定义实现。
Spring 的例子
BeanFactoryPostProcessor
CustomScopeConfigurer.java 源码分析
public class CustomScopeConfigurer implements BeanFactoryPostProcessor, BeanClassLoaderAware, Ordered {
// 保存 scope 和 scope 对象,scope 是控制 bean 作用域的属性
@Nullable
private Map<String, Object> scopes;
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
if (this.scopes != null) {
// 迭代作用域Map
this.scopes.forEach((scopeKey, value) -> {
// 对象类型为 Scope 对象
if (value instanceof Scope) {
// 注册作用域
beanFactory.registerScope(scopeKey, (Scope)value);
} else {
Class scopeClass;
// 对象类型是类类型
if (value instanceof Class) {
scopeClass = (Class)value;
// 校验是否为 作用域类型
Assert.isAssignable(Scope.class, scopeClass, "Invalid scope class");
// 注册作用域
beanFactory.registerScope(scopeKey, (Scope)BeanUtils.instantiateClass(scopeClass));
} else {
// 对象类型不属于字符串,抛出非法论点异常
if (!(value instanceof String)) {
throw new IllegalArgumentException("Mapped value [" + value + "] for scope key [" + scopeKey + "] is not an instance of required type [" + Scope.class.getName() + "] or a corresponding Class or String value indicating a Scope implementation");
}
// 类加载对应的作用域类
scopeClass = ClassUtils.resolveClassName((String)value, this.beanClassLoader);
Assert.isAssignable(Scope.class, scopeClass, "Invalid scope class");
// 注册作用域
beanFactory.registerScope(scopeKey, (Scope)BeanUtils.instantiateClass(scopeClass));
}
}
});
}
}
}
自定义 BeanFactoryPostProcessor 类
MyBeanFactoryBean.java
public class MyBeanFactoryBean implements InitializingBean {
private String initEcho;
private String processorEcho;
public String getProcessorEcho() {
return processorEcho;
}
public void setProcessorEcho(String processorEcho) {
this.processorEcho = processorEcho;
}
public String getInitEcho() {
return initEcho;
}
public void setInitEcho(String initEcho) {
this.initEcho = initEcho;
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("调用afterPropertiesSet方法");
this.initEcho = "在初始化方法中修改之后的信息";
}
}
MyBeanFactoryPostProcessor.java
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
System.out.println("调用MyBeanFactoryPostProcessor的postProcessBeanFactory");
BeanDefinition bd = configurableListableBeanFactory.getBeanDefinition("myBeanFactoryBean");
MutablePropertyValues pv = bd.getPropertyValues();
pv.addPropertyValue("processorEcho", "在BeanFactoryPostProcessor中添加之后的信息");
}
}
测试方式,放到启动类里面进行注入和获取:
@SpringBootApplication
public class ProcessorApplication {
public static void main(String[] args) {
//启动WEB项目
SpringApplication application = new SpringApplication(ProcessorApplication.class);
ConfigurableApplicationContext context = application.run(args);
MyBeanFactoryBean bean = (MyBeanFactoryBean) context.getBean("myBeanFactoryBean");
System.out.println("===============下面输出结果============");
System.out.println("初始化信息:" + bean.getInitEcho());
System.out.println("后处理信息:" + bean.getProcessorEcho());
}
}
BeanPostProcessor
ApplicationContextAwareProcessor.java 源码分析
class ApplicationContextAwareProcessor implements BeanPostProcessor {
private final ConfigurableApplicationContext applicationContext;
private final StringValueResolver embeddedValueResolver;
public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) {
this.applicationContext = applicationContext;
this.embeddedValueResolver = new EmbeddedValueResolver(applicationContext.getBeanFactory());
}
@Nullable
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
AccessControlContext acc = null;
// 判断bean 是否为感知类,同时获取 访问控制上下文
if (System.getSecurityManager() != null && (bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware || bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware || bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
acc = this.applicationContext.getBeanFactory().getAccessControlContext();
}
if (acc != null) {
AccessController.doPrivileged(() -> {
this.invokeAwareInterfaces(bean);
return null;
}, acc);
} else {
this.invokeAwareInterfaces(bean);
}
return bean;
}
private void invokeAwareInterfaces(Object bean) {
...
}
public Object postProcessAfterInitialization(Object bean, String beanName) {
return bean;
}
}
自定义 BeanPostProcessor 类
MyBeanBean.java
@Component
public class MyBeanBean{
}
MyBeanPostProcessor.java
@Component
public class MyBeanPostProcessor implements BeanPostProcessor,PriorityOrdered {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof MyBeanBean) {
System.out.println("MyBeanBean,对象" + beanName + "调用初始化方法之前的数据: " + bean.toString());
}
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof MyBeanBean) {
System.out.println("MyBeanBean,对象" + beanName + "调用初始化方法之后的数据:" + bean.toString());
}
return bean;
}
@Override
public int getOrder() {
return 10;
}
}
执行相同的启动方式:
Spring Boot 的例子
EnvironmentPostProcessor
SpringApplicationJsonEnvironmentPostProcessor.java 源码分析
public class SpringApplicationJsonEnvironmentPostProcessor
implements EnvironmentPostProcessor, Ordered {
public static final String SPRING_APPLICATION_JSON_PROPERTY = "spring.application.json";
public static final String SPRING_APPLICATION_JSON_ENVIRONMENT_VARIABLE = "SPRING_APPLICATION_JSON";
private static final String SERVLET_ENVIRONMENT_CLASS = "org.springframework.web."
+ "context.support.StandardServletEnvironment";
public static final int DEFAULT_ORDER = Ordered.HIGHEST_PRECEDENCE + 5;
private int order = DEFAULT_ORDER;
@Override
public int getOrder() {
return this.order;
}
public void setOrder(int order) {
this.order = order;
}
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment,
SpringApplication application) {
MutablePropertySources propertySources = environment.getPropertySources();
propertySources.stream().map(JsonPropertyValue::get).filter(Objects::nonNull)
.findFirst().ifPresent((v) -> processJson(environment, v));
}
private void processJson(ConfigurableEnvironment environment,
JsonPropertyValue propertyValue) {
JsonParser parser = JsonParserFactory.getJsonParser();
Map<String, Object> map = parser.parseMap(propertyValue.getJson());
if (!map.isEmpty()) {
addJsonPropertySource(environment,
new JsonPropertySource(propertyValue, flatten(map)));
}
}
...
}
实现EnvironmentPostProcessor接口。
使用它来读取几个环境变量:
calculation_mode=GROSS
gross_calculation_tax_rate=0.15
使用后处理器以特定于应用程序的方式来公开这些内容,在这种情况下,使用自定义前缀:
com.baeldung.environmentpostprocessor.calculation.mode=GROSS
com.baeldung.environmentpostprocessor.gross.calculation.tax.rate=0.15
然后,将新属性添加到Environment中:
@Order(Ordered.LOWEST_PRECEDENCE)
public class PriceCalculationEnvironmentPostProcessor implements EnvironmentPostProcessor {
private static final Logger logger = LoggerFactory.getLogger(PriceCalculationEnvironmentPostProcessor.class);
// 测试用例环境变量名称前缀
private static final String PREFIX = "com.baeldung.environmentpostprocessor.";
// 计算模式后缀
private static final String CALCUATION_MODE = "calculation_mode";
// 计算比率后缀
private static final String GROSS_CALCULATION_TAX_RATE = "gross_calculation_tax_rate";
// 计算模式默认值
private static final String CALCUATION_MODE_DEFAULT_VALUE = "NET";
// 计算比率默认值
private static final double GROSS_CALCULATION_TAX_RATE_DEFAULT_VALUE = 0;
// 后缀集合
List<String> names = Arrays.asList(CALCUATION_MODE, GROSS_CALCULATION_TAX_RATE);
// 默认值Map
private static Map<String, Object> defaults = new LinkedHashMap<>();
static {
defaults.put(CALCUATION_MODE, CALCUATION_MODE_DEFAULT_VALUE);
defaults.put(GROSS_CALCULATION_TAX_RATE, GROSS_CALCULATION_TAX_RATE_DEFAULT_VALUE);
}
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
// 获取系统中的配置信息,相当于 system.getProperty()
// 这里调用的是 org.springframework.core.env.StandardEnvironment
// 中的 SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = “systemEnvironment”
PropertySource<?> system = environment.getPropertySources()
.get(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME);
Map<String, Object> prefixed = new LinkedHashMap<>();
if (!hasOurPriceProperties(system)) {
// 内部代码
logger.warn("System environment variables [calculation_mode,gross_calculation_tax_rate] not detected, fallback to default value [calcuation_mode={},gross_calcuation_tax_rate={}]", CALCUATION_MODE_DEFAULT_VALUE,
GROSS_CALCULATION_TAX_RATE_DEFAULT_VALUE);
prefixed = names.stream()
.collect(Collectors.toMap(this::rename, this::getDefaultValue));
// 将获取到的自定义配置信息放到环境变量中
environment.getPropertySources()
.addAfter(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, new MapPropertySource("prefixer", prefixed));
return;
}
prefixed = names.stream()
.collect(Collectors.toMap(this::rename, system::getProperty));
environment.getPropertySources()
.addAfter(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, new MapPropertySource("prefixer", prefixed));
}
要在 Spring Boot 引导过程中调用实现,需要在 META-INF/spring.factories 中注册该类:
org.springframework.boot.env.EnvironmentPostProcessor=\
com.baeldung.environmentpostprocessor.PriceCalculationEnvironmentPostProcessor
综上所述,EnvironmentPostProcessor 实现可以从不同位置加载各种格式的任意文件。此外,可以进行所需的任何转换,以使属性在环境中随时可用,以备后用。
结论
通过本文内容,认识到了 Processor 只是一个处理称呼,可以手动实现任何对象的处理逻辑,在 Spring 框架中有两个核心的 Processor 类,当然还有其他作用的其他 Processor,介绍了这两个 Processor 具体做了哪些处理帮助 Spring 框架更好工作,通过 Spring 框架如何实现,以及如何进行自定义实现来理解 Spring 的设计理念和原理。介绍了 Spring Boot框架中约定大于配置的设计理念核心处理类 EnvironmentPostProcessor 的作用是用来扩展自定义的系统参数来扩展应用。希望通过本文内容可以帮助开发人员更好的理解 Spring 的设计思路。
参考资料
Spring的后置处理器到底是怎么回事?
Spring后处理器
Spring的BeanFactoryPostProcessor和BeanPostProcessor
spring–BeanPostProcesstor
A Post-Processor for Spring Boot(Spring Boot的后处理器)
Spring BeanPostProcessor Example(pring BeanPostProcessor示例)
EnvironmentPostProcessor in Spring Boot(Spring Boot中的EnvironmentPostProcessor)
来源:CSDN
作者:feng_xiaoshi
链接:https://blog.csdn.net/feng_xiaoshi/article/details/103841919