09-Spring生命周期-BeanPostProcessor后置处理器

BeanPostProcessor 后置处理器

在 bean 初始化前后做处理,对 bean 初始化方法做了拦截,使用也很简单,新建一个组件实现 BeanPostProcessor 并加入到容器中.

BeanPostProcessor 提供了两个方法,实现这两个方法即可:

  • postProcessBeforeInitialization: 在初始化之前调用
  • postProcessAfterInitialization: 在初始化之后调用

实现一个 BeanPostProcessor 后置处理器

package com.demon.bean;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

/**
 * BeanPostProcessor后置处理器实现
 *
 * @author Demon-HY
 * @date 2019-12-10
 */
// 将后置处理器加入到容器中
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {

    public MyBeanPostProcessor() {
        System.out.println("MyBeanPostProcessor 初始化方法");
    }

    // 可以设置bean的值
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("初始化之前调用, beanName=" + beanName + " bean=" +bean.getClass());
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("初始化之后调用, beanName=" + beanName + " bean=" +bean.getClass());
        return bean;
    }
}

执行测试用例

    @Test
    public void test2() throws Exception {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
        System.out.println("容器创建成功.................");

        // 关闭容器
        context.close();
    }

打印输出:

MyBeanPostProcessor 初始化方法
初始化之前调用, beanName=org.springframework.context.event.internalEventListenerProcessor bean=class org.springframework.context.event.EventListenerMethodProcessor
初始化之后调用, beanName=org.springframework.context.event.internalEventListenerProcessor bean=class org.springframework.context.event.EventListenerMethodProcessor
初始化之前调用, beanName=org.springframework.context.event.internalEventListenerFactory bean=class org.springframework.context.event.DefaultEventListenerFactory
初始化之后调用, beanName=org.springframework.context.event.internalEventListenerFactory bean=class org.springframework.context.event.DefaultEventListenerFactory
初始化之前调用, beanName=config bean=class com.demon.config.Config$$EnhancerBySpringCGLIB$$869d37c8
初始化之后调用, beanName=config bean=class com.demon.config.Config$$EnhancerBySpringCGLIB$$869d37c8
初始化之前调用, beanName=color bean=class com.demon.bean.Color
初始化之后调用, beanName=color bean=class com.demon.bean.Color
容器创建成功.................

BeanPostProcessor 原理

在我们实现的 MyBeanPostProcessor 的 postProcessBeforeInitialization()方法里面打断点debug,可以看到下面的代码,Spring 在 AbstractAutowireCapableBeanFactory 类里面
预留了 BeanPostProcessor 处理器的插槽.

    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
        // 在 bean 初始化之前调用
        wrappedBean = this.applyBeanPostProcessorsBeforeInitialization(bean, beanName);
    }

    try {
        // 实际执行 bean 的初始化方法
        this.invokeInitMethods(beanName, wrappedBean, mbd);
    } catch (Throwable var6) {
        throw new BeanCreationException(mbd != null ? mbd.getResourceDescription() : null, beanName, "Invocation of init method failed", var6);
    }

    if (mbd == null || !mbd.isSynthetic()) {
        // 在 bean 初始化之后调用
        wrappedBean = this.applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }

public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) 代码实现:

    // 遍历容器中所有的 BeanPostProcessor,并挨个调用,当某一个 BeanPostProcessor.postProcessBeforeInitialization() 方法返回false,则跳出该方法
    @Override
	public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
			throws BeansException {

		Object result = existingBean;
		for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
			result = beanProcessor.postProcessBeforeInitialization(result, beanName);
			if (result == null) {
				return result;
			}
		}
		return result;
	}

BeanPostProcessor 典型应用 ApplicationContextAwareProcessor

ApplicationContextAwareProcessor 接口就是基于 BeanPostProcessor 实现的,当你的Service需要注入ApplicationContext时,只需要实现ApplicationContextAware 接口,
就可以实现 ApplicationContext 的注入.

先看下demo:

package com.demon.service;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;

/**
 * @author Demon-HY
 * @date 2019-12-12
 */
@Service
public class UserService implements ApplicationContextAware {
   
    // Spring 容器
    private ApplicationContext context;
    
    @Override
    public void setApplicationContext(ApplicationContext context) throws BeansException {
        this.context = context;
    }
}

找到实现了 BeanPostProcessor 接口的 ApplicationContextAwareProcessor 类

class ApplicationContextAwareProcessor implements BeanPostProcessor {

	private final ConfigurableApplicationContext applicationContext;

	private final StringValueResolver embeddedValueResolver;


	/**
	 * Create a new ApplicationContextAwareProcessor for the given context.
	 */
	public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) {
		this.applicationContext = applicationContext;
		this.embeddedValueResolver = new EmbeddedValueResolver(applicationContext.getBeanFactory());
	}

    // 初始化之前调用
	@Override
	public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
		AccessControlContext acc = null;

        // 如果
		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(new PrivilegedAction<Object>() {
				@Override
				public Object run() {
					invokeAwareInterfaces(bean);
					return null;
				}
			}, acc);
		}
		else {
			invokeAwareInterfaces(bean);
		}

		return bean;
	}

    // 设置属性
	private void invokeAwareInterfaces(Object bean) {
		if (bean instanceof Aware) {
		    // bean 实现了 EnvironmentAware 接口,则调用 bean.setEnvironment() 设置系统环境
			if (bean instanceof EnvironmentAware) {
				((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
			}
			if (bean instanceof EmbeddedValueResolverAware) {
				((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
			}
			if (bean instanceof ResourceLoaderAware) {
				((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
			}
			if (bean instanceof ApplicationEventPublisherAware) {
				((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
			}
			if (bean instanceof MessageSourceAware) {
				((MessageSourceAware) bean).setMessageSource(this.applicationContext);
			}
			// bean 实现了 ApplicationContextAware 接口,则调用 bean.setApplicationContext() 设置Spring 容器
			if (bean instanceof ApplicationContextAware) {
				((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
			}
		}
	}
}

咖啡小馆

QQ群: 823971061 点击按钮入群

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Demon-HY

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值