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的实现源码:
[java]
- 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的源码如下:
[java
- 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框架学习[IoC容器高级特性]的更多相关文章
- Spring框架及IOC容器
Spring是一个非常活跃的开源框架, 它是一个基于IOC和AOP来构架多层JavaEE系统的框架,它的主要目地是简化企业开发.Spring以一种非侵入式的方式来管理你的代码, Spring提倡”最少 ...
- Spring框架 之IOC容器 和AOP详解
主要分析点: 一.Spring开源框架的简介 二.Spring下IOC容器和DI(依赖注入Dependency injection) 三.Spring下面向切面编程(AOP)和事务管理配置 一.S ...
- Spring.NET依赖注入框架学习--实例化容器常用方法
Spring.NET依赖注入框架学习---实例化容器常用方法 本篇学习实例化Spring.NET容器的俩种方式 1.通过XmlObjectFactory创建一个Spring.NET容器 IResour ...
- Spring框架学习之IOC(二)
Spring框架学习之IOC(二) 接着上一篇的内容,下面开始IOC基于注解装配相关的内容 在 classpath 中扫描组件 <context:component-scan> 特定组件包 ...
- Spring框架学习之IOC(一)
Spring框架学习之IOC(一) 先前粗浅地学过Spring框架,但当时忙于考试及后期实习未将其记录,于是趁着最近还有几天的空闲时间,将其稍微整理一下,以备后期查看. Spring相关知识 spri ...
- Spring框架学习02——Spring IOC 详解
1.Spring IOC的基本概念 IOC(Inverse of Control)反转控制的概念,就是将原本在程序中手动创建对象的控制权,交由Spring框架管理.当某个Java对象(调用者)需要调用 ...
- Spring框架学习1
AnonymouL 兴之所至,心之所安;尽其在我,顺其自然 新随笔 管理 Spring框架学习(一) 阅读目录 一. spring概述 核心容器: Spring 上下文: Spring AOP ...
- Spring.NET的IoC容器(The IoC container)——简介(Introduction)
简介 这个章节介绍了Spring Framework的控制反转(Inversion of Control ,IoC)的实现原理. Spring.Core 程序集是Spring.NET的 IoC 容器实 ...
- Spring之一:IoC容器体系结构
温故而知心. Spring IoC概述 常说spring的控制反转(依赖反转),看看维基百科的解释: 如果合作对象的引用或依赖关系的管理要由具体对象来完成,会导致代码的高度耦合和可测试性降低,这对复杂 ...
随机推荐
- JDK自带方法实现AES对称加密
请看代码. 1 package jdbc.pro.lin; 2 3 import java.security.InvalidAlgorithmParameterException; 4 import ...
- Java 线程Thread.Sleep详解
我们可能经常会用到 Thread.Sleep 函数来使线程挂起一段时间.那么你有没有正确的理解这个函数的用法呢? 思考下面这两个问题: 1.假设现在是 2008-4-7 12:00:00.000,如果 ...
- PHP 5.5 新特性
文章转自:http://wulijun.github.io/2013/07/17/whats-new-in-php-5-5.html http://www.cnblogs.com/yjf512/p/3 ...
- flask 项目的开发经验总结
已经开发了几个flask项目, 是时候总结一下了, 这里涉及到项目源码的组织, 常用的包, 源码示例. =========================需要的 python 包有:========= ...
- PHP 线程安全与非线程安全版本的区别深入解析
Windows版的PHP从版本5.2.1开始有Thread Safe(线程安全)和None Thread Safe(NTS,非线程安全)之分,这两者不同在于何处?到底应该用哪种?这里做一个简单的介绍 ...
- 在OS X中使用Homebrew
Homebrew可以很方便的进行软件包管理,用官网的一句话来形容就是 Homebrew 使 OS X 更完整.用 gem 来安装您的 gems.用 brew 来搞定它们的依赖包. 安装Homebrew ...
- 清北暑假模拟day2 之
/* 现场代码,枚举每条边删除 */ #include<iostream> #include<cstdio> #include<string> #include&l ...
- Swift2.1 语法指南——访问控制
原档:https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programmi ...
- Java连接池详解
于共享资源,有一个很著名的设计模式:资源池(Resource Pool).该模式正是为了解决资源的频繁分配﹑释放所造成的问题.为解决我们的问题,可以采用数据库连接池技术.数据库连接池的基本思想就是为数 ...
- 查看SQL Server日志 Part 1
曾经有朋友问我数据被删除了,不借助第三方工具能不能查是什么时候发生的. SQL Server提供了一个undocumented的函数fn_dblog可以让我们查看活动的transaction log. ...