概述
再谈bean生命周期
目前整个bean的生命周期,我们可以进行如下控制:
- bean的实例化: 容器初始化时调用bean的构造方法,我们可以在构造方法中执行必要的逻辑
- bean的初始化: 在初始化时,可以通过BeanPostProcessor的postProcessBeforeInitialization()方法和postProcessAfterInitialization()方法进行拦截,执行自定义的逻辑;通过@PostConstruct注解、InitializingBean和init-method来指定bean初始化前后执行的方法,执行自定义的逻辑。
- bean的销毁: 可以通过@PreDestroy注解,DisposableBean和destroy-method来指定bean在销毁前的执行逻辑。
以上,就是我们可以通过spring容器控制bean生命周期的方式。
解析几种重要的BeanPostProcessor
本章会详解几种spring自带的几种BeanPostProcessor,通过它们实现了对bean的功能定制。主要了解这几个:
-
ApplicationContextAwareProcessor
它的作用是可以向组件中注入IOC容器 -
BeanValidationPostProcessor
它的作用是对bean进行校验,当我们创建bean,并赋值后,可以通过它对bean进行校验,看是否合法。 -
CommonAnnotationBeanPostProcessor
它的作用是用来处理@PostConstructor,@PreDestroy和@Resource等注解,这些注解是JSR-250注解,位于javax.annotation包中。 -
AutowiredAnnotationBeanPostProcessor
它的作用是用于处理标注了@Autowired注解的变量或方法。 -
AnnotationAwareAspectJAutoProxyCreator
它的作用是用于Spring AOP的动态代理。
这里以ApplicationContextAwareProcessor为示例,讲解下spring容器如何利用BeanPostProcessor实现bean功能增强的。其他几个后置处理器在相关主题时再做介绍。
ApplicationContextAwareProcessor
ApplicationContextAwareProcessor是比较简单易懂的Bean后置处理器。
当我们自己的Bean想持有容器对象时可在定义Bean 类的时候实现这么一个接口:ApplicationContextAware,接口定义如下:
package org.springframework.context;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.Aware;
/**
* Interface to be implemented by any object that wishes to be notified
* of the {@link ApplicationContext} that it runs in.
*
* <p>Implementing this interface makes sense for example when an object
* requires access to a set of collaborating beans. Note that configuration
* via bean references is preferable to implementing this interface just
* for bean lookup purposes.
*
* <p>This interface can also be implemented if an object needs access to file
* resources, i.e. wants to call {@code getResource}, wants to publish
* an application event, or requires access to the MessageSource. However,
* it is preferable to implement the more specific {@link ResourceLoaderAware},
* {@link ApplicationEventPublisherAware} or {@link MessageSourceAware} interface
* in such a specific scenario.
*
* <p>Note that file resource dependencies can also be exposed as bean properties
* of type {@link org.springframework.core.io.Resource}, populated via Strings
* with automatic type conversion by the bean factory. This removes the need
* for implementing any callback interface just for the purpose of accessing
* a specific file resource.
*
* <p>{@link org.springframework.context.support.ApplicationObjectSupport} is a
* convenience base class for application objects, implementing this interface.
*
* <p>For a list of all bean lifecycle methods, see the
* {@link org.springframework.beans.factory.BeanFactory BeanFactory javadocs}.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @author Chris Beams
* @see ResourceLoaderAware
* @see ApplicationEventPublisherAware
* @see MessageSourceAware
* @see org.springframework.context.support.ApplicationObjectSupport
* @see org.springframework.beans.factory.BeanFactoryAware
*/
public interface ApplicationContextAware extends Aware {
/**
* Set the ApplicationContext that this object runs in.
* Normally this call will be used to initialize the object.
* <p>Invoked after population of normal bean properties but before an init callback such
* as {@link org.springframework.beans.factory.InitializingBean#afterPropertiesSet()}
* or a custom init-method. Invoked after {@link ResourceLoaderAware#setResourceLoader},
* {@link ApplicationEventPublisherAware#setApplicationEventPublisher} and
* {@link MessageSourceAware}, if applicable.
* @param applicationContext the ApplicationContext object to be used by this object
* @throws ApplicationContextException in case of context initialization errors
* @throws BeansException if thrown by application context methods
* @see org.springframework.beans.factory.BeanInitializationException
*/
void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}
接口本身挺简单,就一个方法setApplicationContext, spring容器会在目标bean初始化的某个阶段调用该方法,将自己注入。
举个示例:
先见一个容器持有工具类,它实现了ApplicationContextAware接口,期望容器初始化该bean时注入spring容器。
package win.elegentjs.spring.ioc.beanpost.appware;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
/**
* 持有容器类工具类,方便从容器中获取Bean对象
*/
public class SpringContextHolder implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringContextHolder.applicationContext = applicationContext;
}
/**
* 从容器中获取Bean
*/
public static <T> T getBean(Class<T> clazz) {
return applicationContext.getBean(clazz);
}
}
定义java config类加载bean
package win.elegentjs.spring.ioc.beanpost.appware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* java config配置类
*/
@Configuration
public class SpringContextHolderConfig
{
/**
* 定义Bean,在容器初始化bean的某个阶段注入容器对象
*/
@Bean
public SpringContextHolder springContextHolder() {
return new SpringContextHolder();
}
}
写示例,看看执行结果
package win.elegentjs.spring.ioc.beanpost.appware;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
@Slf4j
public class SpringContextHolderSample {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringContextHolderConfig.class);
SpringContextHolderConfig config = SpringContextHolder.getBean(SpringContextHolderConfig.class);
log.info("==> config: {}", config);
}
}
// result:
2021-05-29 16:31:42.851 [main] INFO
w.e.s.i.beanpost.appware.SpringContextHolderSample-==> config: win.elegentjs.spring.ioc.beanpost.appware.SpringContextHolderConfig$$EnhancerBySpringCGLIB$$162c7fe1@1623b78d
可以看出能顺利的获取bean实例,而方法的内部实现是委托spring容器实现,说明spring容器成功注入了。
以下我们分析ApplicationContextAwareProcessor,看看spring容器到底是如何实现容器注入到bean中的。
分析ApplicationContextAwareProcessor类
先上源码:
package org.springframework.context.support;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.EmbeddedValueResolver;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.MessageSourceAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.lang.Nullable;
import org.springframework.util.StringValueResolver;
/**
* {@link BeanPostProcessor} implementation that supplies the {@code ApplicationContext},
* {@link org.springframework.core.env.Environment Environment}, or
* {@link StringValueResolver} for the {@code ApplicationContext} to beans that
* implement the {@link EnvironmentAware}, {@link EmbeddedValueResolverAware},
* {@link ResourceLoaderAware}, {@link ApplicationEventPublisherAware},
* {@link MessageSourceAware}, and/or {@link ApplicationContextAware} interfaces.
*
* <p>Implemented interfaces are satisfied in the order in which they are
* mentioned above.
*
* <p>Application contexts will automatically register this with their
* underlying bean factory. Applications do not use this directly.
*
* @author Juergen Hoeller
* @author Costin Leau
* @author Chris Beams
* @since 10.10.2003
* @see org.springframework.context.EnvironmentAware
* @see org.springframework.context.EmbeddedValueResolverAware
* @see org.springframework.context.ResourceLoaderAware
* @see org.springframework.context.ApplicationEventPublisherAware
* @see org.springframework.context.MessageSourceAware
* @see org.springframework.context.ApplicationContextAware
* @see org.springframework.context.support.AbstractApplicationContext#refresh()
*/
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
@Nullable
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)){
return bean;
}
AccessControlContext acc = null;
if (System.getSecurityManager() != null) {
acc = this.applicationContext.getBeanFactory().getAccessControlContext();
}
if (acc != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareInterfaces(bean);
return null;
}, acc);
}
else {
// 执行Aware接口对象的注入方法,bean就是容器初始化的bean
invokeAwareInterfaces(bean);
}
return bean;
}
private void invokeAwareInterfaces(Object bean) {
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接口,则调用setApplicationContext方法,传入容器对象
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
}
}
可以看出ApplicationContextAwareProcessor的逻辑并不难,甚至挺简单,就是在bean实例化并设置了必要属性后,调用了ApplicationContextAwareProcessor的postProcessBeforeInitialization方法,在该方法中执行了setApplicationContext方法注入了容器。
小结
本节通过分析ApplicationContextAwareProcessor的源码了解了容器增强bean背后的秘密,即通过Bean后置处理器实现,干预的时机是两个:
- Bean实例化,属性设值后,初始化方法执行前
- Bean实例化,属性设值后,初始化方法执行后
通过这两个阶段,可以插入自己的逻辑,实现对Bean实例的增强,如:
- 对bean属性做合法性校验
- 检查是否有特殊的接口,如果有做相应的处理(如本示例注入spring容器本身)
- 对注解的支持,如:@Autowired, @PostConstructor等
- AOP,包装生成Bean代理对象,实现对象功能的增强。
最后
以上就是神勇八宝粥为你收集整理的10. spring-容器: BeanPostProcessor后置处理器-进阶的全部内容,希望文章能够帮你解决10. spring-容器: BeanPostProcessor后置处理器-进阶所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复