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}. */
从类的说明中知道:静态工厂允许我们在程序中以编程的方式注册单例的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 */
上面提到:
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容器了