围绕生命周期展开拓展点
按照Bean的生命周期去梳理整个拓展点,这样可以很清晰的知道,在哪个阶段该使用哪个拓展点。其生命周期的范围:从Bean的定义注册开始到最终Bean实例化完成。
以下是流程图:
拓展点详解
自定义Spring XML Schema
概述
自定义Spring XML SCHEMA,这个是Spring中非常常见的拓展点,Dubbo就是用了此拓展点。例如Apache Dubbo的实现类:org.apache.dubbo.config.spring.schema.DubboNamespaceHandler。就定义了对<dubbo>标签的支持。
注意:虽然xml schema拓展点被提到了第一位,但是并不代表自定义标签对应的Bean会率先初始化。自定义标签对应的Bean依旧会是按照上图的生命周期进行执行。
org.springframework.beans.factory.xml.NamespaceHandlerSupport是一个抽象类,对org.springframework.beans.factory.xml.NamespaceHandler进行了简单封装,拓展自定义标签,可以直接实现抽象类,会方便很多。只需要实现init方法,并通过registerBeanDefinitionParser方法,传入一个标签名和org.springframework.beans.factory.xml.BeanDefinitionParser的实现类即可。如下Dubbo拓展点的代码:
public class DubboNamespaceHandler extends NamespaceHandlerSupport {
static {
Version.checkDuplicate(DubboNamespaceHandler.class);
}
@Override
public void init() {
registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
registerBeanDefinitionParser("config-center", new DubboBeanDefinitionParser(ConfigCenterBean.class, true));
registerBeanDefinitionParser("metadata-report", new DubboBeanDefinitionParser(MetadataReportConfig.class, true));
registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
registerBeanDefinitionParser("metrics", new DubboBeanDefinitionParser(MetricsConfig.class, true));
registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
registerBeanDefinitionParser("annotation", new AnnotationBeanDefinitionParser());
}
}
实例
1.声明一个xsd文件,放置于文件目录resource/META-INF/下。例如:resource/META-INF/ajian.xsd
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:tool="http://www.springframework.org/schema/tool"
xmlns="http://dubbo.apache.org/schema/dubbo"
targetNamespace="http://www.ajian.com/schema/ajian">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
<xsd:import namespace="http://www.springframework.org/schema/beans" schemaLocation="http://www.springframework.org/schema/beans/spring-beans.xsd"/>
<xsd:import namespace="http://www.springframework.org/schema/tool"/>
<xsd:element name="ajian">
<xsd:complexType>
<xsd:complexContent>
<xsd:extension base="beans:identifiedType">
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
</xsd:schema>
2. 声明AjianNamespaceHandler类,继承NamespaceHandlerSupport。声明一个BeanDefinitionParse的实现类,即根据xml元素的内容生成一个BeanDefinition。
public class AjianNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("ajian",new AjianBeanDefinitionParse(AjianBean.class));
}
}
public class AjianBeanDefinitionParse implements BeanDefinitionParser {
private Class<?> beanClass;
public AjianBeanDefinitionParse(Class<?> beanClass) {
this.beanClass = beanClass;
}
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition();
rootBeanDefinition.setBeanClass(beanClass);
rootBeanDefinition.setLazyInit(false);
// 设置属性
String name = element.getAttribute("name");
rootBeanDefinition.getPropertyValues().addPropertyValue("name",name);
parserContext.getRegistry().registerBeanDefinition(name,rootBeanDefinition);
return rootBeanDefinition;
}
}
3.在resource/META-INF下声明两个文件,spring.handlers与spring.schemas。
spring.handlers内容
http\://www.ajian.com/schema/ajian=com.yangt.risk.ao.ioc.AjianNamespaceHandler
spring.schemas内容
http\://www.ajian.com/schema/ajian/ajian.xsd=META-INF/ajian.xsd
4.修改spring-ioc.xml加上新标签的声明,如下
5.测试代码如下:
自定义Bean被解析部分的源码
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
String namespaceUri = getNamespaceURI(ele);
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
return null;
}
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
通过元素找到nameSpaceUri,然后通过nameSpaceUri找到对应的NamespaceHandler,最后调用对应的parse方法解析为具体的BeanDefinition。所以需要实现NamespaceHandler接口和BeanDefinitionParser接口。
BeanDefinitionRegistryPostProcessor
BeanDefinitionRegistryPostProcessor继承自BeanFactoryPostProcessor,对外提供一个拓展方法:
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
此方法,允许修改已经注册到Registry内的BeanDefinition,或者添加一些自定义BeanDefinition到Registry,同时也支持删除某些BeanDefinition。因为此时这些bean还都只是BeanDefinition,未被实例化。执行时机:会在普通BeanFactoryPostProcessor接口实现类执行之前被调用。
Spring源码内调用时机:
AbstractApplicationCotext refresh方法:
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
// 判断是否实现了PriorityOrdered接口
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
// 排序
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
// 循环调用所有实现了BeanDefinitionRegistryPostProcessor的子类
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
// 判断是否实现了Ordered接口
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
// 排序
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
// 循环调用所有实现了BeanDefinitionRegistryPostProcessor的子类
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
// 最后调用其他实现了BeanDefinitionRegistryPostProcessors接口的子类
boolean reiterate = true;
while (reiterate) {
reiterate = false;
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
reiterate = true;
}
}
// 排序
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
// 循环调用所有实现了BeanDefinitionRegistryPostProcessor的子类
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
}
// 调用所有实现类BeanFactoryPostProcessors接口的子类
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
执行顺序:
- 首先,实现了BeanDefinitionRegistryPostProcessor和PriorityOrdered的接口的类先执行。
- 其次,执行实现了BeanDefinitionRegistryPostProcessor和Ordered的接口的类。
- 最后,调用实现了BeanDefinitionRegistryPostProcessor接口的类。
实例:
disconf-client内DisconfMgrBean
public class DisconfMgrBean implements BeanDefinitionRegistryPostProcessor, PriorityOrdered, ApplicationContextAware {
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE + 1;
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
// 留个口子可以方便的替换配置文件
if (StringUtils.isNotBlank(disconfFileName)) {
SupportFileTypeEnum fileTypeEnum = SupportFileTypeEnum.getByFileName(disconfFileName);
if (fileTypeEnum != SupportFileTypeEnum.PROPERTIES) {
throw new RuntimeException("disconfFileName 配置错误,必须为properties 文件");
}
DisClientConfig.setDisconfFileName(disconfFileName);
}
List<String> scanPackList = Lists.newArrayList();
if (StringUtils.isNotBlank(scanPackage)) {
// unique
Set<String> hs = Sets.newHashSet(StringUtil.parseStringToStringList(scanPackage, SCAN_SPLIT_TOKEN));
scanPackList = Lists.newArrayList(hs);
}
// 进行扫描
DisconfMgr.getInstance().setApplicationContext(applicationContext);
DisconfMgr.getInstance().firstScan(scanPackList);
// register java bean
registerAspect(registry);
}
}
此类执行的顺序是目前的项目中是第一位的,主要是实现了BeanDefinitionRegistryPostProcessor, PriorityOrdered。同时getOrder的顺序是最高的,所以postProcessBeanDefinitionRegistry方法会先被回调。
BeanFactoryPostProcessor
允许修改程序上下文中的BeanDefinition,可以对BeanFactory这种Bean的属性值进行修改,一个典型的应用是PropertyResourceConfigurer。
实例
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
try {
Properties mergedProps = mergeProperties();
// Convert the merged properties, if necessary.
convertProperties(mergedProps);
// Let the subclass process the properties.
processProperties(beanFactory, mergedProps);
}
catch (IOException ex) {
throw new BeanInitializationException("Could not load properties", ex);
}
}
真正的替换属性的逻辑
/**
* Apply the given property value to the corresponding bean.
*/
protected void applyPropertyValue(
ConfigurableListableBeanFactory factory, String beanName, String property, String value) {
BeanDefinition bd = factory.getBeanDefinition(beanName);
while (bd.getOriginatingBeanDefinition() != null) {
bd = bd.getOriginatingBeanDefinition();
}
PropertyValue pv = new PropertyValue(property, value);
pv.setOptional(this.ignoreInvalidKeys);
bd.getPropertyValues().addPropertyValue(pv);
}
比如说:可能某些参数是${key},这个实现类就是把前边这种参数转换成xxx.properties中key所对应的值。
Spring源码内调用时机:
同理,也是在AbstractApplicationContext的refresh方法内的invokeBeanFactoryPostProcessors(beanFactory);内被调用,但是执行时机在BeanDefinitionRegistryPostProceesor之后。
InstantiationAwareBeanPostProcessor
这个接口是BeanPostProcessor的子接口,用于在实例化之后,但在设置显式属性或自动装配之前,设置实例化之前的回调函数。通常用于抑制特定目标bean的默认实例化,例如,创建具有特殊TargetSources(池化目标,延迟初始化目标等)的代理,或者实现其他注入策略,例如字段注入。注意:这个接口是一个专用接口,主要用于框架内的内部使用。 建议尽可能实现简单的BeanPostProcessor接口,或者从InstantiationAwareBeanPostProcessorAdapter派生,以便屏蔽此接口的扩展。
postProcessBeforeInstantiation方法,在目标bean实例化之前创建bean,如果在这里创建了bean,则不会走默认的实例化过程,通常用来创建代理。注意工厂方法生成的bean不会走这个方法。
postProcessAfterInstantiation方法,在目标bean实例化后,但是没有进行属性填充前执行的方法。
postProcessPropertyValues方法,在将给定属性值设置到到给定的bean后,对其进行后处理。 允许检查所有的依赖关系是否被满足,例如基于bean属性设置器上的“Required”注解。还允许替换要应用的属性值,通常通过创建基于原始PropertyValues的新MutablePropertyValues实例,添加或删除特定值。
BeanPostProcessor
对bean进行处理的回调接口,有两个方法:
postProcessBeforeInitialization:在bean初始化(如InitializingBean的afterPropertiesSet或自定义init方法)之前进行回调。
postProcessAfterInitialization:在bean初始化之后(如InitializingBean的afterPropertiesSet或自定义init方法)进行回调。
实例: ApplicationContextAwareProcessor
@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 {
// 对所有实现aware接口的类,set注入ApplicationContext上下文
invokeAwareInterfaces(bean);
}
return bean;
}
// 注入上下文操作
private void invokeAwareInterfaces(Object bean) {
if (bean instanceof Aware) {
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);
}
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
}
}
InitializingBean
如果bean实现了InitializingBean接口,初始化时,则会调用afterPropertiesSet方法。
Bean显示声明init-method
执行完InitializingBean的afterPropertiesSet方法后,则会调用在bean上显示声明的init-method。
结论
以上是大部分拓展点执行的时机以及部分实例,还有部分源码分析。总结来看,最常用的几个拓展点:
- BeanDefinitionRegistryPostProcessor
- BeanFactoryPostProcessor
- BeanPostProcssor
- InitializingBean