Spring框架中的容器以及两大特性
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring框架中的容器以及两大特性相关的知识,希望对你有一定的参考价值。
参考技术ASpring容器提供了一种管理方法,致力于解决我们各个层级之间的对象的调用关系。
我们通常调用各层级对象的时候,需要不断创建对象,一次访问就需要创建两个对象;如果我们使用Spring容器,将不同层级的对象放入容器中,每次使用的时候调用容器中的对象,就不用创建那么多对象,达到节约内存空间的目的。简单来讲,Spring容器就是存储JavaBean对象的容器。
BeanFactory是一个接口,需要创建继承的子类对象。下图是其继承结构图:
方式二:使用ClassPathApplicationContext获取容器类
这个方法替代了方式一,是我们创建容器类对象主要使用的方法。
方式三:使用FileSystemXmlApplicationContext来获取容器对象
这种方式在创建对象的时候需要传入配置文件的绝对路径,这个方法可以使用项目外部的配置文件
IOC(inversion of controller)指的是控制反转,简单来书,就是讲创建对象的过程或者创建对象的权限交给了spring框架来帮我们处理,我们不用再通过new的方式来创建JavaBean对象,这个过程就叫做IOC。
首先在applicationContext中配置我们的对象
然后从容器中获取我们的JavaBean对象
创建bean的工厂类
在配置文件中进行配置
获取JavaBean对象
创建工厂类的方式与上面相同
在配置文件中进行配置
获取JavaBean对象
Bean属性scope可以声明bean的作用域范围,Bean的作用域范围有四种:
我们可以在JavaBean类中添加init-method与destroy-method两个方法,实现bean在初始化和关闭的时候调用的方法,然后在配置文件中进行配置。
JavaBean类
配置文件
DI(dependency injection)指的是依赖注入,简单来说就是使用spring框架对我们的JavaBean对象赋值的过程。
使用上文中创建的JavaBean类
注意:一定要给属性生成对应的setter方法
配置JavaBean类的属性
从容器中获取我们的JavaBean对象
在JavaBean中生成带所有属性的构造方法
在配置文件中申明JavaBean对象
申明的另一种方法:
调用JavaBean的属性
P名称空间与C名称空间其实都是不存在的虚拟空间,主要是用于简化我们的spring为JavaBean属性赋值时的配置。
添加P名称空间与C名称空间到schema
通过setter方法进行赋值:
等价于:
通过构造方法进行赋值
等价于:
Spel表达式,类似于jstl与el表达式的语言,spring可以支持我们在为属性赋值的时候,通过spel表达式来进行更改我们的属性值。
创建一个含有集合属性的JavaBean类
为集合属性注入值
Spring框架学习[IoC容器高级特性]
1.通过前面4篇文章对Spring IoC容器的源码分析,我们已经基本上了解了Spring IoC容器对Bean定义资源的定位、读入和解析过程,同时也清楚了当用户通过getBean方法向IoC容器获取被管理的Bean时,IoC容器对Bean进行的初始化和依赖注入过程,这些是Spring IoC容器的基本功能特性。Spring IoC容器还有一些高级特性,如使用lazy-init属性对Bean预初始化、FactoryBean产生或者修饰Bean对象的生成、IoC容器初始化Bean过程中使用BeanPostProcessor后置处理器对Bean声明周期事件管理和IoC容器的autowiring自动装配功能等。
2.Spring IoC容器的lazy-init属性实现预实例化:
通过前面我们对IoC容器的实现和工作原理分析,我们知道IoC容器的初始化过程就是对Bean定义资源的定位、载入和注册,此时容器对Bean的依赖注入并没有发生,依赖注入主要是在应用程序第一次向容器索取Bean时,通过getBean方法的调用完成。
当Bean定义资源的元素中配置了lazy-init属性时,容器将会在初始化的时候对所配置的Bean进行预实例化,Bean的依赖注入在容器初始化的时候就已经完成。这样,当应用程序第一次向容器索取被管理的Bean时,就不用再初始化和对Bean进行依赖注入了,直接从容器中获取已经完成依赖注入的现成Bean,可以提高应用第一次向容器获取Bean的性能。
下面我们通过代码分析容器预实例化的实现过程:
(1).先从IoC容器的初始会过程开始,通过前面文章分析,我们知道IoC容器读入已经定位的Bean定义资源是从refresh方法开始的,我们首先从AbstractApplicationContext类的refresh方法入手分析,源码如下:
[java]
- //容器初始化的过程,读入Bean定义资源,并解析注册 public void refresh() throws BeansException, IllegalStateException {
- synchronized (this.startupShutdownMonitor) { //调用容器准备刷新的方法,获取容器的当时时间,同时给容器设置同步标识
- prepareRefresh(); //告诉子类启动refreshBeanFactory()方法,Bean定义资源文件的载入从
- //子类的refreshBeanFactory()方法启动 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
- //为BeanFactory配置容器特性,例如类加载器、事件处理器等 prepareBeanFactory(beanFactory);
- try { //为容器的某些子类指定特殊的BeanPost事件处理器
- postProcessBeanFactory(beanFactory); //调用所有注册的BeanFactoryPostProcessor的Bean
- invokeBeanFactoryPostProcessors(beanFactory); //为BeanFactory注册BeanPost事件处理器.
- //BeanPostProcessor是Bean后置处理器,用于监听容器触发的事件 registerBeanPostProcessors(beanFactory);
- //初始化信息源,和国际化相关. initMessageSource();
- //初始化容器事件传播器. initApplicationEventMulticaster();
- //调用子类的某些特殊Bean初始化方法 onRefresh();
- //为事件传播器注册事件监听器. registerListeners();
- //这里是对容器lazy-init属性进行处理的入口方法 finishBeanFactoryInitialization(beanFactory);
- //初始化容器的生命周期事件处理器,并发布容器的生命周期事件 finishRefresh();
- } catch (BeansException ex) {
- //销毁以创建的单态Bean destroyBeans();
- //取消refresh操作,重置容器的同步标识. cancelRefresh(ex);
- throw ex; }
- } }
在refresh方法中ConfigurableListableBeanFactorybeanFactory = obtainFreshBeanFactory();启动了Bean定义资源的载入、注册过程,而finishBeanFactoryInitialization方法是对注册后的Bean定义中的预实例化(lazy-init=false,Spring默认就是预实例化,即为true)的Bean进行处理的地方。
(2).finishBeanFactoryInitialization处理预实例化Bean:
当Bean定义资源被载入IoC容器之后,容器将Bean定义资源解析为容器内部的数据结构BeanDefinition注册到容器中,AbstractApplicationContext类中的finishBeanFactoryInitialization方法对配置了预实例化属性的Bean进行预初始化过程,源码如下:
[java]- //对配置了lazy-init属性的Bean进行预实例化处理 protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
- //这是Spring3以后新加的代码,为容器指定一个转换服务(ConversionService) //在对某些Bean属性进行转换时使用
- if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) && beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
- beanFactory.setConversionService( beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
- } //为了类型匹配,停止使用临时的类加载器
- beanFactory.setTempClassLoader(null); //缓存容器中所有注册的BeanDefinition元数据,以防被修改
- beanFactory.freezeConfiguration(); //对配置了lazy-init属性的单态模式Bean进行预实例化处理
- beanFactory.preInstantiateSingletons(); }
- ConfigurableListableBeanFactory是一个接口,其preInstantiateSingletons方法由其子类DefaultListableBeanFactory提供。 (3).DefaultListableBeanFactory对配置lazy-init属性单态Bean的预实例化:
- //对配置lazy-init属性单态Bean的预实例化 public void preInstantiateSingletons() throws BeansException {
- if (this.logger.isInfoEnabled()) { this.logger.info(Pre-instantiating singletons in + this);
- } //在对配置lazy-init属性单态Bean的预实例化过程中,必须多线程同步,以确
- //保数据一致性 synchronized (this.beanDefinitionMap) {
- for (String beanName : this.beanDefinitionNames) { //获取指定名称的Bean定义
- RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); //Bean不是抽象的,是单态模式的,且lazy-init属性配置为false
- if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { //如果指定名称的bean是创建容器的Bean
- if (isFactoryBean(beanName)) { //FACTORY_BEAN_PREFIX=”&”,当Bean名称前面加”&”符号
- //时,获取的是产生容器对象本身,而不是容器产生的Bean. //调用getBean方法,触发容器对Bean实例化和依赖注入过程
- final FactoryBean factory = (FactoryBean) getBean(FACTORY_BEAN_PREFIX + beanName); //标识是否需要预实例化
- boolean isEagerInit; if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
- //一个匿名内部类 isEagerInit = AccessController.doPrivileged(new PrivilegedAction() {
- public Boolean run() { return ((SmartFactoryBean) factory).isEagerInit();
- } }, getAccessControlContext());
- } else {
- isEagerInit = factory instanceof SmartFactoryBean && ((SmartFactoryBean) factory).isEagerInit(); }
- if (isEagerInit) { //调用getBean方法,触发容器对Bean实例化和依赖注入过程
- getBean(beanName); }
- } else {
- //调用getBean方法,触发容器对Bean实例化和依赖注入过程 getBean(beanName);
- } }
- } }
- }
通过对lazy-init处理源码的分析,我们可以看出,如果设置了lazy-init属性,则容器在完成Bean定义的注册之后,会通过getBean方法,触发对指定Bean的初始化和依赖注入过程,这样当应用第一次向容器索取所需的Bean时,容器不再需要对Bean进行初始化和依赖注入,直接从已经完成实例化和依赖注入的Bean中取一个线程的Bean,这样就提高了第一次获取Bean的性能。
3.FactoryBean的实现:
在Spring中,有两个很容易混淆的类:BeanFactory和FactoryBean。
BeanFactory:Bean工厂,是一个工厂(Factory),我们Spring IoC容器的最顶层接口就是这个BeanFactory,它的作用是管理Bean,即实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。FactoryBean:工厂Bean,是一个Bean,作用是产生其他bean实例。通常情况下,这种bean没有什么特别的要求,仅需要提供一个工厂方法,该方法用来返回其他bean实例。通常情况下,bean无须自己实现工厂模式,Spring容器担任工厂角色;但少数情况下,容器中的bean本身就是工厂,其作用是产生其它bean实例。
当用户使用容器本身时,可以使用转义字符”&”来得到FactoryBean本身,以区别通过FactoryBean产生的实例对象和FactoryBean对象本身。在BeanFactory中通过如下代码定义了该转义字符:
StringFACTORY_BEAN_PREFIX = &;
如果myJndiObject是一个FactoryBean,则使用&myJndiObject得到的是myJndiObject对象,而不是myJndiObject产生出来的对象。
(1).FactoryBean的源码如下:
[java]- //工厂Bean,用于产生其他对象 public interface FactoryBean {
- //获取容器管理的对象实例 T getObject() throws Exception;
- //获取Bean工厂创建的对象的类型 ClassgetObjectType();
- //Bean工厂创建的对象是否是单态模式,如果是单态模式,则整个容器中只有一个实例 //对象,每次请求都返回同一个实例对象
- boolean isSingleton(); }
(2). AbstractBeanFactory的getBean方法调用FactoryBean:
在第5篇博客我们分析Spring Ioc容器实例化Bean并进行依赖注入过程的源码时,提到在getBean方法触发容器实例化Bean的时候会调用AbstractBeanFactory的doGetBean方法来进行实例化的过程,源码如下:
[java]- //真正实现向IoC容器获取Bean的功能,也是触发依赖注入功能的地方 @SuppressWarnings(unchecked)
- protected T doGetBean( final String name, final Class requiredType, final Object[] args, boolean typeCheckOnly)
- throws BeansException { //根据指定的名称获取被管理Bean的名称,剥离指定名称中对容器的相关依赖
- //如果指定的是别名,将别名转换为规范的Bean名称 final String beanName = transformedBeanName(name);
- Object bean; //先从缓存中取是否已经有被创建过的单态类型的Bean,对于单态模式的Bean整
- //个IoC容器中只创建一次,不需要重复创建 Object sharedInstance = getSingleton(beanName);
- //IoC容器创建单态模式Bean实例对象 if (sharedInstance != null && args == null) {
- if (logger.isDebugEnabled()) { //如果指定名称的Bean在容器中已有单态模式的Bean被创建,直接返回
- //已经创建的Bean 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 + ‘); }
- } //获取给定Bean的实例对象,主要是完成FactoryBean的相关处理
- bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); }
- …… }
- //获取给定Bean的实例对象,主要是完成FactoryBean的相关处理 protected Object getObjectForBeanInstance( Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
- //容器已经得到了Bean实例对象,这个实例对象可能是一个普通的Bean,也可能是 //一个工厂Bean,如果是一个工厂Bean,则使用它创建一个Bean实例对象,如果
- //调用本身就想获得一个容器的引用,则指定返回这个工厂Bean实例对象 //如果指定的名称是容器的解引用(dereference,即是对象本身而非内存地址),
- //且Bean实例也不是创建Bean实例对象的工厂Bean if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
- throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass()); }
- //如果Bean实例不是工厂Bean,或者指定名称是容器的解引用,调用者向获取对 //容器的引用,则直接返回当前的Bean实例
- if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) { return beanInstance;
- } //处理指定名称不是容器的解引用,或者根据名称获取的Bean实例对象是一个工厂Bean
- //使用工厂Bean创建一个Bean的实例对象 Object object = null;
- if (mbd == null) { //从Bean工厂缓存中获取给定名称的Bean实例对象
- object = getCachedObjectForFactoryBean(beanName); }
- //让Bean工厂生产给定名称的Bean对象实例 if (object == null) {
- FactoryBean factory = (FactoryBean) beanInstance; //如果从Bean工厂生产的Bean是单态模式的,则缓存
- if (mbd == null && containsBeanDefinition(beanName)) { //从容器中获取指定名称的Bean定义,如果继承基类,则合并基类相关属性
- mbd = getMergedLocalBeanDefinition(beanName); }
- //如果从容器得到Bean定义信息,并且Bean定义信息不是虚构的,则让工厂 //Bean生产Bean实例对象
- boolean synthetic = (mbd != null && mbd.isSynthetic()); //调用FactoryBeanRegistrySupport类的getObjectFromFactoryBean
- //方法,实现工厂Bean生产Bean对象实例的过程 object = getObjectFromFactoryBean(factory, beanName, !synthetic);
- } return object;
- }
在上面获取给定Bean的实例对象的getObjectForBeanInstance方法中,会调用FactoryBeanRegistrySupport类的getObjectFromFactoryBean方法,该方法实现了Bean工厂生产Bean实例对象。
Dereference(解引用):一个在C/C++中应用比较多的术语,在C++中,”*”是解引用符号,而”&”是引用符号,解引用是指变量指向的是所引用对象的本身数据,而不是引用对象的内存地址。
(3). AbstractBeanFactory生产Bean实例对象:
AbstractBeanFactory类中生产Bean实例对象的主要源码如下:
[java]- //Bean工厂生产Bean实例对象 protected Object getObjectFromFactoryBean(FactoryBean factory, String beanName, boolean shouldPostProcess) {
- //Bean工厂是单态模式,并且Bean工厂缓存中存在指定名称的Bean实例对象 if (factory.isSingleton() && containsSingleton(beanName)) {
- //多线程同步,以防止数据不一致 synchronized (getSingletonMutex()) {
- //直接从Bean工厂缓存中获取指定名称的Bean实例对象 Object object = this.factoryBeanObjectCache.get(beanName);
- //Bean工厂缓存中没有指定名称的实例对象,则生产该实例对象 if (object == null) {
- //调用Bean工厂的getObject方法生产指定Bean的实例对象 object = doGetObjectFromFactoryBean(factory, beanName, shouldPostProcess);
- //将生产的实例对象添加到Bean工厂缓存中 this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));
- } return (object != NULL_OBJECT ? object : null);
- } }
- //调用Bean工厂的getObject方法生产指定Bean的实例对象 else {
- return doGetObjectFromFactoryBean(factory, beanName, shouldPostProcess); }
- } //调用Bean工厂的getObject方法生产指定Bean的实例对象
- private Object doGetObjectFromFactoryBean( final FactoryBean factory, final String beanName, final boolean shouldPostProcess)
- throws BeanCreationException { Object object;
- try { if (System.getSecurityManager() != null) {
- AccessControlContext acc = getAccessControlContext(); try {
- //实现PrivilegedExceptionAction接口的匿名内置类 //根据JVM检查权限,然后决定BeanFactory创建实例对象
- object = AccessController.doPrivileged(new PrivilegedExceptionAction() { public Object run() throws Exception {
- //调用BeanFactory接口实现类的创建对象方法 return factory.getObject();
- } }, acc);
- } catch (PrivilegedActionException pae) {
- throw pae.getException(); }
- } else {
- //调用BeanFactory接口实现类的创建对象方法 object = factory.getObject();
- } }
- catch (FactoryBeanNotInitializedException ex) { throw new BeanCurrentlyInCreationException(beanName, ex.toString());
- } catch (Throwable ex) {
- throw new BeanCreationException(beanName, FactoryBean threw exception on object creation, ex); }
- //创建出来的实例对象为null,或者因为单态对象正在创建而返回null if (object == null && isSingletonCurrentlyInCreation(beanName)) {
- throw new BeanCurrentlyInCreationException( beanName, FactoryBean which is currently in creation returned null from getObject);
- } //为创建出来的Bean实例对象添加BeanPostProcessor后置处理器
- if (object != null && shouldPostProcess) { try {
- object = postProcessObjectFromFactoryBean(object, beanName); }
- catch (Throwable ex) { throw new BeanCreationException(beanName, Post-processing of the FactoryBean‘s object failed, ex);
- } }
- return object; }
从上面的源码分析中,我们可以看出,BeanFactory接口调用其实现类的getObject方法来实现创建Bean实例对象的功能。
(4).工厂Bean的实现类getObject方法创建Bean实例对象:
FactoryBean的实现类有非常多,比如:Proxy、RMI、JNDI、ServletContextFactoryBean等等,FactoryBean接口为Spring容器提供了一个很好的封装机制,具体的getObject有不同的实现类根据不同的实现策略来具体提供,我们分析一个最简单的AnnotationTestFactoryBean的实现源码:
- public class AnnotationTestBeanFactory implements FactoryBean { private final FactoryCreatedAnnotationTestBean instance = new FactoryCreatedAnnotationTestBean();
- public AnnotationTestBeanFactory() { this.instance.setName(FACTORY);
- } //AnnotationTestBeanFactory产生Bean实例对象的实现
- public IJmxTestBean getObject() throws Exception { return this.instance;
- } public ClassgetObjectType() {
- return FactoryCreatedAnnotationTestBean.class; }
- public boolean isSingleton() { return true;
- } }
其他的Proxy,RMI,JNDI等等,都是根据相应的策略提供getObject的实现。这里不做一一分析,这已经不是Spring的核心功能,有需要的时候再去深入研究。
4.BeanPostProcessor后置处理器的实现:
BeanPostProcessor后置处理器是Spring IoC容器经常使用到的一个特性,这个Bean后置处理器是一个监听器,可以监听容器触发的Bean声明周期事件。后置处理器想容器注册以后,容器中管理的Bean就具备了接收IoC容器事件回调的能力。
BeanPostProcessor的使用非常简单,只需要提供一个实现接口BeanPostProcessor的实现类,然后在Bean的配置文件中设置即可。
(1).BeanPostProcessor的源码如下:
- package org.springframework.beans.factory.config; import org.springframework.beans.BeansException;
- public interface BeanPostProcessor { //为在Bean的初始化前提供回调入口
- Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException; //为在Bean的初始化之后提供回调入口
- Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException; }
这两个回调的入口都是和容器管理的Bean的生命周期事件紧密相关,可以为用户提供在Spring IoC容器初始化Bean过程中自定义的处理操作。
(2).AbstractAutowireCapableBeanFactory类对容器生成的Bean添加后置处理器:
BeanPostProcessor后置处理器的调用发生在Spring IoC容器完成对Bean实例对象的创建和属性的依赖注入完成之后,在对Spring依赖注入的源码分析过程中我们知道,当应用程序第一次调用getBean方法(lazy-init预实例化除外)向Spring IoC容器索取指定Bean时触发Spring IoC容器创建Bean实例对象并进行依赖注入的过程,其中真正实现创建Bean对象并进行依赖注入的方法是AbstractAutowireCapableBeanFactory类的doCreateBean方法,主要源码如下:
[java]- //真正创建Bean的方法 protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
- //创建Bean实例对象 ……
- try { //对Bean属性进行依赖注入
- populateBean(beanName, mbd, instanceWrapper); if (exposedObject != null) {
- //在对Bean实例对象生成和依赖注入完成以后,开始对Bean实例对象 //进行初始化 ,为Bean实例对象应用BeanPostProcessor后置处理器
- exposedObject = initializeBean(beanName, exposedObject, mbd); }
- } catch (Throwable ex) {
- if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) { throw (BeanCreationException) ex;
- } ……
- //为应用返回所需要的实例对象 return exposedObject;
- }
从上面的代码中我们知道,为Bean实例对象添加BeanPostProcessor后置处理器的入口的是initializeBean方法。
(3).initializeBean方法为容器产生的Bean实例对象添加BeanPostProcessor后置处理器:
同样在AbstractAutowireCapableBeanFactory类中,initializeBean方法实现为容器创建的Bean实例对象添加BeanPostProcessor后置处理器,源码如下:
[java]- //初始容器创建的Bean实例对象,为其添加BeanPostProcessor后置处理器 protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
- //JDK的安全机制验证权限 if (System.getSecurityManager() != null) {
- //实现PrivilegedAction接口的匿名内部类 AccessController.doPrivileged(new PrivilegedAction() {
- public Object run() { invokeAwareMethods(beanName, bean);
- return null; }
- }, getAccessControlContext()); }
- else { //为Bean实例对象包装相关属性,如名称,类加载器,所属容器等信息
- invokeAwareMethods(beanName, bean); }
- Object wrappedBean = bean; //对BeanPostProcessor后置处理器的postProcessBeforeInitialization
- //回调方法的调用,为Bean实例初始化前做一些处理 if (mbd == null || !mbd.isSynthetic()) {
- wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); }
- //调用Bean实例对象初始化的方法,这个初始化方法是在Spring Bean定义配置 //文件中通过init-method属性指定的
- try { invokeInitMethods(beanName, wrappedBean, mbd);
- } catch (Throwable ex) {
- throw new BeanCreationException( (mbd != null ? mbd.getResourceDescription() : null),
- beanName, Invocation of init method failed, ex); }
- //对BeanPostProcessor后置处理器的postProcessAfterInitialization //回调方法的调用,为Bean实例初始化之后做一些处理
- if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
- } return wrappedBean;
- } //调用BeanPostProcessor后置处理器实例对象初始化之前的处理方法
- public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException {
- Object result = existingBean; //遍历容器为所创建的Bean添加的所有BeanPostProcessor后置处理器
- for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) { //调用Bean实例所有的后置处理中的初始化前处理方法,为Bean实例对象在
- //初始化之前做一些自定义的处理操作 result = beanProcessor.postProcessBeforeInitialization(result, beanName);
- if (result == null) { return result;
- } }
- return result; }
- //调用BeanPostProcessor后置处理器实例对象初始化之后的处理方法 public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
- throws BeansException { Object result = existingBean;
- //遍历容器为所创建的Bean添加的所有BeanPostProcessor后置处理器 for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
- //调用Bean实例所有的后置处理中的初始化后处理方法,为Bean实例对象在 //初始化之后做一些自定义的处理操作
- result = beanProcessor.postProcessAfterInitialization(result, beanName); if (result == null) {
- return result; }
- } return result;
- }
BeanPostProcessor是一个接口,其初始化前的操作方法和初始化后的操作方法均委托其实现子类来实现,在Spring中,BeanPostProcessor的实现子类非常的多,分别完成不同的操作,如:AOP面向切面编程的注册通知适配器、Bean对象的数据校验、Bean继承属性/方法的合并等等,我们以最简单的AOP切面织入来简单了解其主要的功能。
(4).AdvisorAdapterRegistrationManager在Bean对象初始化后注册通知适配器:
AdvisorAdapterRegistrationManager是BeanPostProcessor的一个实现类,其主要的作用为容器中管理的Bean注册一个面向切面编程的通知适配器,以便在Spring容器为所管理的Bean进行面向切面编程时提供方便,其源码如下:
[java]- //为容器中管理的Bean注册一个面向切面编程的通知适配器 public class AdvisorAdapterRegistrationManager implements BeanPostProcessor {
- //容器中负责管理切面通知适配器注册的对象 private AdvisorAdapterRegistry advisorAdapterRegistry = GlobalAdvisorAdapterRegistry.getInstance();
- public void setAdvisorAdapterRegistry(AdvisorAdapterRegistry advisorAdapterRegistry) { this.advisorAdapterRegistry = advisorAdapterRegistry;
- } //BeanPostProcessor在Bean对象初始化前的操作
- public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { //没有做任何操作,直接返回容器创建的Bean对象
- return bean; }
- //BeanPostProcessor在Bean对象初始化后的操作 public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
- if (bean instanceof AdvisorAdapter){ //如果容器创建的Bean实例对象是一个切面通知适配器,则向容器的注册this.advisorAdapterRegistry.registerAdvisorAdapter((AdvisorAdapter) bean);
- } return bean;
- } }
其他的BeanPostProcessor接口实现类的也类似,都是对Bean对象使用到的一些特性进行处理,或者向IoC容器中注册,为创建的Bean实例对象做一些自定义的功能增加,这些操作是容器初始化Bean时自动触发的,不需要认为的干预。
5.Spring IoC容器autowiring实现原理:
Spring IoC容器提供了两种管理Bean依赖关系的方式:
a. 显式管理:通过BeanDefinition的属性值和构造方法实现Bean依赖关系管理。
b. autowiring:Spring IoC容器的依赖自动装配功能,不需要对Bean属性的依赖关系做显式的声明,只需要在配置好autowiring属性,IoC容器会自动使用反射查找属性的类型和名称,然后基于属性的类型或者名称来自动匹配容器中管理的Bean,从而自动地完成依赖注入。
通过对autowiring自动装配特性的理解,我们知道容器对Bean的自动装配发生在容器对Bean依赖注入的过程中。在前面对Spring IoC容器的依赖注入过程源码分析中,我们已经知道了容器对Bean实例对象的属性注入的处理发生在AbstractAutoWireCapableBeanFactory类中的populateBean方法中,我们通过程序流程分析autowiring的实现原理:
(1). AbstractAutoWireCapableBeanFactory对Bean实例进行属性依赖注入:
应用第一次通过getBean方法(配置了lazy-init预实例化属性的除外)向IoC容器索取Bean时,容器创建Bean实例对象,并且对Bean实例对象进行属性依赖注入,AbstractAutoWireCapableBeanFactory的populateBean方法就是实现Bean属性依赖注入的功能,其主要源码如下:
[java] view plaincopy- protected void populateBean(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw) { //获取Bean定义的属性值,并对属性值进行处理
- PropertyValues pvs = mbd.getPropertyValues(); ……
- //对依赖注入处理,首先处理autowiring自动装配的依赖注入 if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
- mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) { MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
- //根据Bean名称进行autowiring自动装配处理 if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
- autowireByName(beanName, mbd, bw, newPvs); }
- //根据Bean类型进行autowiring自动装配处理 if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
- autowireByType(beanName, mbd, bw, newPvs); }
- } //对非autowiring的属性进行依赖注入处理
- …… }
(2).Spring IoC容器根据Bean名称或者类型进行autowiring自动依赖注入:
[java] view plaincopy- //根据名称对属性进行自动依赖注入 protected void autowireByName(
- String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) { //对Bean对象中非简单属性(不是简单继承的对象,如8中原始类型,字符串,URL等//都是简单属性)进行处理
- String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw); for (String propertyName : propertyNames) {
- //如果Spring IoC容器中包含指定名称的Bean if (containsBean(propertyName)) {
- //调用getBean方法向IoC容器索取指定名称的Bean实例,迭代触发属性的//初始化和依赖注入 Object bean = getBean(propertyName);
- //为指定名称的属性赋予属性值 pvs.add(propertyName, bean);
- //指定名称属性注册依赖Bean名称,进行属性依赖注入 registerDependentBean(propertyName, beanName);
- if (logger.isDebugEnabled()) { logger.debug(Added autowiring by name from bean name ‘ + beanName +
- ‘ via property ‘ + propertyName + ‘ to bean named ‘ + propertyName + ‘); }
- } else {
- if (logger.isTraceEnabled()) { logger.trace(Not autowiring property ‘ + propertyName + ‘ of bean ‘ + beanName +
- ‘ by name: no matching bean found); }
- } }
- } //根据类型对属性进行自动依赖注入
- protected void autowireByType( String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
- //获取用户定义的类型转换器 TypeConverter converter = getCustomTypeConverter();
- if (converter == null) { converter = bw;
- } //存放解析的要注入的属性
- SetautowiredBeanNames = new LinkedHashSet(4); //对Bean对象中非简单属性(不是简单继承的对象,如8中原始类型,字符
- //URL等都是简单属性)进行处理 String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
- for (String propertyName : propertyNames) { try {
- //获取指定属性名称的属性描述器 PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
- //不对Object类型的属性进行autowiring自动依赖注入 if (!Object.class.equals(pd.getPropertyType())) {
- //获取属性的setter方法 MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
- //检查指定类型是否可以被转换为目标对象的类型 boolean eager = !PriorityOrdered.class.isAssignableFrom(bw.getWrappedClass());
- //创建一个要被注入的依赖描述 DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
- //根据容器的Bean定义解析依赖关系,返回所有要被注入的Bean对象 Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
- if (autowiredArgument != null) { //为属性赋值所引用的对象
- pvs.add(propertyName, autowiredArgument); }
- for (String autowiredBeanName : autowiredBeanNames) { //指定名称属性注册依赖Bean名称,进行属性依赖注入
- registerDependentBean(autowiredBeanName, beanName); if (logger.isDebugEnabled()) {
- logger.debug(Autowiring by type from bean name ‘ + beanName + ‘ via property ‘ + propertyName + ‘ to bean named ‘ + autowiredBeanName + ‘);
- } }
- //释放已自动注入的属性 autowiredBeanNames.clear();
- } }
- catch (BeansException ex) { throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);
- } }
- }
通过上面的源码分析,我们可以看出来通过属性名进行自动依赖注入的相对比通过属性类型进行自动依赖注入要稍微简单一些,但是真正实现属性注入的是DefaultSingletonBeanRegistry类的registerDependentBean方法。
(3).DefaultSingletonBeanRegistry的registerDependentBean方法对属性注入:
[java] view plaincopy- //为指定的Bean注入依赖的Bean public void registerDependentBean(String beanName, String dependentBeanName) {
- //处理Bean名称,将别名转换为规范的Bean名称 String canonicalName = canonicalName(beanName);
- //多线程同步,保证容器内数据的一致性 //先从容器中:bean名称-->全部依赖Bean名称集合找查找给定名称Bean的依赖Bean
- synchronized (this.dependentBeanMap) { //获取给定名称Bean的所有依赖Bean名称
- SetdependentBeans = this.dependentBeanMap.get(canonicalName); if (dependentBeans == null) {
- //为Bean设置依赖Bean信息 dependentBeans = new LinkedHashSet(8);
- this.dependentBeanMap.put(canonicalName, dependentBeans); }
- //向容器中:bean名称-->全部依赖Bean名称集合添加Bean的依赖信息 //即,将Bean所依赖的Bean添加到容器的集合中
- dependentBeans.add(dependentBeanName); }
- //从容器中:bean名称-->指定名称Bean的依赖Bean集合找查找给定名称 //Bean的依赖Bean
- synchronized (this.dependenciesForBeanMap) { SetdependenciesForBean = this.dependenciesForBeanMap.get(dependentBeanName);
- if (dependenciesForBean == null) { dependenciesForBean = new LinkedHashSet(8);
- this.dependenciesForBeanMap.put(dependentBeanName, dependenciesForBean); }
- //向容器中:bean名称-->指定Bean的依赖Bean名称集合添加Bean的依赖信息 //即,将Bean所依赖的Bean添加到容器的集合中
- dependenciesForBean.add(canonicalName); }
- }
通过对autowiring的源码分析,我们可以看出,autowiring的实现过程:
a. 对Bean的属性迭代调用getBean方法,完成依赖Bean的初始化和依赖注入。
b. 将依赖Bean的属性引用设置到被依赖的Bean属性上。
c. 将依赖Bean的名称和被依赖Bean的名称存储在IoC容器的集合中。
Spring IoC容器的autowiring属性自动依赖注入是一个很方便的特性,可以简化开发时的配置,但是凡是都有两面性,自动属性依赖注入也有不足,首先,Bean的依赖关系在配置文件中无法很清楚地看出来,对于维护造成一定困难。其次,由于自动依赖注入是Spring容器自动执行的,容器是不会智能判断的,如果配置不当,将会带来无法预料的后果,所以自动依赖注入特性在使用时还是综合考虑。
以上是关于Spring框架中的容器以及两大特性的主要内容,如果未能解决你的问题,请参考以下文章