Spring源码阅读:IOC容器之BeanFactory

 

Spring IOC容器系列的设计与实现

 

命名解释

    容器:这里说的容器不是Java中的集合容器,也不是Web程序运行的环境。而是一组API组成的框架。

 

 

    IOC:控制反转。控制是对Bean的创建的控制,反转从程序员手写创建Bean转为由容器来创建。IOC又名DI(依赖注入),说明了Spring中IOC的容器处理Bean创建主要集中与依赖的注入。因此还可以叫IOC为依赖反转,就是把bean的创建依赖的注入的工作交给了容器

    DIP(依赖倒置原则):这是设计模式中的一条很重要的设计原则。所谓依赖倒置原则,指的是,要依赖于抽象,不要依赖于具体类。要做到依赖倒置,典型应该做到:

·高层抽象不应该依赖于底层模块,二者应该依赖于抽象。

·抽象不应该依赖于具体实现,具体实现应该依赖于抽象。

 

IOC其实也是DIP。

 

IOC中有三种依赖注入方式:接口注入、setter注入,构造器注入。在Spring中主要使用了setter注入和构造器注入,两者相比而言,setter更为常用。

 

 

Spring IOC容器的设计与实现:BeanFactory与ApplicationContext

 

    在Spring 官方提供的参考文档(Spring 2.5)中,提到了4中Bean工厂:BeanFactory, ApplicationContext, 静态Bean工厂,SimpleJndiBeanFactory。

    在Spring IOC容器设计上是这样的:

    ·BeanFactory作为最顶层的接口出现,它提供了可配置的框架以及容器基本功能。具体的实现是在DefaultListableBeanFactory中。

    ·ApplicationContext是BeanFactory的一个子接口,它在BeanFactory已有功能的基础上,添加了新的特性:1)与AOP集成、2)消息资源处理(例如国际化的支持),3)事件发布,4)提供应用层特定的上下文(例如WebApplicationContext)

    ·静态Bean工厂是BeanFactory的一个子类,具体来说就是StaticListableBeanFactory,它只支持Singleton,不支持Prototype和别名。

    ·SimpleJndiBeanFactory 是对于JDNI的支持。

通常我们会选择使用ApplicationContext。下面就来看看他们分别是如何实现的:

 

 Spring源码阅读:IOC容器之BeanFactory

 

 

静态工厂

StaticListableBeanFactory类的说明:

Spring源码阅读:IOC容器之BeanFactory
/**

 * Static {@link org.springframework.beans.factory.BeanFactory} implementation

 * which allows to register existing singleton instances programmatically.

 * Does not have support for prototype beans or aliases.

 *

 * <p>Serves as example for a simple implementation of the

 * {@link org.springframework.beans.factory.ListableBeanFactory} interface,

 * managing existing bean instances rather than creating new ones based on bean

 * definitions, and not implementing any extended SPI interfaces (such as

 * {@link org.springframework.beans.factory.config.ConfigurableBeanFactory}).

 *

 * <p>For a full-fledged factory based on bean definitions, have a look

 * at {@link DefaultListableBeanFactory}.

 */
StaticListableBeanFactory说明

 

从类的说明中知道:静态工厂允许我们在程序中以编程的方式注册单例的bean(添加到bean集合中)。它不支持prototype的bean,也不支持别名。

 类的部分代码:

Spring源码阅读:IOC容器之BeanFactory
public class StaticListableBeanFactory implements ListableBeanFactory {

 

   /** Map from bean name to bean instance */

   private final Map<String, Object> beans = new HashMap<String, Object>();

 

 

   /**

    * Add a new singleton bean.

    * Will overwrite any existing instance for the given name.

    * @param name the name of the bean

    * @param bean the bean instance

    */

   public void addBean(String name, Object bean) {

      this.beans.put(name, bean);

   }

 
View Code

// 其实就是将单例的Bean添加到Map中。

对于单例的Bean,一般来说就是在程序中直接编程的方式使用了,很少将其添加到静态Bean工厂中。

 

在这个类的说明的最后,提到了一个类:DefaultListableBeanFactory,这个类其实是BeanFactory的最完全的实现方式了。下面就来看看BeanFactory。

 

BeanFactory

 

BeanFactory接口的说明

Spring源码阅读:IOC容器之BeanFactory
/**

 * The root interface for accessing a Spring bean container.

 * This is the basic client view of a bean container;

 * further interfaces such as {@link ListableBeanFactory} and

 * {@link org.springframework.beans.factory.config.ConfigurableBeanFactory}

 * are available for specific purposes.

 *

 * <p>This interface is implemented by objects that hold a number of bean definitions,

 * each uniquely identified by a String name. Depending on the bean definition,

 * the factory will return either an independent instance of a contained object

 * (the Prototype design pattern), or a single shared instance (a superior

 * alternative to the Singleton design pattern, in which the instance is a

 * singleton in the scope of the factory). Which type of instance will be returned

 * depends on the bean factory configuration: the API is the same. Since Spring

 * 2.0, further scopes are available depending on the concrete application

 * context (e.g. "request" and "session" scopes in a web environment).

 *

 * <p>The point of this approach is that the BeanFactory is a central registry

 * of application components, and centralizes configuration of application

 * components (no more do individual objects need to read properties files,

 * for example). See chapters 4 and 11 of "Expert One-on-One J2EE Design and

 * Development" for a discussion of the benefits of this approach.

 *

 * <p>Note that it is generally better to rely on Dependency Injection

 * ("push" configuration) to configure application objects through setters

 * or constructors, rather than use any form of "pull" configuration like a

 * BeanFactory lookup. Spring‘s Dependency Injection functionality is

 * implemented using this BeanFactory interface and its subinterfaces.

 *

 * <p>Normally a BeanFactory will load bean definitions stored in a configuration

 * source (such as an XML document), and use the <code>org.springframework.beans</code>

 * package to configure the beans. However, an implementation could simply return

 * Java objects it creates as necessary directly in Java code. There are no

 * constraints on how the definitions could be stored: LDAP, RDBMS, XML,

 * properties file, etc. Implementations are encouraged to support references

 * amongst beans (Dependency Injection).

 *

 * <p>In contrast to the methods in {@link ListableBeanFactory}, all of the

 * operations in this interface will also check parent factories if this is a

 * {@link HierarchicalBeanFactory}. If a bean is not found in this factory instance,

 * the immediate parent factory will be asked. Beans in this factory instance

 * are supposed to override beans of the same name in any parent factory.

 *

 * <p>Bean factory implementations should support the standard bean lifecycle interfaces

 * as far as possible. The full set of initialization methods and their standard order is:<br>

 * 1. BeanNameAware‘s <code>setBeanName</code><br>

 * 2. BeanClassLoaderAware‘s <code>setBeanClassLoader</code><br>

 * 3. BeanFactoryAware‘s <code>setBeanFactory</code><br>

 * 4. ResourceLoaderAware‘s <code>setResourceLoader</code>

 * (only applicable when running in an application context)<br>

 * 5. ApplicationEventPublisherAware‘s <code>setApplicationEventPublisher</code>

 * (only applicable when running in an application context)<br>

 * 6. MessageSourceAware‘s <code>setMessageSource</code>

 * (only applicable when running in an application context)<br>

 * 7. ApplicationContextAware‘s <code>setApplicationContext</code>

 * (only applicable when running in an application context)<br>

 * 8. ServletContextAware‘s <code>setServletContext</code>

 * (only applicable when running in a web application context)<br>

 * 9. <code>postProcessBeforeInitialization</code> methods of BeanPostProcessors<br>

 * 10. InitializingBean‘s <code>afterPropertiesSet</code><br>

 * 11. a custom init-method definition<br>

 * 12. <code>postProcessAfterInitialization</code> methods of BeanPostProcessors

 *

 * <p>On shutdown of a bean factory, the following lifecycle methods apply:<br>

 * 1. DisposableBean‘s <code>destroy</code><br>

 * 2. a custom destroy-method definition

*/
BeanFactory说明

 

上面提到:

1、BeanFactory是Spring Bean容器的根接口,也是 最基本的接口。它的子接口ListableBeanFactory和ConfigurableBeanFactory是为了特定的目的而设计的。

2、BeanFactory的实现类需要拥有一个BeanDefinition的集合,BeanDefinition的名字是唯一,其实就是个Map<String, BeanDefinition>。使用BeanFactory可以获取一个Bean,Bean可以是Prototype的,也可以是Singleton的。能够取到那种类型的Bean,要依赖于配置了。在Spring2.0之后,又添加了Scope特性,这个要依赖于具体的ApplicationContext了,到ApplicationContext再说明。

3、BeanFactory提供了集中化管理组件,而不是将他们分开管理。其实就是说applictionContext.xml配置文件的集中化管理组件,组件就是扩展功能,可以是对第三方框架的支持,他们在Spring中都称为组件(例如事务管理、ORM集成、ws框架集成、调度集成、UI框架集成,只需要将相关的配置写在applictionContext.xml中即可)。

4、通常情况下,BeanFactory将从以XML文件方式的配置文件中加载Bean定义。其实Spring并没有限定配置方式,可以从XML文件中、属性文件中、LDAP、关系型数据库中等等。

5、BeanFactory有两大重要的子接口:HierarchicalBeanFactory和ListableBeanFactory。HierarchicalBeanFactory的实现类中,会有parentFactory 的说法在查找bean时,如果在指定的Hierarchical类型的BeanFactory中找不到,就会去它的parentFactory中找。并且bean是支持重写的。

6、BeanFactory的实现类应当尽可能去实现Lifecycle接口。拥有完整的初始化方法,按照初始化的顺序是:

    1)BeanNameAware.setBeanName

    2)BeanClassLoaderAware.setBeanClassLoader

    3)BeanFactoryAware.setBeanFactory

    4)ResourceLoaderAware.setResourceLoader

    5)ApplicationEventPublisherAware.setApplicationEventPublisher

    6)MessageSourceAware.setMessageSource

    7)ApplicationContextAware.setApplicationContext

    8)ServletContextAware.setServletContext

    9)BeanPostProcessors.postProcessBeforeInitialization.

    10)InitializingBean.afterPropertiesSet

    11)自定义的init方法

    12) BeanPostProcessors.postProcessAfterInitialization

 

其中:

    1,2,3,9,10,12是必须有的。

    4,5,6,7,8 是使用ApplicationContext作为Factory时需要的。

    9,12 是在初始化前后添加辅助功能的。

    这些在我们使用Spring时都是知道的。

 

7、当关闭BeanFactory时,需要调用的方法有:

1) DisposableBean.destroy

2) 自定义的destroy方法

 

 

接下来看看BeanFactory中定义了那些方法:

 Spring源码阅读:IOC容器之BeanFactory

 

对BeanFactory的扩充

 

在前文的类图中,从BeanFactory到DefaultListableBeanFactory的过程中,经历了多次的功能扩展。添加了很多特性:

Listable\ ConfigurableListable\ AutowireCapable

分别来看看他们都添加了哪些特性:

 

1、ListableBeanFactory

 Spring源码阅读:IOC容器之BeanFactory

 

 

从接口来看,添加了BeanDefinition的支持可以,获取到指定的类型的所有的实例了,通过时可以取得类的相关注解了。

 

2、HierarchialBeanFactory

 Spring源码阅读:IOC容器之BeanFactory

 

支持了parentBeanFactory

 

3、ConfigurableBeanFactory

提供一种可插拔的配置BeanFactory的方式。

 Spring源码阅读:IOC容器之BeanFactory

 

4、ConfigurableListableBeanFactory

从名字就可以看出,它将ListableBeanFactory和ConfigurableBeanFactory的功能结合到一起了。

 

DefaultListableBeanFactory

DefaultListableBeanFactory提供的方法在那些接口中都已经说明了,这里只看看它的数据结构就行了:

Spring源码阅读:IOC容器之BeanFactory
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {

 

   /** Parent bean factory, for bean inheritance support */

   private BeanFactory parentBeanFactory;

 

   /** ClassLoader to resolve bean class names with, if necessary */

   private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();

 

   /** ClassLoader to temporarily resolve bean class names with, if necessary */

   private ClassLoader tempClassLoader;

 

   /** Whether to cache bean metadata or rather reobtain it for every access */

   private boolean cacheBeanMetadata = true;

 

   /** Resolution strategy for expressions in bean definition values */

   private BeanExpressionResolver beanExpressionResolver;

 

   /** Spring 3.0 ConversionService to use instead of PropertyEditors */

   private ConversionService conversionService;

 

   /** Custom PropertyEditorRegistrars to apply to the beans of this factory */

   private final Set<PropertyEditorRegistrar> propertyEditorRegistrars =

        new LinkedHashSet<PropertyEditorRegistrar>(4);

 

   /** A custom TypeConverter to use, overriding the default PropertyEditor mechanism */

   private TypeConverter typeConverter;

 

   /** Custom PropertyEditors to apply to the beans of this factory */

   private final Map<Class, Class<? extends PropertyEditor>> customEditors =

        new HashMap<Class, Class<? extends PropertyEditor>>(4);

 

   /** String resolvers to apply e.g. to annotation attribute values */

   private final List<StringValueResolver> embeddedValueResolvers = new LinkedList<StringValueResolver>();

 

   /** BeanPostProcessors to apply in createBean */

   private final List<BeanPostProcessor> beanPostProcessors = new ArrayList<BeanPostProcessor>();

 

   /** Indicates whether any InstantiationAwareBeanPostProcessors have been registered */

   private boolean hasInstantiationAwareBeanPostProcessors;

 

   /** Indicates whether any DestructionAwareBeanPostProcessors have been registered */

   private boolean hasDestructionAwareBeanPostProcessors;

 

   /** Map from scope identifier String to corresponding Scope */

   private final Map<String, Scope> scopes = new HashMap<String, Scope>();

 

   /** Security context used when running with a SecurityManager */

   private SecurityContextProvider securityContextProvider;

 

   /** Map from bean name to merged RootBeanDefinition */

   private final Map<String, RootBeanDefinition> mergedBeanDefinitions =

        new ConcurrentHashMap<String, RootBeanDefinition>();

 

   /** Names of beans that have already been created at least once */

   private final Set<String> alreadyCreated = Collections.synchronizedSet(new HashSet<String>());

 

   /** Names of beans that are currently in creation */

   private final ThreadLocal<Object> prototypesCurrentlyInCreation =

        new NamedThreadLocal<Object>("Prototype beans currently in creation");

}

 

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory

      implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {

 

   private static Class javaxInjectProviderClass = null;

 

   static {

      ClassLoader cl = DefaultListableBeanFactory.class.getClassLoader();

      try {

        javaxInjectProviderClass = cl.loadClass("javax.inject.Provider");

      }

      catch (ClassNotFoundException ex) {

        // JSR-330 API not available - Provider interface simply not supported then.

      }

   }

 

 

   /** Map from serialized id to factory instance */

   private static final Map<String, Reference<DefaultListableBeanFactory>> serializableFactories =

        new ConcurrentHashMap<String, Reference<DefaultListableBeanFactory>>();

 

   /** Optional id for this factory, for serialization purposes */

   private String serializationId;

 

   /** Whether to allow re-registration of a different definition with the same name */

   private boolean allowBeanDefinitionOverriding = true;

 

   /** Whether to allow eager class loading even for lazy-init beans */

   private boolean allowEagerClassLoading = true;

 

   /** Resolver to use for checking if a bean definition is an autowire candidate */

   private AutowireCandidateResolver autowireCandidateResolver = new SimpleAutowireCandidateResolver();

 

   /** Map from dependency type to corresponding autowired value */

   private final Map<Class, Object> resolvableDependencies = new HashMap<Class, Object>();

 

   /** Map of bean definition objects, keyed by bean name */

   private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();

 

   /** List of bean definition names, in registration order */

   private final List<String> beanDefinitionNames = new ArrayList<String>();

 

   /** Whether bean definition metadata may be cached for all beans */

   private boolean configurationFrozen = false;

 

   /** Cached array of bean definition names in case of frozen configuration */

   private String[] frozenBeanDefinitionNames;

}

 
View Code

 

如果想要定义自己的BeanFactory,继承这个类是一个很不错的选择。

 

他有一个直接子类:XmlBeanFactory,就是使用XML作为Bean定义的配置文件的方式的实现。

 

XmlBeanFactory

XmlBeanFactory类说明:

Spring源码阅读:IOC容器之BeanFactory
/**

 * Convenience extension of {@link DefaultListableBeanFactory} that reads bean definitions

 * from an XML document. Delegates to {@link XmlBeanDefinitionReader} underneath; effectively

 * equivalent to using an XmlBeanDefinitionReader with a DefaultListableBeanFactory.

 *

 * <p>The structure, element and attribute names of the required XML document

 * are hard-coded in this class. (Of course a transform could be run if necessary

 * to produce this format). "beans" doesn‘t need to be the root element of the XML

 * document: This class will parse all bean definition elements in the XML file.

 *

 * <p>This class registers each bean definition with the {@link DefaultListableBeanFactory}

 * superclass, and relies on the latter‘s implementation of the {@link BeanFactory} interface.

 * It supports singletons, prototypes, and references to either of these kinds of bean.

 * See "spring-beans-2.0.dtd" for details on options and configuration style.

 *

 * <p><b>For advanced needs, consider using a {@link DefaultListableBeanFactory} with

 * an {@link XmlBeanDefinitionReader}.</b> The latter allows for reading from multiple XML

 * resources and is highly configurable in its actual XML parsing behavior.

 *
*/
View Code

 

上面提到了下列内容:

1、XmlBeanFactory是一个扩展自DefaultListableBeanFactory的很方便的从XML文档中读取Bean定义的BeanFactory。但是它并不会直接的处理XML文档,而是委托给XmlBeanDefinitionReader来处理。

2、在处理XML文档中定义的Bean时,会将Bean Definition注册到DefaultListableBeanFactory中。在Spring提供的Beans.xml中会指定如何配置:spring-beans-x.xx.dtd(x.xx是版本号)。

3、可以在多个文件中定义beans,这点我们都是知道的。

 

Spring源码阅读:IOC容器之BeanFactory
public class XmlBeanFactory extends DefaultListableBeanFactory {

 

   private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);

 

public XmlBeanFactory(Resource resource) throws BeansException {

      this(resource, null);

   }

public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {

      super(parentBeanFactory);

      this.reader.loadBeanDefinitions(resource);

   }

 

}
View Code

 

从XmlBeanFactory的源码中知道,我们只需要在编码时提供一个资源Resource就可以XmlBeanFactory来获取相应的Bean了 。

例如可以这样使用:

// 加载BeanDefinitions:

Resource res=new ClassPathResource("beans.xml");

DefaultListableBeanFactory fct=new DefaultListableBeanFactory();

XmlBeanDefinitionReader reader=new XmlBeanDefinitionReader(fct);

Reader.loadBeanDefinitions(res);

// 接下来就可以使用IOC容器了

 

 

Spring源码阅读:IOC容器之BeanFactory

上一篇:【DMCP】2020-CVPR-DMCP Differentiable Markov Channel Pruning for Neural Networks-论文阅读


下一篇:Single Number leetcode java