Spring之IOC、核心容器和Bean概念详解

    这一周忙了很多与代码无关的事,感觉心态上还是有些急躁,周中挑几个晚上看了一些文章,上午起来总结了一下,下午开始写博客,因为没有时间撸代码,所以就打算先把看到的概念梳理梳理,磨刀不误砍柴工。

    首先来看一看什么是IOC,他的全称是Inversion of Control,即控制反转,如果上网找绝大多数的概念是这样说的:Spring实现了把原始的通过代码操纵的组件和应用的调用权利交给了容器,由容器去进行组件代码的控制和管理,反转也就是把组件代码的控制权由外部代码转移到了内部容器。

    可是光这么说还是有一些抽象,本着知乎上先问是什么再问是不是的原则,我们把这个问题拆解开来看,首先梳理出来参与者,一般会有三个参与者,一个是应用对象,一个是IOC容器,一个是该对象所依赖(或所使用)的另一个对象。应用对象很好理解,就是一个单纯的Java对象,IOC容器简单理解就是Spring实现IOC的一套框架程序,所依赖对象就是这个对象实现过程中需要依赖的某个外部程序。

    梳理明白了这个参与者的问题,下面解释什么是控制反转,控制,即对应用对象的控制权,反转,就意味着对象的初始化等一系列工作不再需要我们在外部完成,而是全部交给容器这个框架程序,我们只是被动地等待,所以被反转了,那么这么做有什么好处呢?事实上使用Spring配置文件来管理对象,可以大幅度减少代码间的耦合,不必在上层类调用下层类的时候进行下层类的初始化。这里再提到另外一个概念,就是依赖注入(DependencyInjection),其实就我的理解,依赖注入和控制反转说的是一回事,控制反转是结果,实现这个结果的过程(或者叫方法)是依赖注入,也就是反转的过程是通过把应用程序注入到容器中所实现的,而这里的依赖是指应用程序的工作要依赖容器去完成,因为容器控制着应用程序所依赖的外部对象。

    或者还可以这么说,依赖注入和控制反转其实是表述的对象不同,依赖注入是从应用程序的角度来说的,应用程序需要将原始的,对象的创建过程交给容器去做,应用程序中对象的创建就依赖容器去完成,而容器创建这个对象使用的就是注入的方式,比如set注入或者是构造注入什么的而控制反转是从容器的角度去说的,容器将之前手动在程序里去创建的对象反转为由容器自己去创建,所以叫控制反转。


    说了这么久的容器,那么容器到底是什么呢,上文说了可以把容器理解为一个实现控制反转的框架程序,那么这个程序是如何实现的,又是如果工作的?

    容器,顾名思义,是承载东西的一个器皿,从程序的角度,可以大致把容器分为两类,一类是web容器,就是一个位于应用程序和平台之间的接口集合,比如Tomcat等,还有一类,就是存储和组织其他对象的对象,比如Java的Map,List类等等,我们可以叫它编程容器。容器可以管理对象的生命周期,对象与对象之间的依赖关系,我们依靠一个XML文件(通常情况下),来配置一个对象的名称,id,产生方式,以及产生后是否作为另一个对象的属性等,而这个对象的初始化,设置依赖关系的过程不用写一行代码,Spring实现了代码间的高度解耦。

Spring之IOC、核心容器和Bean概念详解_第1张图片    这是Spring的接口设计图,这里我们只关注两条继承路线,一条是从BeanFactory到HierarchicalBeanFactory,再到ConfigurableBeanFactory,这是一条BeanFactory的设计路线,他规定了IOC容器的规范,首先在BeanFactory接口中定义了类似getBean()等基础的方法,然后在HierarchicalBeanFactory继承了它之后,实现了getParentBeanFactory()方法,使对象具有双亲IOC容器的管理功能,然后在ConfigurableBeanFactory接口中,又实现了setParentBeanFactory功能来设置双亲IOC容器,通过一层层接口的叠加,来实现IOC的基本功能。

    另一条线是从BeanFactory到ListableBeanFactory,再到ApplicationContext,然后到我们经常使用的WebApplicationContext和ConfigurableApplicationContext等接口,ListableBeanFactory在BeanFactory的基础上实现了类似getBeanDefinitionNames等细分功能,而ApplicationContext通过继承ResourceLoader等方法,又实现了许多对高级容器支持的特性。

    BeanFactory源码:

/*
 * Copyright 2002-2006 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.beans.factory;

import org.springframework.beans.BeansException;

/**
 * The root interface for accessing a Spring bean container.
 * This is the basic client view of a bean container; further interfaces
 * such as ListableBeanFactory and ConfigurableBeanFactory
 * are available for specific purposes.
 *
 * 

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. The Singleton * approach is more useful and more common in practice. * *

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

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 BeanFactory and its subinterfaces. * *

Normally a BeanFactory will load bean definitions stored in a configuration * source (such as an XML document), and use the org.springframework.beans 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, to either * Singletons or Prototypes. * *

In contrast to the methods in ListableBeanFactory, all of the methods in this * interface will also check parent factories if this is a HierarchicalBeanFactory. * If a bean is not found in this factory instance, the immediate parent is asked. * Beans in this factory instance are supposed to override beans of the same name * in any parent factory. * *

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:
* 1. BeanNameAware's setBeanName
* 2. BeanClassLoaderAware's setBeanClassLoader
* 3. BeanFactoryAware's setBeanFactory
* 4. ResourceLoaderAware's setResourceLoader * (only applicable when running in an application context)
* 5. ApplicationEventPublisherAware's setApplicationEventPublisher * (only applicable when running in an application context)
* 6. MessageSourceAware's setMessageSource * (only applicable when running in an application context)
* 7. ApplicationContextAware's setApplicationContext * (only applicable when running in an application context)
* 8. ServletContextAware's setServletContext * (only applicable when running in a web application context)
* 9. postProcessBeforeInitialization methods of BeanPostProcessors
* 10. InitializingBean's afterPropertiesSet
* 11. a custom init-method definition
* 12. postProcessAfterInitialization methods of BeanPostProcessors * *

On shutdown of a bean factory, the following lifecycle methods apply:
* 1. DisposableBean's destroy
* 2. a custom destroy-method definition * * @author Rod Johnson * @author Juergen Hoeller * @since 13 April 2001 * @see ListableBeanFactory * @see org.springframework.beans.factory.config.ConfigurableBeanFactory * @see BeanNameAware#setBeanName * @see BeanClassLoaderAware#setBeanClassLoader * @see BeanFactoryAware#setBeanFactory * @see org.springframework.context.ResourceLoaderAware#setResourceLoader * @see org.springframework.context.ApplicationEventPublisherAware#setApplicationEventPublisher * @see org.springframework.context.MessageSourceAware#setMessageSource * @see org.springframework.context.ApplicationContextAware#setApplicationContext * @see org.springframework.web.context.ServletContextAware#setServletContext * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization * @see InitializingBean#afterPropertiesSet * @see org.springframework.beans.factory.support.RootBeanDefinition#getInitMethodName * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization * @see DisposableBean#destroy * @see org.springframework.beans.factory.support.RootBeanDefinition#getDestroyMethodName */ public interface BeanFactory { /** * Used to dereference a FactoryBean and distinguish it from beans * created by the FactoryBean. For example, if the bean named * myEjb is a FactoryBean, getting &myEjb will * return the factory, not the instance returned by the factory. */ String FACTORY_BEAN_PREFIX = "&"; /** * Return an instance, which may be shared or independent, of the given bean name. * This method allows a Spring BeanFactory to be used as a replacement for the * Singleton or Prototype design pattern. *

Callers may retain references to returned objects in the case of Singleton beans. *

Translates aliases back to the corresponding canonical bean name. * Will ask the parent factory if the bean cannot be found in this factory instance. * @param name the name of the bean to return * @return the instance of the bean * @throws NoSuchBeanDefinitionException if there is no bean definition * with the specified name * @throws BeansException if the bean could not be obtained */ Object getBean(String name) throws BeansException; /** * Return an instance (possibly shared or independent) of the given bean name. *

Behaves the same as getBean(String), but provides a measure of type safety by * throwing a Spring BeansException if the bean is not of the required type. * This means that ClassCastException can't be thrown on casting the result correctly, * as can happen with getBean(String). * @param name the name of the bean to return * @param requiredType type the bean must match. Can be an interface or superclass * of the actual class, or null for any match. For example, if the value * is Object.class, this method will succeed whatever the class of the * returned instance. * @return an instance of the bean (never null) * @throws BeanNotOfRequiredTypeException if the bean is not of the required type * @throws NoSuchBeanDefinitionException if there's no such bean definition * @throws BeansException if the bean could not be created */ Object getBean(String name, Class requiredType) throws BeansException; /** * Does this bean factory contain a bean definition with the given name? *

Will ask the parent factory if the bean cannot be found in this factory instance. * @param name the name of the bean to query * @return whether a bean with the given name is defined */ boolean containsBean(String name); /** * Is this bean a singleton? That is, will getBean always return the same object? *

Will ask the parent factory if the bean cannot be found in this factory instance. * @param name the name of the bean to query * @return is this bean a singleton * @throws NoSuchBeanDefinitionException if there is no bean with the given name * @see #getBean */ boolean isSingleton(String name) throws NoSuchBeanDefinitionException; /** * Determine the type of the bean with the given name. * More specifically, checks the type of object that getBean would return. * For a FactoryBean, returns the type of object that the FactoryBean creates. * @param name the name of the bean to query * @return the type of the bean, or null if not determinable * @throws NoSuchBeanDefinitionException if there is no bean with the given name * @since 1.1.2 * @see #getBean * @see FactoryBean#getObjectType() */ Class getType(String name) throws NoSuchBeanDefinitionException; /** * Return the aliases for the given bean name, if defined. *

If the given name is an alias, the corresponding original bean name * and other aliases (if any) will be returned, with the original bean name * being the first element in the array. *

Will ask the parent factory if the bean cannot be found in this factory instance. * @param name the bean name to check for aliases * @return the aliases, or an empty array if none */ String[] getAliases(String name); }

ApplicationContext源码:

/*
 * Copyright 2002-2006 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.context;

import org.springframework.beans.factory.HierarchicalBeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.core.io.support.ResourcePatternResolver;

/** 
 * Central interface to provide configuration for an application.
 * This is read-only while the application is running, but may be
 * reloaded if the implementation supports this.
 *
 * 

An ApplicationContext provides: *

    *
  • Bean factory methods, inherited from ListableBeanFactory. * This avoids the need for applications to use singletons. *
  • The ability to resolve messages, supporting internationalization. * Inherited from the MessageSource interface. *
  • The ability to load file resources in a generic fashion. * Inherited from the ResourceLoader interface. *
  • The ability to publish events. Implementations must provide a means * of registering event listeners. *
  • Inheritance from a parent context. Definitions in a descendant context * will always take priority. This means, for example, that a single parent * context can be used by an entire web application, while each servlet has * its own child context that is independent of that of any other servlet. *
* *

In addition to standard bean factory lifecycle capabilities, * ApplicationContext implementations need to detect ApplicationContextAware * beans and invoke the setApplicationContext method accordingly. * * @author Rod Johnson * @author Juergen Hoeller * @see ApplicationContextAware#setApplicationContext * @see ConfigurableApplicationContext */ public interface ApplicationContext extends ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver { /** * Return the parent context, or null if there is no parent, * and this is the root of the context hierarchy. * @return the parent context, or null if there is no parent */ ApplicationContext getParent(); /** * Expose AutowireCapableBeanFactory functionality for this context. *

This is not typically used by application code, except for the purpose * of initializing bean instances that live outside the application context, * applying the Spring bean lifecycle (fully or partly) to them. *

Alternatively, the internal BeanFactory exposed by the * ConfigurableApplicationContext interface offers access to the * AutowireCapableBeanFactory interface too. The present method mainly * serves as convenient, specific facility on the ApplicationContext * interface itself. * @throws IllegalStateException if the context does not support * the AutowireCapableBeanFactory interface or does not hold an autowire-capable * bean factory yet (usually if refresh() has never been called) * @see ConfigurableApplicationContext#refresh() * @see ConfigurableApplicationContext#getBeanFactory() */ AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException; /** * Return a friendly name for this context. * @return a display name for this context */ String getDisplayName(); /** * Return the timestamp when this context was first loaded. * @return the timestamp (ms) when this context was first loaded */ long getStartupDate(); }

    总结一下:BeanFactory是Spring中比较原始的Factory,他无法支持Spring的许多插件,比如AOP功能,Web应用等,而ApplicationContext由BeanFactory接口继承而来,因此提供更多功能,是以一种更面向框架的方式工作以及对上下文进行分层和实现继承。

    最后说一个概念,就是Spring里的Bean,Spring的一切都是围绕Bean来工作的,创建Bean,配置Bean,最后销毁Bean,下面是一片博文中对Bean的配置和理解,摘录如下,一个最基本的Bean的配置:




  
  
      
      
          Hello World
      
     
      
          
      
 
    
 

从内容和注释我们可以总结出以下几点:
    1. Bean的标识(id和name) 
        在Spring中可以用id或name属性来指定Bean的id,并且至少指定一个id。id和name的区别:id属性是Bean的唯一标识,不可重复标记,并且它在XML DTD中作为一个XML元素的ID属性被标记。如果开发中需要给Bean增加别名,可以通过name属性指定一个或多个id,多个id用(,)或(;)分隔。
    2. Bean的类(class)
    	在Spring的配置文档中,class属性指明了Bean的来源,即Bean的实际路径。
    3. Singleton的使用
    	在Spring中,Bean可以定义为两种部署模式:singleton或non-singleton(prototype)。Spring默认为singleton模式。
    	如果一个Bean被定义为singleton模式:只有一个共享的实例存在,所有对这个Bean的请求都会返回这个唯一的实例。
    	如果一个Bean被定义为non-singleton(prototype)模式,那么对这个Bean的每次请求都会创建一个新的bean实例。
    4. 使用依赖depends-on
    	Bean的depends-on属性可以用来在初始化使用这个Bean之前,强制执行一个或多个Bean的初始化。详见上面代码中的第1点。
    【生命周期】
    	一个Bean从定义到销毁都有一个生命周期。在Spring中,Bean的生命周期包括Bean的定义、初始化、使用和销毁4个阶段。下面分别进行介绍:
    1. Bean的定义
    	在Spring中,通常是通过配置文档的方式定义Bean。如上面的代码所示。
    	在一个大的应用中,会有很多的Bean需要定义,这样配置文档就会很大,而不好维护。所以,我们可以把相关的Bean放在一个配置文档中,出现多个配置文档。
    2. Bean的初始化
    	第一种方式,通过在配置文档中指定init-method属性完成。    
	实现思路:在类中增加一个初始化方法init(),用来完成初始化工作,并去掉构造函数。修改配置文档,指定Bean的初始化方法为init(),即init-method="init",并去掉通过setter注入方法。
    	第二种方式,实现org.springframework.beans.factory.InitializingBean接口。
	实现思路:让类实现InitializingBean接口,增加afterPropertiesSet()完成初始化工作,然后修改配置文档。
    	以上两种方式都是Bean的初始化方式,但第一种方式没有把代码耦合于Spring。
    3. Bean的使用
    	在Spring中,Bean的使用有3种方式:BeanWrapper、BeanFactory和ApplicationContext。
    	通过前面的学习,我们对后面两种都很熟悉了。在此也不具体讲解了。
    4. Bean的销毁
    	在Spring中,Bean的销毁有以下两种方式:
    	第一种,在配置文档中通过制定destroy-method属性完成。
    	第二种,实现org.springframework.beans.factory.DisposableBean接口。
    	和初始化方式相同,不再写出具体的实现思路。


你可能感兴趣的:(Spring,核心容器,IOC,依赖注入,Bean)