Spring源码学习(三):容器的功能扩展·一

14 篇文章 0 订阅

目录

1.prepareBeanFactory方法

1.1 扩展容器的组件

1.2 忽略依赖接口

1.3 注册可解析依赖

1.4 注册环境

2.invokeBeanFactoryPostProcessors

2.1 一个例子

2.2核心方法介绍

3.registerBeanPostProcessors


容器完成配置文件的解析和Bean的加载、注册之后,ApplicationContext就已经拥有了BeanFactory的所有功能了,但是仅仅如此,还无法体现ApplicationContext与BeanFactory之间的差异。在refresh方法中,还有很多后续步骤,用于对容器功能进行扩展:

this.prepareBeanFactory(beanFactory); //对BeanFactory进行功能填充
this.postProcessBeanFactory(beanFactory); //允许子类在所有的bean尚未初始化之前注册BeanPostProcessor
this.invokeBeanFactoryPostProcessors(beanFactory); //是我们可以在bean初始化之前修改Bean的定义
this.registerBeanPostProcessors(beanFactory); //注册拦截Bean创建的后处理器
this.initMessageSource(); //初始化消息源,用于国际化
this.initApplicationEventMulticaster(); //初始化应用程序的事件广播器
this.onRefresh(); //空方法,作为扩展点
this.registerListeners(); //查找并注册Listener Bean
this.finishBeanFactoryInitialization(beanFactory); //初始化剩余的单例
this.finishRefresh(); //完成刷新,并通知相关监听器

这里先看下前四个方法。 

1.prepareBeanFactory方法

该方法大致可以分成四块来看。

1.1 扩展容器的组件

beanFactory.setBeanClassLoader(this.getClassLoader());
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, this.getEnvironment()));
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
if (beanFactory.containsBean("loadTimeWeaver")) {
    beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
    beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}

1)setBeanClassLoader不难理解,就是将BeanFactory的类加载器设置为Context同款。

2)setBeanExpressionResolver是为容器添加SpEL支持。Spring Expression Language(简称SpEL)在Spring3.0加入,是一种功能强大的表达式语言、用于在运行时查询和操作对象图;语法上类似于Unified EL,但提供了更多的特性,特别是方法调用和基本字符串模板函数。其用法如下:

<bean id="test" class="..."/>
<bean>
    <property name="spel" value="${test}"/>
</bean>

<!--上面的配置与下面的效果一样-->

<bean id="test" class="..."/>
<bean>
    <property name="spel" ref="test"/>
</bean>

当然也可以直接构造SpelExpressionParser,通过parseExpression传入SpEL表达式,然后使用getValue()取出结果。

StandardBeanExpressionResolver的构造方法中实例化了一个SpelExpressionParser对象,其evaluate方法会在Bean初始化时调用。

3)addPropertyEditorRegistar方法向容器增加了PropertyEditor注册器。以下一个例子可以说明PropertyEditor的作用:

Bean类:
public class testBean{
    Date date;
    ...
}

配置文件:
<beans>
    <bean id="test" class="testBean">
        <property name="date" value="1970-01-01"/>
    </bean>
</beans>

testBean在实例化时会报错,原因是XML中配置的date属性被识别为String类型,无法直接进行类型转换。

PropertyEditor有2*2,一共4种添加方法:

从配置方法来看,有编程式(context.getBeanFactory().registerCustomEditor()方法,或context.getBeanFactory().addPropertyEditorRegistrar()方法)和配置式(将自定义的PropertyEditor配置为Bean)两种;

从实现来看,有继承PropertyEditorSupport类并重写其setAsText方法,以及实现PropertyEditorRegistar接口两种。

下面是配置式的示例:

public class DatePropertyEditor extends PropertyEditorSupport {
    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        SimpleDateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd");
        try {
            Date date=dateFormat.parse(text);
            setValue(date);
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }
}

public class DatePropertyEditorRegistar implements PropertyEditorRegistrar {
    @Override
    public void registerCustomEditors(PropertyEditorRegistry registry) {
        registry.registerCustomEditor(Date.class,new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"),true));
    }
}
    <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
        <property name="customEditors">
            <map>
                <entry key="java.util.Date">
                    <bean class="DatePropertyEditor"/>
                </entry>
            </map>
        </property>
        <property name="propertyEditorRegistrars">
            <list>
                <bean class="DatePropertyEditorRegistar"/>
            </list>
        </property>
    </bean>

被注册的PropertyEditor会在初始化Bean时调用。

4)addBeanPostProcessor方法向容器添加了ApplicationContextAwareProcessor,用于帮助实现了某些Aware接口的Bean获取资源。主要逻辑在ApplicationContextAwareProcessor中,如果具有权限并且实现了特定借口,则调用invokeAwareInterfaces方法:

    public Object postProcessBeforeInitialization(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(() -> {
                this.invokeAwareInterfaces(bean);
                return null;
            }, acc);
        } else {
            this.invokeAwareInterfaces(bean);
        }
        return bean;
    }

invokeAwareInterfaces方法就是判断传入的bean是否继承了指定的Aware接口,是则调用对应的setter方法,赋予其资源。

5)ApplicationListenerDetector顾名思义,是用来检测监听器的,Spring提供了ApplicationListener<T>接口,可以接收特定类型的事件

6)LoadTimeWeaverAwareProcessor与AspectJ有关,AspectJ weaver可以对类进行编织,然后输出为类文件。

1.2 忽略依赖接口

实现了如ApplicationContextAware等接口的Bean,在上一步中已经全部通过ApplicationContextAwareProcessor配置,因此无需再次装配,可以在DI时忽略:

beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

1.3 注册可解析依赖

以下四个接口可以被自动装配:

beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);

官方的描述是:

You can also use @Autowired for interfaces that are well-known resolvable dependencies: BeanFactoryApplicationContextEnvironmentResourceLoaderApplicationEventPublisher, and MessageSource. These interfaces and their extended interfaces, such as ConfigurableApplicationContext or ResourcePatternResolver, are automatically resolved, with no special setup necessary. 

1.4 注册环境

这一段用到的几个方法都很熟悉了,不需要多介绍。

        if (!beanFactory.containsLocalBean("environment")) {
            beanFactory.registerSingleton("environment", this.getEnvironment());
        }
        if (!beanFactory.containsLocalBean("systemProperties")) {
            beanFactory.registerSingleton("systemProperties", this.getEnvironment().getSystemProperties());
        }
        if (!beanFactory.containsLocalBean("systemEnvironment")) {
            beanFactory.registerSingleton("systemEnvironment", this.getEnvironment().getSystemEnvironment());
        }

2.invokeBeanFactoryPostProcessors

之所以跳过postProcessBeanFactory方法,是由于该方法为空,且在ClassPathXmlApplicationContext的继承链上没有覆盖。

2.1 一个例子

如上面的注释所述,invokeBeanFactoryPostProcessors方法可以赋予开发者修改已注册Bean的能力,还可以为这些BeanFactoryPostProcessor设置作用次序。下面是一个使用例子:

public class HelloBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        BeanDefinition bean=beanFactory.getBeanDefinition("hello");
        MutablePropertyValues propertyValues=bean.getPropertyValues();
        propertyValues.addPropertyValue("word","Spring");
    }
}

public class Hello{
    String word;
    Hello(){}
    public void sayHello(){System.out.println("Hello "+word);}
    public void setWord(String word) {this.word = word;}
}


public class Main{
    public static void main(String args[]){
        ApplicationContext context=new ClassPathXmlApplicationContext("config.xml");
        Hello hello=(Hello)context.getBean("hello");
        hello.sayHello();
    }
}

配置文件为:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="hello" class="Hello">
        <property name="word" value="World"/>
    </bean>
    <bean class="HelloBeanFactoryPostProcessor"/>
</beans>

也可以通过context.addBeanFactoryPostProcessor()方法配置。运行后,输出的不是“Hello World”,而是“Hello Spring”。

2.2核心方法介绍

invokeBeanFactoryPostProcessors的核心方法是invokeBeanFactoryPostProcessors,该方法长达130多行,因此分段进行解释。

首先,会先判断传入的beanFactory是否是BeanDefinitionRegistry,从DefaultListableBeanFactory的继承关系来看,答案是肯定的。然后就从传入的BeanFactoryPostProcessor列表中读取每个元素,判断是否是BeanDefinitionRegistryPostProcessor类型,然后分别进行注册。

BeanDefinitionRegistry registry = (BeanDefinitionRegistry)beanFactory;
regularPostProcessors = new ArrayList();
registryProcessors = new ArrayList();
Iterator var6 = beanFactoryPostProcessors.iterator();
while(var6.hasNext()) {
    BeanFactoryPostProcessor postProcessor = (BeanFactoryPostProcessor)var6.next();
    if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
        BeanDefinitionRegistryPostProcessor registryProcessor = (BeanDefinitionRegistryPostProcessor)postProcessor;
        registryProcessor.postProcessBeanDefinitionRegistry(registry);
        registryProcessors.add(registryProcessor);
    } else {
        regularPostProcessors.add(postProcessor);
    }
}

接下来,优先处理实现了PriorityOrdered或Ordered接口的元素(两段差不多,所以只列出PriorityOrdered的)。getBeanNamesForType方法就是从BeanFactory中根据PostProcessor的类型来查找BeanName。也就是说,上面一段用的BeanFactoryPostProcessor列表,并不包含XML配置的后处理器:

currentRegistryProcessors = new ArrayList();
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
String[] var16 = postProcessorNames;
var9 = postProcessorNames.length;
int var10;
String ppName;
for(var10 = 0; var10 < var9; ++var10) {
    ppName = var16[var10];
    if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
        currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
        processedBeans.add(ppName);
    }
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);

invokeBeanDefinitionRegistryPostProcessors实际就是调用BeanDefinitionRegistryPostProcessor实现类的postProcessBeanDefinitionRegistry方法。

对于那些未实现PriorityOrdered或Ordered接口的元素,在接下来的循环里进行处理:

boolean reiterate = true;
while(reiterate) {
    reiterate = false;
    postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
    String[] var19 = postProcessorNames;
    var10 = postProcessorNames.length;
    for(int var26 = 0; var26 < var10; ++var26) {
        String ppName = var19[var26];
        if (!processedBeans.contains(ppName)) {
            currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
            processedBeans.add(ppName);
            reiterate = true;
        }
    }
    sortPostProcessors(currentRegistryProcessors, beanFactory);
    registryProcessors.addAll(currentRegistryProcessors);
    invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
    currentRegistryProcessors.clear();
}

上面的代码里,仅仅处理了BeanDefinitionRegistryPostProcessor,对于BeanFactoryPostProcessors还没有处理,会在这里统一进行处理,实际就是调用BeanFactoryPostProcessor实现类的postProcessBeanFactory方法。:

invokeBeanFactoryPostProcessors((Collection)registryProcessors, (ConfigurableListableBeanFactory)beanFactory);
invokeBeanFactoryPostProcessors((Collection)regularPostProcessors, (ConfigurableListableBeanFactory)beanFactory);

如果传入的beanFactory并不是是BeanDefinitionRegistry,则直接调用invokeBeanFactoryPostProcessors(Collection,ConfigurableListableBeanFactory)方法。

上面一部分,处理了所有的BeanDefinitionRegistryPostProcessor和编程式配置的BeanFactoryPostProcessors,但是XML配置的BeanFactoryPostProcessor还没处理,后面的代码就是进行这部分工作。逻辑和上面的类似。

3.registerBeanPostProcessors

上一步完成了BeanFactoryPostProcessor的注册和调用,这一步的工作就是进行BeanPostProcessor的注册(未调用,调用过程发生在Bean实例化时)。在prepareBeanFactory方法中,实际上已经注册了一部分特殊的(实现了Aware接口)Bean。与BeanFactoryPostProcessor一样,该方法同样借助了PostProcessorRegistrationDelegate类。

因此两个方法代码也差不多,都是先处理实现PriorityOrdered或Ordered接口的元素,再处理普通元素,唯二的区别是:1.此处是仅考虑了XML配置的BeanPostProcessor;2.此处只进行了注册(register),而非调用(invoke)。结合来看,BeanFactoryPostProcessor是提取并调用,因此需要将两种配置方式全部考虑, 而这里BeanPostProcessor仅仅进行了注册,还不需要考虑调用,因此无需处理API配置的后处理器。

一个有意思的地方是,在所有BeanPostProcessor之前,添加了一个BeanPostProcessorChecker。它的作用是检查配置的BeanPostProcessor是否已经被实例化。上一步调用BeanFactoryPostProcessor可以修改Bean的行为,如果此时尝试获取Bean,就可能导致它们提前实例化。作为Bean的一种,BeanPostProcessor也有可能已经被实例化过了,那么当BeanPostProcessor实例化时,就不需要再次实例化了。

beanFactory.addBeanPostProcessor(new PostProcessorRegistrationDelegate.BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值