Spring 后置处理器 BeanPostProcessor

前言

BeanPostProcessor也称为Bean后置处理器,它是Spring中定义的接口,在Spring容器的创建过程中(具体为Bean初始化前后)会回调BeanPostProcessor中定义的两个方法。

BeanPostProcessor的源码如下:


public interface BeanPostProcessor {

	/**
	 * Apply this 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.
	 */
	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

	/**
	 * Apply this 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.
	 */
	@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

}

其中postProcessBeforeInitialization方法会在每一个bean对象的初始化方法调用之前回调;postProcessAfterInitialization方法会在每个bean对象的初始化方法调用之后被回调。

实例:

新建两个后置处理器:

public class My1BeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("My1.Before被调用。 bean=" + bean);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("My1.After 被调用。 bean="+ bean);
        return bean;
    }
}


public class My2BeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("My2.Before被调用。 bean=" + bean );
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("My2.After 被调用。 bean=" + bean);
        return bean;
    }
}

将 Person 对象注入 Spring容器


public class Person  implements InitializingBean {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Person() {
        System.out.println("构造方法 this=" + this);
    }

    
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean.afterPropertiesSet  初始化 bean");
    }
}


@SpringBootApplication
@Configuration
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);

    }

    @Bean
    public BeanPostProcessor postBeanProcessor1() {
        return new My1BeanPostProcessor();
    }

    @Bean
    public BeanPostProcessor postBeanProcessor2() {
        return new My2BeanPostProcessor();
    }

    @Bean
    public Person person() {
        Person u = new Person();
        u.setName("my son");
        return u;
    }
}

运行结果:

这个例子证明了:1、postProcessBeforeInitialization方法会在每一个bean对象的初始化方法调用之前回调;2、postProcessAfterInitialization方法会在每个bean对象的初始化方法调用之后被回调。

 

从源码的角度这一切在哪里发生的?

 AbstractAutowireCapableBeanFactory.java

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
        
        Object wrappedBean = bean;
        if (mbd == null || !mbd.isSynthetic()) {
	   //bean 的后置处理器中的 beforeInitialization的调用。
            wrappedBean = this.applyBeanPostProcessorsBeforeInitialization(bean, beanName);
        }

        try {
	   //这个包含了初始化方法的调用(InitializingBean 和 init-method)
            this.invokeInitMethods(beanName, wrappedBean, mbd);
        } catch (Throwable var6) {
           
        }

        if (mbd == null || !mbd.isSynthetic()) {
	   //bean 的后置处理器中的 afterInitialization的调用。
            wrappedBean = this.applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }

        return wrappedBean;
    }

重点就是applyBeanPostProcessorsBeforeInitialization 、applyBeanPostProcessorsAfterInitialization两个方法:

applyBeanPostProcessorsBeforeInitialization方法:

public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
			throws BeansException {
		Object result = existingBean;
                //获取所有的 bean 的后置处理器,并遍历
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
                    //调用后置处理器的postProcessBeforeInitialization方法
			Object current = processor.postProcessBeforeInitialization(result, beanName);
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}

十分简单,没有什么可说的。获取所有的后置处理器,有哪些处理器呢?

applyBeanPostProcessorsAfterInitialization也十分简单就不说了。

 

在所有的后置处理器中有一个CommonAnnotationBeanPostProcessor后置处理器。这一后置处理器就是@PostConstruct和@PreDestroy的以实现的载体。@PostConstruct修饰的方法会在构造函数之后,init()方法之前运行,@PreDestroy修饰的方法会在destroy()方法之前运行。

实例:将上面的 Person 类修改一下,增加两个方法:

public class Person implements InitializingBean {
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Person() {
        System.out.println("构造方法 this=" + this);
    }
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean.afterPropertiesSet  初始化 bean");
    }
    @PostConstruct
    public void postConstructMethod() {
        System.out.println("@PostConstruct");
    }
    @PreDestroy
    public void preDestroyMethod() {
        System.out.println("@PreDestroy");
    }
}

运行结果:

 

 源码分析:

 

private Class<? extends Annotation> initAnnotationType;
	private Class<? extends Annotation> destroyAnnotationType;

    //构造方法
	public CommonAnnotationBeanPostProcessor() {
		setOrder(Ordered.LOWEST_PRECEDENCE - 3);
		setInitAnnotationType(PostConstruct.class);//设置initAnnotationType
		setDestroyAnnotationType(PreDestroy.class);//设置idestroyAnnotationType
		ignoreResourceType("javax.xml.ws.WebServiceContext");
	}

    //后置处理器的实现postProcessBeforeInitialization
	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
		try {
			metadata.invokeInitMethods(bean, beanName);
		}
		catch (InvocationTargetException ex) {
		}
		
		return bean;
	}
	
	//后置处理器的实现postProcessAfterInitialization
	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

在构造方法中,设置了属性initAnnotationType和idestroAnnotationType。后置处理器的实现postProcessAfterInitialization方法直接返回bean。最重要的就是postProcessBeforeInitialization方法,这一方法中调用了两个方法:findLifecycleMetadata方法是用来获取bean中被@PostConstruct和@PreDestroy修饰的方法。invokeInitMethods方法用来调用被@PostConstruct和@PreDestroy修饰的方法。简单说就是一个负责获取、一个负责调用。
findLifecycleMetadata方法:

private LifecycleMetadata findLifecycleMetadata(Class<?> clazz) {
		if (this.lifecycleMetadataCache == null) {
			//核心方法
			return buildLifecycleMetadata(clazz);
		}
		// lifecycleMetadataCache是一个map,用来做缓存
		LifecycleMetadata metadata = this.lifecycleMetadataCache.get(clazz);//获取缓存中的数据
		if (metadata == null) {//缓存中为空
			synchronized (this.lifecycleMetadataCache) {//加锁
				metadata = this.lifecycleMetadataCache.get(clazz);//再次获取
				if (metadata == null) {//再判断为空
					//核心方法
					metadata = buildLifecycleMetadata(clazz);
					this.lifecycleMetadataCache.put(clazz, metadata);//放入缓存
				}
				return metadata;
			}
		}
		return metadata;
	}



	//核心方法
	private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
		final boolean debug = logger.isDebugEnabled();
		List<LifecycleElement> initMethods = new ArrayList<>();
		List<LifecycleElement> destroyMethods = new ArrayList<>();
		Class<?> targetClass = clazz;

		do {
			final List<LifecycleElement> currInitMethods = new ArrayList<>();
			final List<LifecycleElement> currDestroyMethods = new ArrayList<>();

			ReflectionUtils.doWithLocalMethods(targetClass, method -> {
				//this.initAnnotationType是在构造方法中设置的@PostConstruct。
				if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {//判断是否有@PostConstruct修饰的方法。
					//将方法包装成LifecycleElement,并放入currInitMethods集合中
					LifecycleElement element = new LifecycleElement(method);
					currInitMethods.add(element);
			
				}
				//this.destroyAnnotationType是在构造方法中设置的@PreDestroy
				if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {
					//将方法包装成LifecycleElement,并放入currDestroyMethods集合中
					currDestroyMethods.add(new LifecycleElement(method));
				
				}
			});
			initMethods.addAll(0, currInitMethods);//将currInitMethods放入initMethods集合中
			destroyMethods.addAll(currDestroyMethods);//将currDestroyMethods放入destroyMethods集合中
			targetClass = targetClass.getSuperclass();
		}
		while (targetClass != null && targetClass != Object.class);
		
		//最后再将clazz, initMethods, destroyMethods包装成LifecycleMetadata。
		return new LifecycleMetadata(clazz, initMethods, destroyMethods);
	}
	

findLifecycleMetadata方法获取LifecycleMetadata对象中含 initMethods、destroyMethods这两个集合,
一个包含bean中所有@PostConstruct修饰的方法,一个包含bean中所有@PreDestroy修饰的方法。

所需的信息准备完成,invokeInitMethods方法开始调用

public void invokeInitMethods(Object target, String beanName) throws Throwable {
			Collection<LifecycleElement> checkedInitMethods = this.checkedInitMethods;
			//获取LifecycleMetadata中的initMethods集合
			Collection<LifecycleElement> initMethodsToIterate =
					(checkedInitMethods != null ? checkedInitMethods : this.initMethods);
			if (!initMethodsToIterate.isEmpty()) {//集合不为空
				boolean debug = logger.isDebugEnabled();
				for (LifecycleElement element : initMethodsToIterate) {//遍历集合
					if (debug) {
						logger.debug("Invoking init method on bean '" + beanName + "': " + element.getMethod());
					}
					element.invoke(target);//调用方法。
				}
			}
		}

 

destroyMethods集合中的方法在bean销毁时才能被调用,这里就不在赘诉。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值