Spring源码解析笔记8——容器的功能扩展ApplicationContext

ApplicationContext包含BeanFactory的所有功能,并且可以对BeanFactory现有的功能进行扩展。绝大多数典型的企业应用和系统,使用的都是ApplicationContext而不是直接使用BeanFactory。下面看一下ApplicationContext相对于BeanFactory扩展了哪些功能。

//BeanFactory的加载配置文件的方式:
BeanFactory bf = new XmlBeanFactory(new ClassPathResource("beanFactoryTest.xml"));

//ApplicationContext加载配置文件的方式:
ApplicationContext bf = new ClassPathXmlApplicationContext("");

继续根据ClassPathXmlApplicationContext进行跟踪:

public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
        this(new String[]{configLocation}, true, (ApplicationContext)null);
}

//根据this继续走:
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException {
        super(parent);

        //将配置文件的路径以数组的方式传入。
        this.setConfigLocations(configLocations);
        if(refresh) {

            //解析和功能实现。
            this.refresh();
        }

    }

继续跟踪setConfigLocations:

public void setConfigLocations(String... locations) {
        if(locations != null) {
            Assert.noNullElements(locations, "Config locations must not be null");
            this.configLocations = new String[locations.length];

            for(int i = 0; i < locations.length; ++i) {

                //解析给定路径,如果数组总包含特殊符号,如${var},那么resolvePath中会搜寻系统的变量被替换。
                this.configLocations[i] = this.resolvePath(locations[i]).trim();
            }
        } else {
            this.configLocations = null;
        }

    }

继续跟踪refresh函数:

 public void refresh() throws BeansException, IllegalStateException {
        Object var1 = this.startupShutdownMonitor;
        synchronized(this.startupShutdownMonitor) {

            //准备刷新上下文环境,例如对系统属性或者环境变量进行准备及验证。
            this.prepareRefresh();

            //初始化BeanFactory,并进行XML文件的读取,这一步骤要服用BeanFactory的配置文件读取的以及其他功能。
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();

            //对BeanFactory进行各种功能填充。@Qualifier和@Autowired是在此步骤增加的支持。
            this.prepareBeanFactory(beanFactory);

            try {

                //子类覆盖方法做额外的处理。
                this.postProcessBeanFactory(beanFactory);

                //激活各种BeanFactory处理器
                this.invokeBeanFactoryPostProcessors(beanFactory);

                //注册拦截Bean创建的Bean处理器,这里只是注册,真正的调用是在getBean的时候
                this.registerBeanPostProcessors(beanFactory);

                //为上下文初始化Mesagge源,即不同语言的消息体,国际化处理。
                this.initMessageSource();

                //初始化应用消息广播器,并放入applicationEventMulticaster中
                this.initApplicationEventMulticaster();

                //留给子类来初始化其他的bean
                this.onRefresh();

                //在所有注册的bean中查找Listener bean,注册到消息广播器中。
                this.registerListeners();

                //初始化剩下的单例。
                this.finishBeanFactoryInitialization(beanFactory);

                //完成刷新过程。
                this.finishRefresh();
            } catch (BeansException var9) {
                if(this.logger.isWarnEnabled()) {
                    this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
                }

                this.destroyBeans();
                this.cancelRefresh(var9);
                throw var9;
            } finally {
                this.resetCommonCaches();
            }

        }
    }

继续跟踪refresh方法中的this.prepareRefresh()方法:

protected void prepareRefresh() {
        this.startupDate = System.currentTimeMillis();
        this.closed.set(false);
        this.active.set(true);
        if(this.logger.isInfoEnabled()) {
            this.logger.info("Refreshing " + this);
        }

        //留给子类覆盖。
        this.initPropertySources();

        //验证需要的属性文件是否都已经放入环境中。
        this.getEnvironment().validateRequiredProperties();
        this.earlyApplicationEvents = new LinkedHashSet();
    }

上述留给子类覆盖的方法initPropertySources使用举例:

class MyClassPathXmlApplicationContext extends ClassPathXmlApplicationContext{

        public MyClassPathXmlApplicationContext(String ... configLocations) {
            super(configLocations);
        }

        @Override
        protected void initPropertySources() {
            getEnvironment().setRequiredProperties("VAR");
        }
    }

 //读取配置文件时这样调用:
 ApplicationContext bf2 = new MyClassPathXmlApplicationContext("");

继续跟踪refresh方法中的this.obtainFreshBeanFactory()方法:

//通过了这个函数以后,ApplicationContext就已经拥有了BeanFactory的全部功能。
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {

        //初始化BeanFactory,并进行XML文件读取,并将得到的BeanFactory记录在当前实体的属性中,
        this.refreshBeanFactory();

        //返回当前实体的beanFactory
        ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();
        if(this.logger.isDebugEnabled()) {
            this.logger.debug("Bean factory for " + this.getDisplayName() + ": " + beanFactory);
        }

        return beanFactory;
    }


//上面的this.refreshBeanFactory()方法源码:
protected final void refreshBeanFactory() throws BeansException {
        if(this.hasBeanFactory()) {
            this.destroyBeans();
            this.closeBeanFactory();
        }

        try {

            //创建DefaultListableBeanFactory
            DefaultListableBeanFactory ex = this.createBeanFactory();

            //为了反序列化指定id,如果需要,让这个BeanFactory从id反序列化到BeanFactory对象。
            ex.setSerializationId(this.getId());

            //定制beanFactory,设置相关属性,包括是否允许覆盖同名称的不同定义的对象以及循环依赖
            //设置@Autowired和@Qualitier注册解析器QualifierAnnotationAutowireCandidateResolver
            this.customizeBeanFactory(ex);

            //初始化DocumentReader,并进行XML文件读取及解析。
            this.loadBeanDefinitions(ex);
            Object var2 = this.beanFactoryMonitor;
            synchronized(this.beanFactoryMonitor) {
                this.beanFactory = ex;
            }
        } catch (IOException var5) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var5);
        }
    }


//跟踪上面的this.customizeBeanFactory(ex)方法:
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {

        //是否允许覆盖同名称的不同定义的对象。
        if(this.allowBeanDefinitionOverriding != null) {
            beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding.booleanValue());
        }

        //是否允许bean之间存在循环依赖。
        if(this.allowCircularReferences != null) {
            beanFactory.setAllowCircularReferences(this.allowCircularReferences.booleanValue());
        }

    }

//关于上面方法中allowBeanDefinitionOverriding和allowCircularReferences的变量设置举例:

class MyClassPathXmlApplicationContext extends ClassPathXmlApplicationContext{

        @Override
        protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
            super.setAllowBeanDefinitionOverriding(false);
            super.setAllowCircularReferences(false);
            super.customizeBeanFactory(beanFactory);
        }
    }

//继续走this.loadBeanDefinitions(ex),此方法是用来加载BeanDefinition
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

        //对上一步创建的beanDefinitionReader进行环境变量的设置。
        beanDefinitionReader.setEnvironment(this.getEnvironment());
        beanDefinitionReader.setResourceLoader(this);
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

        //对beanDefinitionReader进行设置,可以覆盖。
        this.initBeanDefinitionReader(beanDefinitionReader);
        this.loadBeanDefinitions(beanDefinitionReader);
    }

//继续查看this.loadBeanDefinitions(beanDefinitionReader)
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
        Resource[] configResources = this.getConfigResources();
        if(configResources != null) {
            reader.loadBeanDefinitions(configResources);
        }

        String[] configLocations = this.getConfigLocations();
        if(configLocations != null) {
            reader.loadBeanDefinitions(configLocations);
        }

    }

继续跟踪refresh方法中的this.prepareBeanFactory(beanFactory)

//源码如下:
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {

        //设置beanFactory的classLoader为当前的classLoader。
        beanFactory.setBeanClassLoader(this.getClassLoader());

        //默认可以使用EL表达式
        beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));

        //为beanFactory增加了一个默认propertyEditor,主要是对bean的属性等设置管理的一个工具。
        beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, this.getEnvironment()));

        //添加PostProcessor
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

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

        //设置几个自动装配的特殊规则
        beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
        beanFactory.registerResolvableDependency(ResourceLoader.class, this);
        beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
        beanFactory.registerResolvableDependency(ApplicationContext.class, this);
        beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

        //增加对ApectJ的支持
        if(beanFactory.containsBean("loadTimeWeaver")) {
            beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
            beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
        }

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

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

        //增加默认环境bean.
        if(!beanFactory.containsLocalBean("systemEnvironment")) {
            beanFactory.registerSingleton("systemEnvironment", this.getEnvironment().getSystemEnvironment());
        }

    }

/**
    setBeanExpressionResolver注册语言解析器,就可以对SPEL进行解析了,
    真正调用这个解析器是在Spring对bean进行初始化时的属性填充这步,
    在这一步中Spring会调用AbstractAutowireCapableBeanFactory类中的applyPropertyValues函数来完成。
**/

上述方法中对bean的属性等设置管理说明:在SpringDI注入的时候可以把普通属性注入进来,但是像Date这种类型就无法被识别。例如:

class UserManager{
        private Date dataValue;

        public Date getDataValue() {
            return dataValue;
        }

        public void setDataValue(Date dataValue) {
            this.dataValue = dataValue;
        }
 }

//上述代码中需要对日期类型的属性进行注入:
<bean id="userManager" class com.test.UserManager>
    <property name="dataValue">
        <value>2013-03-15</value>
    </property>
</bean>

//测试
ApplicationContext bf = new ClassPathXmlApplicationContext("");
UserManager userManager = (UserManager)bf.getBean("userManager");
System.out.println(userManager);

如果直接这样使用,程序会报错,类型转换不成功。String无法转换成Date类型。spring针对这类问题提供了两种解决办法:
1.自定义属性编辑器,通过继承PropertyEditorSupport.

//编写自定义的属性编辑器
class DatePropertyEditor extends PropertyEditorSupport{
        private String format = "yyyy-MM-dd";

        public void setFormat(String format) {
            this.format = format;
        }

        public void setAsText(String arg0) throws IllegalArgumentException{
            SimpleDateFormat sdf = new SimpleDateFormat(format);
            try {
                Date d = sdf.parse(arg0);
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
    }

    //将自定义属性编辑器注册到Spring中。
    <bean class="org.Springframework.beans.factory.config.CustomEditorConfigurer">
        <property name="customEditors">
            <map>
                <entry key="java.util.Date">
                <bean class="com.test.DatePropertyEditor">
                    <property name="format" value="yyyy-MM-dd"/>
                </bean>
            </map>
        </property>
    </bean>   

2.注册Spring自带的属性编辑器CustomDateEditor


//定义属性编辑器
class DatePropertyEditorRegostrar implements PropertyEditorRegistrar{

        @Override
        public void registerCustomEditors(PropertyEditorRegistry propertyEditorRegistry) {
            propertyEditorRegistry.registerCustomEditor(Date.class,new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"),true));
        }
    }

//注册到spring
<bean class="org.Springframework.beans.factory.config.CustomEditorConfigurer">
    <property name="propertyEditorRegistrars">
        <list>
            <bean class="com.test.DatePropertyEditorRegistrar"></bean>
        </list>
    </property>
</bean>

ResourceEditorRegistrar中也实现了registerCustomEditors方法:

//源码如下:
public void registerCustomEditors(PropertyEditorRegistry registry) {
        ResourceEditor baseEditor = new ResourceEditor(this.resourceLoader, this.propertyResolver);
        this.doRegisterEditor(registry, Resource.class, baseEditor);
        this.doRegisterEditor(registry, ContextResource.class, baseEditor);
        this.doRegisterEditor(registry, InputStream.class, new InputStreamEditor(baseEditor));
        this.doRegisterEditor(registry, InputSource.class, new InputSourceEditor(baseEditor));
        this.doRegisterEditor(registry, File.class, new FileEditor(baseEditor));
        if(pathClass != null) {
            this.doRegisterEditor(registry, pathClass, new PathEditor(baseEditor));
        }

        this.doRegisterEditor(registry, Reader.class, new ReaderEditor(baseEditor));
        this.doRegisterEditor(registry, URL.class, new URLEditor(baseEditor));
        ClassLoader classLoader = this.resourceLoader.getClassLoader();
        this.doRegisterEditor(registry, URI.class, new URIEditor(classLoader));
        this.doRegisterEditor(registry, Class.class, new ClassEditor(classLoader));
        this.doRegisterEditor(registry, Class[].class, new ClassArrayEditor(classLoader));
        if(this.resourceLoader instanceof ResourcePatternResolver) {
            this.doRegisterEditor(registry, Resource[].class, new ResourceArrayPropertyEditor((ResourcePatternResolver)this.resourceLoader, this.propertyResolver));
        }
}

//继续追踪doRegisterEditor:
 private void doRegisterEditor(PropertyEditorRegistry registry, Class<?> requiredType, PropertyEditor editor) {
        if(registry instanceof PropertyEditorRegistrySupport) {
            ((PropertyEditorRegistrySupport)registry).overrideDefaultEditor(requiredType, editor);
        } else {

            //前面提到的自定义属性的关键代码在此被调用
            registry.registerCustomEditor(requiredType, editor);
        }

    }

查找了registerCustomEditors方法被调用的位置,发现AbstractBeanFactory类中的initBeanWrapper方法调用了此方法,这个方法是在bean初始化时使用的一个方法,主要作用就是将BeanDefinition转换为BeanWrapper后用于属性的填充。在bean初始化以后会调用ResourceEditorRegistrar的registerCustomEditors方法进行批量的通用属性编辑器注册。注册后,在属性填充的环节便可以直接让Spring使用这些编辑器进行属性的解析了。



BeanWrapper除了实现了BeanWrapperImpl还继承了PropertyEditorRegistrySupport,在该类中有这样一个方法:

/**
    通过这个方法可以知道在spring中定义了上面一系列常用的属性编辑器,
    如果我们定义的bean中的某个属性的类型不在上面的常用配置中,才需要我们进行个性化属性编辑器的注册。
**/
private void createDefaultEditors() {
        this.defaultEditors = new HashMap(64);
        this.defaultEditors.put(Charset.class, new CharsetEditor());
        this.defaultEditors.put(Class.class, new ClassEditor());
        this.defaultEditors.put(Class[].class, new ClassArrayEditor());
        this.defaultEditors.put(Currency.class, new CurrencyEditor());
        this.defaultEditors.put(File.class, new FileEditor());
        this.defaultEditors.put(InputStream.class, new InputStreamEditor());
        this.defaultEditors.put(InputSource.class, new InputSourceEditor());
        this.defaultEditors.put(Locale.class, new LocaleEditor());
        if(pathClass != null) {
            this.defaultEditors.put(pathClass, new PathEditor());
        }

        this.defaultEditors.put(Pattern.class, new PatternEditor());
        this.defaultEditors.put(Properties.class, new PropertiesEditor());
        this.defaultEditors.put(Reader.class, new ReaderEditor());
        this.defaultEditors.put(Resource[].class, new ResourceArrayPropertyEditor());
        this.defaultEditors.put(TimeZone.class, new TimeZoneEditor());
        this.defaultEditors.put(URI.class, new URIEditor());
        this.defaultEditors.put(URL.class, new URLEditor());
        this.defaultEditors.put(UUID.class, new UUIDEditor());
        if(zoneIdClass != null) {
            this.defaultEditors.put(zoneIdClass, new ZoneIdEditor());
        }

        this.defaultEditors.put(Collection.class, new CustomCollectionEditor(Collection.class));
        this.defaultEditors.put(Set.class, new CustomCollectionEditor(Set.class));
        this.defaultEditors.put(SortedSet.class, new CustomCollectionEditor(SortedSet.class));
        this.defaultEditors.put(List.class, new CustomCollectionEditor(List.class));
        this.defaultEditors.put(SortedMap.class, new CustomMapEditor(SortedMap.class));
        this.defaultEditors.put(byte[].class, new ByteArrayPropertyEditor());
        this.defaultEditors.put(char[].class, new CharArrayPropertyEditor());
        this.defaultEditors.put(Character.TYPE, new CharacterEditor(false));
        this.defaultEditors.put(Character.class, new CharacterEditor(true));
        this.defaultEditors.put(Boolean.TYPE, new CustomBooleanEditor(false));
        this.defaultEditors.put(Boolean.class, new CustomBooleanEditor(true));
        this.defaultEditors.put(Byte.TYPE, new CustomNumberEditor(Byte.class, false));
        this.defaultEditors.put(Byte.class, new CustomNumberEditor(Byte.class, true));
        this.defaultEditors.put(Short.TYPE, new CustomNumberEditor(Short.class, false));
        this.defaultEditors.put(Short.class, new CustomNumberEditor(Short.class, true));
        this.defaultEditors.put(Integer.TYPE, new CustomNumberEditor(Integer.class, false));
        this.defaultEditors.put(Integer.class, new CustomNumberEditor(Integer.class, true));
        this.defaultEditors.put(Long.TYPE, new CustomNumberEditor(Long.class, false));
        this.defaultEditors.put(Long.class, new CustomNumberEditor(Long.class, true));
        this.defaultEditors.put(Float.TYPE, new CustomNumberEditor(Float.class, false));
        this.defaultEditors.put(Float.class, new CustomNumberEditor(Float.class, true));
        this.defaultEditors.put(Double.TYPE, new CustomNumberEditor(Double.class, false));
        this.defaultEditors.put(Double.class, new CustomNumberEditor(Double.class, true));
        this.defaultEditors.put(BigDecimal.class, new CustomNumberEditor(BigDecimal.class, true));
        this.defaultEditors.put(BigInteger.class, new CustomNumberEditor(BigInteger.class, true));
        if(this.configValueEditorsActive) {
            StringArrayPropertyEditor sae = new StringArrayPropertyEditor();
            this.defaultEditors.put(String[].class, sae);
            this.defaultEditors.put(short[].class, sae);
            this.defaultEditors.put(int[].class, sae);
            this.defaultEditors.put(long[].class, sae);
        }

    }

继续跟踪this.prepareBeanFactory(beanFactory)方法中的beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));,该方法主要还是用来注册BeanPostProcessor.

/**
    该方法的重要逻辑都在ApplicationContextAwareProcessor中。
    前面几章提到过Spring激活bean的init-method的前后,会调用BeanPostProcessor中的
    postProcessBeforeInitialization和postProcessAfterInitialization方法。
    ApplicationContextAwareProcessor类的源码实现:
**/
class ApplicationContextAwareProcessor implements BeanPostProcessor {
    private final ConfigurableApplicationContext applicationContext;
    private final StringValueResolver embeddedValueResolver;

    public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
        this.embeddedValueResolver = new EmbeddedValueResolver(applicationContext.getBeanFactory());
    }

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

        return bean;
    }

    //通过此方法可以看出实现了Aware接口的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);
            }
        }

    }

    public Object postProcessAfterInitialization(Object bean, String beanName) {
        return bean;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值