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。下面就来看看他们分别是如何实现的:

静态工厂

StaticListableBeanFactory类的说明:

/**

 * 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,也不支持别名。

类的部分代码:

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);

   }

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

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

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

BeanFactory

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中定义了那些方法:

对BeanFactory的扩充

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

Listable\ ConfigurableListable\ AutowireCapable

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

1、ListableBeanFactory

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

2、HierarchialBeanFactory

支持了parentBeanFactory

3、ConfigurableBeanFactory

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

4、ConfigurableListableBeanFactory

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

DefaultListableBeanFactory

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

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;

}

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

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

XmlBeanFactory

XmlBeanFactory类说明:

/**

 * 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.

 *
*/

上面提到了下列内容:

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,这点我们都是知道的。

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);

   }

}

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

例如可以这样使用:

// 加载BeanDefinitions:

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

DefaultListableBeanFactory fct=new DefaultListableBeanFactory();

XmlBeanDefinitionReader reader=new XmlBeanDefinitionReader(fct);

Reader.loadBeanDefinitions(res);

// 接下来就可以使用IOC容器了
时间: 2024-10-13 22:27:44

Spring源码阅读:IOC容器之BeanFactory的相关文章

Spring源码阅读:IOC容器的设计与实现(二)——ApplicationContext

上一主题中,了解了IOC容器的基本概念,以及BeanFactory的设计与实现方式,这里就来了解一下ApplicationContext方式的实现. ApplicationContext 在Spring的参考文档中,为啥要推荐使用ApplicationContext?它能给我们的应用带来什么好处呢?作为BeanFactory的实现之一,它又是如何设计的?在SpringMVC中使用的WebApplictionContext\XmlApplicationContext与之有何关联? Applicat

Spring源码阅读:使用标准AOP的API模拟Spring AOP + AspectJ的设计与实现

在上一篇博客中,提到了标准AOP与Spring AOP.这一篇就来把他们模拟出来. 在模拟之前,还需要提及的是,在Spring框架中,对于AOP的支持: Spring 支持的AOP AspectJ是另外一个有名的AOP框架,Spring也集成AspectJ,同时Spring AOP与AspectJ有一定程度的集成,这样一来Spring中就支持两种AOP:1)Spring AOP.2)AspectJ.而使用AOP的方式却又三种: 1)完全使用Spring AOP 2)完全使用AspectJ(分为注

Spring源码阅读系列总结

最近一段时间,粗略的查看了一下Spring源码,对Spring的两大核心和Spring的组件有了更深入的了解.同时在学习Spring源码时,得了解一些设计模式,不然阅读源码还是有一定难度的,所以一些重要的设计模式简单的做了阐述.同时还会简单的加入一些GOF中提到的设计原则.Spring的源码阅读系列,也暂告一段落.下面是就带你走进Spring世界: Spring系列的引子 1)Spring WebApplicationContext初始化与消亡 这一节帮我们了解Spring是如何初始化WebAp

spring源码分析---IOC(1)

我们都知道spring有2个最重要的概念,IOC(控制反转)和AOP(依赖注入).今天我就分享一下spring源码的IOC. IOC的定义:直观的来说,就是由spring来负责控制对象的生命周期和对象间的关系,将对象之间的关系抽象出来,通过spring容器控制对象生成时机,减少对象之间的耦合度. 更通俗一点的说就是,JAVA程序中,当你在代码中需要使用某个类提供的功能时,你首先需要new一个对象,给它传递必要的参数,然后才能使用它提供的功能:有了IOC之后,IOC的容器类似一个中介,所有的对象都

Spring源码阅读:Spring AOP设计与实现(一):动态代理

在Spring的有两个核心:IOC与AOP,AOP又是基于动态代理模式实现的.所以要了解SpringAOP是如何设计的之前,还是先了解一下Java中的动态代理比较好. 认识代理模式 代理模式是这么描述的: 代理模式是为其他对象提供一种代理以控制对这个对象的访问 代理对象的功能: 通过创建一个代理对象,用这个代理对象去代理真实的对象,客户端得到这个代理对象后,对客户端并没有什么影响,就跟真实的对象一样(因为代理对象和真是对象实现了同一接口). 下面看看代理模式的类图: 解说: RealSubjec

Spring源码阅读:Spring WebApplicationContext初始化与消亡

使用SpringMVC时,需要不论是使用注解配置,还是使用XML配置Bean,他们都会在Web服务器启动后就初始化.根据J2ee的知识可以知道,肯定是使用了ServletContextListener才完成的这个功能.那Spring又是如何实现的呢?还有我们在Web.xml配置的那些applicationContext.xml相关的XML文件的位置(配置方式多样),又是如何读取到相应的文件的呢,读取到这些文件后,是如何初始化类的呢?我们能不能自定义初始化过程或者自定义WebApplication

Spring源码阅读:Spring MVC 初始化

通过之前的源码学习,了解了Spring的两个核心IOC和AOP.也了解到系统初始化时,就已经将所有applicationContext.xml中的bean Definintion加载并初始化了. 如果使用了SpringMVC框架,MVC框架指定的namespace-servlet.xml也已经被初始化了. 使用过SpringMVC,都知道需要在web.xml配置配置DispatcherServlet,它是处理请求的入口.Servlet是单例的,系统指挥在第一次处理用户请求时初始化Servlet对

Spring源码阅读:Spring JDBC 组件的设计与实现

昨天回忆了我在学习JDBC时自己设计的JDBCTemplate(写在上一篇博客中),在使用Spring过程中,有时会用到Spring给我们提供的JdbcTemplate,这里看看Spring是如何实现这个组件的. 在使用Spring JDBC是你要做的工作很少: 从上面的图上可以看出来,使用Spring JDBC,你只需要做四个工作: 1)定义连接参数:也就是定义url,driver,user,password这个几个参数,一般我们会用一个jdbc.properties文件来配置. 2)指定要执

spring源码阅读(3)-- 容器启动之BeanFactoryPostProcessor

接着上文<spring源码阅读(2)-- 容器启动之加载BeanDefinition>,当spring加载完所有BeanDefinition时,并不会马上去创建bean,而是先配置beanFactory,例如设置一下装配规则和判断是否需要创建一些指定的bean. 1 protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { 2 // Tell the internal bean factor

Spring源码阅读:Spring MVC 如何处理HTTP请求

Spring MVC 对HTTP请求的处理流程 通过之前的源码阅读,知道了ApplicationContext初始的过程,也知道了Spring MVC环境的初始化过程,今天就来了解一下SpringMVC是如何处理HTTP请求的. HTTP请求根据请求方式可以分为GET.POST.PUT.DELETE.OPTIONS.TRACE,最常用的还是GET和POST. Spring对于这几种HTTP请求的处理都是使用了processRequest(req,rep); @Override protected