Posts tagged Spring

Spring IoC之容器扩展点

0

容器扩展点

Spring中容器的扩展点一共有三个地方可以扩展,分别对应于三个接口:BeanPostProcessor,BeanFactoryPostProcessor和FactoryBean

BeanPostProcessor

BeanPostProcessor:这个接口可以使Bean在初始化前面或者后面对Bean实例作出修改,下面来看一个例子,作用是仅仅打出Bean的名字以及信息,首先需要在实现BeanPostProcessor接口:

public class TracingBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("Bean:" + beanName + " ---- " + bean.toString());
        return bean;
    }
}

然后将这个BeanPostProcessor定义到Bean配置信息里面去:

<bean class="com.alibaba.khotyn.test.TracingBeanPostProcessor"/>

这样在容器初始化一个Bean之后,容器就会调用TracingBeanPostProcessor将Bean的信息打印到控制台上。注意这里面配置的BeanPostProcessor甚至没有BeanName。

BeanFactoryPostProcessor

BeanFactoryPostProcessor和前面的BeanPostProcessor在名字上看上去很像,在功能上也是类似的,区别的地方在于BeanFactoryPostProcessor可以对Bean定义信息的元数据进行修改(BeanDefinition),而后者是在Bean初始化的时候可以对Bean实例进行修改,可以说BeanFactoryPostProcessor修改地更为彻底一些。在Spring中,已经有一些类实现了BeanFactoryPostPorcessor来提供一些功能,比如PropertyPlaceholderConfigurer,可以对用Property文件中的属性替换XML文件中的属性,下面是一个简单的例子:

<bean id="beanA" class="com.alibaba.khotyn.test.BeanA">
    <property name="name" value="${name}"></property>
    <property name="address" value="${address}"></property>
</bean>
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations">
         <list>
            <value>configure.properties</value>
         </list>
    </property>
</bean>

这样,Properties中的属性就可以去替换XML中相应的属性了

FactoryBean

这个接口乍看可能不怎么像容器的扩展点。但是考虑到最终的Bean使FactoryBean生产出来,所以Bean的初始化完全掌控在FactoryBean当中,这个接口的确是容器的一个扩展点。

Spring IoC之Bean生命周期管理

0

Bean的生命周期管理

Spring的Bean容器只管理非单例Bean的生命周期,单例Bean的生命周期不在管理范围内。用一张很老的图来展示下Bean的生命周期管理
Bean生命周期
关于这张图里面我们可以主要关注3个类:

  • BeanPostProcessor:这个接口定义了两个方法,分别是:postProcessBeforeInitialization和postProcessAfterInitialization,分别在初始化Bean之前和之后被调用,通过这两个方法,接口的实现者可以修改Bean的定义信息。如果接口的实现者需要定制多个BeanPostProcessor,那么它也需要实现Ordered接口。和这个类的非常相似的一个类是BeanFactoryPostProcessor,这两个类的一个区别使后者操纵的使Bean配置信息的元数据,这就意味着Spring允许在容器初始化Bean之前去修改Bean配置信息的元数据。这个接口的一个实现就是PropertyPlaceholderConfigurer和PropertyOverrideConfigurer,具体的例子可以参考Spring Reference
  • InitializingBean:这个接口定义了一个afterPropertiesSet()方法,这个方法在Bean的属性被全部设置后发出。
  • DesposableBean:这个接口定义了一个destroy()方法,这个方法在可以在Bean销毁时调用,比如可以做释放资源用。

Spring IoC之获取Bean

1

非单例Bean的获取

Spring Bean获取的主体代码在AbstractBeanFactory的doGetBean方法中,看下面的方法:

protected <T> T doGetBean(
          final String name, final Class&lt;T&gt; requiredType, final Object[] args, boolean typeCheckOnly)
          throws BeansException {
     // 转换BeanName,如果name参数传过来是aliasName的话,在这里会根据aliasName取出真正的BeanName
     final String beanName = transformedBeanName(name);
     Object bean;

     // 首先检查单例缓存里面有没有这个Bean
     Object sharedInstance = getSingleton(beanName);
     if (sharedInstance != null && args == null) {
          if (logger.isDebugEnabled()) {
               if (isSingletonCurrentlyInCreation(beanName)) {
                    logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
                         "' that is not fully initialized yet - a consequence of a circular reference");
               }
               else {
                    logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
               }
          }
         // 将取出的object(可能是一个FactoryBean)转换成Bean的类型
         bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
     }

     else {
          // 检查是否已经在创建中,如果正在创建中,就确定存在循环引用
          if (isPrototypeCurrentlyInCreation(beanName)) {
               throw new BeanCurrentlyInCreationException(beanName);
          }

          // 检查ParentBeanFactory是否存在Bean定义信息
          BeanFactory parentBeanFactory = getParentBeanFactory();
          if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
               // 如果ParentBeanFacotory不为空而且此BeanFactory不包含Bean定义信息
               String nameToLookup = originalBeanName(name);
               if (args != null) {
                    // 如果参数不为空,带上参数将获取Bean委托给ParentBeanFactory
                    return (T) parentBeanFactory.getBean(nameToLookup, args);
               }
               else {
                    // 如果参数为空,则将获取Bean委托给ParentBeanFactory的标准getBean方法
                    return parentBeanFactory.getBean(nameToLookup, requiredType);
               }
          }

          // typeCheckOnly,实例用来做类型检测的,而不是真正地拿来用的
          if (!typeCheckOnly) {
               markBeanAsCreated(beanName);
          }

          // 如果Bean的定义信息在子Bean定义信息中,则合并到当前的Bean定义信息中
          final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
          checkMergedBeanDefinition(mbd, beanName, args);

          // 处理depends on的情况,确保当前Bean依赖的Bean先创建
          String[] dependsOn = mbd.getDependsOn();
          if (dependsOn != null) {
               for (String dependsOnBean : dependsOn) {
                    getBean(dependsOnBean);
                    registerDependentBean(dependsOnBean, beanName);
               }
          }

          // 开始创建Bean实例
          if (mbd.isSingleton()) {
               sharedInstance = getSingleton(beanName, new ObjectFactory() {
                    public Object getObject() throws BeansException {
                         try {
                              return createBean(beanName, mbd, args);
                         }
                         catch (BeansException ex) {
                              // Explicitly remove instance from singleton cache: It might have been put there
                              // eagerly by the creation process, to allow for circular reference resolution.
                              // Also remove any beans that received a temporary reference to the bean.
                              destroySingleton(beanName);
                              throw ex;
                         }
                    }
               });
               bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
          }

          elseif (mbd.isPrototype()) {
               // Bean的Scope是Prototype,创建一个新实例
               Object prototypeInstance = null;
               try {
                    // 在Bean创建之前,默认行为是:将当前Bean标记为正在创建中,用于前面检测循环引用
                    beforePrototypeCreation(beanName);
                    prototypeInstance = createBean(beanName, mbd, args);
               }
               finally {
                    // 在Bean创建之后,默认行为是:将当前Bean标记为不在创建中,用于前面检测循环引用
                    afterPrototypeCreation(beanName);
               }
                    bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
               }

          else {
               String scopeName = mbd.getScope();
               final Scope scope = this.scopes.get(scopeName);
               if (scope == null) {
                    throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");
               }
               try {
                    Object scopedInstance = scope.get(beanName, new ObjectFactory() {
                         public Object getObject() throws BeansException {
                              beforePrototypeCreation(beanName);
                              try {
                                   return createBean(beanName, mbd, args);
                              }
                              finally {
                                   afterPrototypeCreation(beanName);
                              }
                         }
                    });
                    bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
               }
               catch (IllegalStateException ex) {
                    throw new BeanCreationException(beanName,
                         "Scope '" + scopeName + "' is not active for the current thread; " +
                         "consider defining a scoped proxy for this bean if you intend to refer to it from a singleton",
                         ex);
               }
          }
     }

     // 检测Bean实例和需要的类型是否匹配
     if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
          throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
     }
     return (T) bean;
}

从这里可以看出,Spring是首先尝试从单例缓存中获取Bean,如果找不到,然后在根据不同的Bean Scope调用不同的方法去创建Bean。

Spring IoC之容器初始化

0

容器初始化

Spring容器的初始化主要分为三个步骤,分别使Bean信息的定位,解析与注册。以XML文件形式的Bean信息为例,Spring首先找到XML文件的位置,然后读取此文件,并且将文件解析成相应的BeanDefinition,最后将获取到的BeanDefinition注册到BeanFactory中去。

Bean信息定位,解析与注册

Spring容器的初始化的主要工作是定位Bean配置文件,读取并解析Bean配置文件,最后生成相应的BeanDefinition,先看一张简单的序列图对Spring容器的初始化做大概的了解:
Spring IoC容器初始化时序图
从这副顺序图中我们可以看出,Spring容器的初始化过程主要由四个类来完成,我们可以参考下类的注释以了解这几个类的职责:

  • XmlBeanDefinitionReader:用于XML Bean定义信息的BeanDefinitionReader,将事实上的XML文件读取代理给BeanDefinitionDocumentReader接口的一个实现。
  • BeanDefinitionDocumentReader:用于解析Spring Bean定义信息的服务提供接口(SPI),在实际解析DOM文档的时候,由XmlBeanDefinitionReader来调用。
  • BeanDefinitionParserDelegate:用于解析XML Bean定义信息的有状态代理类。负责一个Bean的定义信息解析策划能够BeanDefinition对象。
  • BeanDefinitionRegistry:负责将得到的Bean定义信息注册到BeanFactory中。

Spring IoC 概览

4

主要的设计思想

关于Spring设计的主要设计思想,其实Rod Johnson在他的那本《Expert One on One – J2EE Development without EJB》中有详细的解释。这里做下概括,Spring出现的主要原因是为了提供一个轻量级的容器,这个容器除了提供容器的基本服务以外,还应该具备以下的特点:

  • 容器应该能够管理在其中的应用程序代码,但是不应该将容器侵入到应用程序的代码之中。也就是说,应用程序的代码应该是独立于容器的
  • 容器应该能够快速启动
  • 在容器中部署一个对象应该不需要任何特殊的部署步骤
  • 容器应该依赖于最少的API以能够在不同的环境下运行
  • ……..

而IoC正是为了解决以上的第一个特点的,在IoC中,组件不需要去查找它所依赖的对象,而是由容器来负责将组件所依赖的对象通过JavaBean Properties(Setter方法)或者构造函数来注入给组件。

主要类及其职责

Spring IoC Class Diagram
这个类图相对来说比较简单些,主要包括了继承BeanFactory接口的各个接口及其实现,主要目的是为了摸清BeanFactory这一条线里面各个类之间的关系。整个类的继承体系相对比较简单,其中有几个类/接口的作用需要重点把握:

  • BeanFactory:这个接口的作用是定义了访问Bean容器所需的基本方法,是整个Spring Bean容器的底层接口
  • AbstractBeanFactory:这个类的作用从名字上就可以看出,使BeanFactory的一个抽象实现,提供了诸如getBean等方法的默认实现
  • SingletonBeanRegistry:这个接口的主要作用对单例Bean进行管理。
  • 其他的一些类/接口基本上是对BeanFactory接口进行了扩展,主要的功能可以看类/接口的名字或者注释来了解

感想

从Spring的类图中可以看出,Spring的类的命名的非常好,基本上让人一下就看出了这个类的职责所在,并且这个职责基本上是单一的,不会有一个类去做多件事情。Spring对BeanFactory的扩展接口也是只加了一种特性,然后通过实现多个接口以实现多个特性,这样的设计使接口的实现方可以方便的根据需求挑选接口来实现,而不用担心实现过多的功能。

Go to Top