本站消息

站长简介/公众号

  出租广告位,需要合作请联系站长


+关注
已关注

分类  

暂无分类

标签  

暂无标签

日期归档  

2024-11(1)

9. spring-容器: BeanPostProcessor后置处理器-入门

发布于2021-05-29 20:01     阅读(602)     评论(0)     点赞(16)     收藏(2)


本章讲spring Bean生命周期中非常重要的功能,即BeanPostProcessor后置处理器, 很多功能都依赖BeanPostProcessor实现,如AOP,Autowired,初始化方法调用等。精通BeanPostProcessor并灵活加以利用,spring 容器就学会了一大半。

既然如此重要,还是先看源码:


package org.springframework.beans.factory.config;

import org.springframework.beans.BeansException;
import org.springframework.lang.Nullable;

/**
 * Factory hook that allows for custom modification of new bean instances —
 * for example, checking for marker interfaces or wrapping beans with proxies.
 *
 * <p>Typically, post-processors that populate beans via marker interfaces
 * or the like will implement {@link #postProcessBeforeInitialization},
 * while post-processors that wrap beans with proxies will normally
 * implement {@link #postProcessAfterInitialization}.
 *
 * <h3>Registration</h3>
 * <p>An {@code ApplicationContext} can autodetect {@code BeanPostProcessor} beans
 * in its bean definitions and apply those post-processors to any beans subsequently
 * created. A plain {@code BeanFactory} allows for programmatic registration of
 * post-processors, applying them to all beans created through the bean factory.
 *
 * <h3>Ordering</h3>
 * <p>{@code BeanPostProcessor} beans that are autodetected in an
 * {@code ApplicationContext} will be ordered according to
 * {@link org.springframework.core.PriorityOrdered} and
 * {@link org.springframework.core.Ordered} semantics. In contrast,
 * {@code BeanPostProcessor} beans that are registered programmatically with a
 * {@code BeanFactory} will be applied in the order of registration; any ordering
 * semantics expressed through implementing the
 * {@code PriorityOrdered} or {@code Ordered} interface will be ignored for
 * programmatically registered post-processors. Furthermore, the
 * {@link org.springframework.core.annotation.Order @Order} annotation is not
 * taken into account for {@code BeanPostProcessor} beans.
 *
 * @author Juergen Hoeller
 * @author Sam Brannen
 * @since 10.10.2003
 * @see InstantiationAwareBeanPostProcessor
 * @see DestructionAwareBeanPostProcessor
 * @see ConfigurableBeanFactory#addBeanPostProcessor
 * @see BeanFactoryPostProcessor
 */
public interface BeanPostProcessor {

	/**
	 * Apply this {@code BeanPostProcessor} to the given new bean instance <i>before</i> any bean
	 * initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
	 * or a custom init-method). The bean will already be populated with property values.
	 * The returned bean instance may be a wrapper around the original.
	 * <p>The default implementation returns the given {@code bean} as-is.
	 * @param bean the new bean instance
	 * @param beanName the name of the bean
	 * @return the bean instance to use, either the original or a wrapped one;
	 * if {@code null}, no subsequent BeanPostProcessors will be invoked
	 * @throws org.springframework.beans.BeansException in case of errors
	 * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
	 */
	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

	/**
	 * Apply this {@code BeanPostProcessor} to the given new bean instance <i>after</i> any bean
	 * initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
	 * or a custom init-method). The bean will already be populated with property values.
	 * The returned bean instance may be a wrapper around the original.
	 * <p>In case of a FactoryBean, this callback will be invoked for both the FactoryBean
	 * instance and the objects created by the FactoryBean (as of Spring 2.0). The
	 * post-processor can decide whether to apply to either the FactoryBean or created
	 * objects or both through corresponding {@code bean instanceof FactoryBean} checks.
	 * <p>This callback will also be invoked after a short-circuiting triggered by a
	 * {@link InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation} method,
	 * in contrast to all other {@code BeanPostProcessor} callbacks.
	 * <p>The default implementation returns the given {@code bean} as-is.
	 * @param bean the new bean instance
	 * @param beanName the name of the bean
	 * @return the bean instance to use, either the original or a wrapped one;
	 * if {@code null}, no subsequent BeanPostProcessors will be invoked
	 * @throws org.springframework.beans.BeansException in case of errors
	 * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
	 * @see org.springframework.beans.factory.FactoryBean
	 */
	@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

}

从源码注释中可以分析出如下信息:

  • 首先是用处:是工厂钩子,允许自定义修改bean实例,如检查接口实现或实现代理。
  • spring容器可以自动识别出所有定义的BeanPostProcessor,后续实例化的bean都会通过这些后置处理器。
  • 可通过编程方式手动注册BeanPostProcessor,此时bean通过时会按注册顺序执行BeanPostProcessor。
  • 如果是自动识别的方式,BeanPostProcessor会按定义的PriorityOrdered或Ordered顺序执行
  • @Order注解并不能影响BeanPostProcessor的执行顺序。
  • 此类非常古老,最早的版本就已经存在。
  • postProcessBeforeInitialization方法是在实例化后,属性设置后,初始化方法(InitializatingBean,initMethod,@PostConstructor)执行前执行。
  • postProcessAfterInitialization方法是在初始化方法执行后执行。

BeanPostProcessor后置处理器作用

用于bean对象初始化前后进行逻辑增强。spring默认提供了很多非常重要的BeanPostProcessor实现类,如:AutowiredAnnotationBeanPostProcessor用于@Autowired注解的实现;AnnotationAwareAspectJAutoProxyCreator用于Spring AOP的动态代理。

一个自定义BeanPostProcessor示例

定义一个普通的Bean class

package win.elegentjs.spring.ioc.beanpost;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import javax.annotation.PostConstruct;

@Data
@Slf4j
public class Car {

    // 车身颜色
    private String color;

    // 车子型号
    private String version;

    @PostConstruct
    public void init() {
        log.info("==> in Car init method.");
    }

}

定义了两个BeanPostProcessor

package win.elegentjs.spring.ioc.beanpost;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.Ordered;

/**
 * 自定义BeanPostProcessor,实现了Ordered接口可设定后置处理器的执行顺序,值越小越先执行
 */
@Slf4j
public class CheckColorBeanPostProcessor implements BeanPostProcessor, Ordered {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        log.info("==> in CheckColorBeanPostProcessor beforeInitialization method.");
        return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        log.info("==> in CheckColorBeanPostProcessor afterInitialization method.");
        return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
    }

    @Override
    public int getOrder() {
        return 1;
    }
}

实现的逻辑很简单,就写了个打印语句,并实现了Ordered接口,本后置处理器设置的序列为1。

这是第二个后置处理器,实现逻辑跟第一个相同,但序列为2,期望第一个后置处理器先执行,第二个后执行

package win.elegentjs.spring.ioc.beanpost;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.Ordered;

/**
 * 自定义BeanPostProcessor,实现了Ordered接口可设定后置处理器的执行顺序,值越小越先执行
 */
@Slf4j
public class CheckVersionBeanPostProcessor implements BeanPostProcessor, Ordered {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        log.info("==> in CheckVersionBeanPostProcessor beforeInitialization method.");
        return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        log.info("==> in CheckVersionBeanPostProcessor afterInitialization method.");
        return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
    }

    @Override
    public int getOrder() {
        return 2;
    }
}

这是java config配置类

package win.elegentjs.spring.ioc.beanpost;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class CarConfig {

    @Bean
    public CheckVersionBeanPostProcessor checkVersionBeanPostProcessor() {
        return new CheckVersionBeanPostProcessor();
    }

    @Bean
    public CheckColorBeanPostProcessor checkColorBeanPostProcessor() {
        return new CheckColorBeanPostProcessor();
    }

    @Bean
    public Car car() {
        return new Car();
    }
}

测试看看结果

package win.elegentjs.spring.ioc.beanpost;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import win.elegentjs.spring.ioc.lifecycle.postpre.MonkeyConfig;

@Slf4j
public class CarSample {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(CarConfig.class);

        context.close();
    }
}

// result
2021-05-28 15:41:01.408 [main] INFO  w.e.s.ioc.beanpost.CheckColorBeanPostProcessor-==> in CheckColorBeanPostProcessor beforeInitialization method.
2021-05-28 15:41:01.410 [main] INFO  w.e.s.ioc.beanpost.CheckVersionBeanPostProcessor-==> in CheckVersionBeanPostProcessor beforeInitialization method.
2021-05-28 15:41:01.410 [main] INFO  win.elegentjs.spring.ioc.beanpost.Car-==> in Car init method.
2021-05-28 15:41:01.410 [main] INFO  w.e.s.ioc.beanpost.CheckColorBeanPostProcessor-==> in CheckColorBeanPostProcessor afterInitialization method.
2021-05-28 15:41:01.410 [main] INFO  w.e.s.ioc.beanpost.CheckVersionBeanPostProcessor-==> in CheckVersionBeanPostProcessor afterInitialization method.
2021-05-28 15:41:01.445 [main] DEBUG o.s.c.a.AnnotationConfigApplicationContext-Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@36f6e879, started on Fri May 28 15:41:01 CST 2021


可以看出执行结果符合我们的预期。

小结

本节分析了BeanPostProcessor的作用以及编写了实际示例。下一节会重点讲解spring自带的若干BeanPostProcessor, 我们深入源码看看spring容器如何借助BeanPostProcessor实现各种有用功能特性的。



所属网站分类: 技术文章 > 博客

作者:我长得真不赖

链接:http://www.javaheidong.com/blog/article/207135/f690274cf3a4dc04efa5/

来源:java黑洞网

任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任

16 0
收藏该文
已收藏

评论内容:(最多支持255个字符)