Spring Processor 是什么?

本文内容如有错误、不足之处,欢迎技术爱好者们一同探讨,在本文下面讨论区留言,感谢。

简述

Processor 中文翻译:处理器、加工机,这里 Processor 只是一种实现类描述其功能具有处理能力。

Spring 中,有两个核心 Processor 接口:BeanPostProcessorBeanFactoryPostProcessor ;
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 没有什么原理,主要原理就是这个翻译上:处理机、加工机。
下面介绍一下 SpringSpring Boot 中的核心 Processor 类的原理,帮助理解 Spring 的设计思路。

Spring 中的 Processor

Spring 设计时考虑的设计模式的开闭原则,因此提供了大量的扩展接口,其中就有 BeanPostProcessorBeanFactoryPostProcessor

作用:

  • BeanPostProcessor : 对容器中的 Bean 进行后处理,增强 Bean 的功能
  • BeanFactoryPostProcessor :对 Spring 容器本身进行后处理,增强容器的功能

区别:

  1. BeanPostProcessor 执行顺序在 BeanFactoryPostProcessor 之后
  2. BeanPostProcessorSpring 容器加载 Bean 的定义文件并且实例化 Bean 之后,在容器执行 InitializingBean 之前执行的。
  3. BeanFactoryPostProcessorSpring 容器加载 Bean 的定义文件之后,在执行 Bean 实例化之前执行的。

BeanFactoryPostProcessor 流程图如下:

Spring 容器加载 Bean 的定义文件
执行 BeanFactoryPostProcessor
执行 Bean 实例化

BeanPostProcessor 流程图如下

Spring IOC 容器 实例化
调用 BeanPostProcessor#postProcessBeforeInitialization
InitializingBean 初始化
执行调用 BeanPostProcessor#postProcessAfterInitialization

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环境

注意

  1. 实现 EnvironmentPostProcessor 接口的同时需要实现 Ordered 排序接口,也可以实现 PriorityOrdered 接口。
  2. 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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章