码迷,mamicode.com
首页 > 编程语言 > 详细

Spring IOC基于源码的理解(二)

时间:2016-06-02 14:09:30      阅读:196      评论:0      收藏:0      [点我收藏+]

标签:

一.知识了解

1.Beanfactory和Application,BeanFactory和FactoryBean

    内容在Spring基本知识点(一)后半部分可见;

2.BeanDefinition

    BeanDefinition是IOC容器体系非常重要的核心数据结构,Spring通过BeanDefinition来管理基于Spring的应用中的各种对象以及他们之间的相互依赖关系,实际就是POJO对象在IOC容器中的抽象。在DefaultListableBeanFactory中使用数据结构ConcurrentHashMap装载,示例如下
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable{
	private final Map beanDefinitionMap;
	public DefaultListableBeanFactory()
    {
		//删除了其他代码
        beanDefinitionMap = new ConcurrentHashMap();//通过Map持有载入的BeanDefition
    }
}

3.编程式使用IOC容器

    方便理解IOC关键类的相互关系,修改上一篇的测试类代码
package RealUse;

import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.core.io.ClassPathResource;

public class Test {
	public static void main(String[] args) {
		//ApplicationContext ctx = new FileSystemXmlApplicationContext("bin/applicationContext.xml");
		ClassPathResource res = new ClassPathResource("applicationContext.xml");//1.创建IOC配置文件的抽象资源,包含了BeanDefinition的定义信息。资源定位。用的两个不同类路径:ClassPathResource;文件系统:FileSystemResource
		DefaultListableBeanFactory factory = new DefaultListableBeanFactory();//2.创建一个BeanFactory的容器
		XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);//3.创建一个载入BeanDefinition的读取器,载入XML形式的BeanDefinition
		reader.loadBeanDefinitions(res);
		System.out.println("1.===返回getObject==="+factory.getBean("sample").getClass()+"=====");
		System.out.println("2.===返回本身==="+factory.getBean("&sample").getClass()+"======");
	}
}

4.总体步骤

    IOC容器初始化(Resource定位、BeanDefinition的载入、IOC容器注册BeanDefinition)--->IOC容器的依赖注入

二.IOC容器的初始化

IOC容器的初始化由AbstractApplicationContext的refresh()启动,若已经有了容器存在那么需要把已有的容器销毁和关闭,保证refresh后使用的是新建立的IOC容器。看下具体代码:
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// 准备上下文用于刷新
			prepareRefresh();
			// 创建BeanFactory,Bean定义的解析与注册
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
			// 为该上下文配置已经生成的BeanFactory
			prepareBeanFactory(beanFactory);
			try {
				// 1.设置BeanFactory的后置处理,加工的是BeanDefinition
				postProcessBeanFactory(beanFactory);
				invokeBeanFactoryPostProcessors(beanFactory);
				
				// 2.注册bean的后处理器。
				//!!!区别:工厂后处理器在获取后立即调用,而Bean后处理器在获取后注册到上下文持有的beanfactory中,供以后操作调用
				registerBeanPostProcessors(beanFactory);
				// 3.初始化信息源
				initMessageSource();
				// 4.初始化事件机制
				initApplicationEventMulticaster();
				// 5.初始其它特殊Bean
				onRefresh();
				//6.注册事件监听器;(观察者模式中的观察者角色)获取ApplicationListener类型的所有bean,即事件监听器
				registerListeners();
				// 7.Bean的真正实例化,初始化lazy-init!=true的singleton的Bean
				finishBeanFactoryInitialization(beanFactory);
				//发布容器事件,结束Refresh过程
				finishRefresh();
			} catch (BeansException ex) {
				destroyBeans();
				cancelRefresh(ex);
				throw ex;
			}
		}
	}


总而言之:创建一个Application上下文持有的一个BeanFactory对象,当这个Beanfactory对象创建完成后,Spring将配置文件的信息解析成为一个个的BeanDefinition对象并装入到容器的Bean定义注册(BeanDefinitionRegistry)中。

1.Resource定位

    指的是BeanDefinition的资源定位,由ResourceLoader接口通过统一的Resource接口实现。

     ResourceLoader接口:通过该类的实例可以获得一个Resource实例,仅仅包含一个方法 Resource getResource(String location)用于返回一个Resource实例。
package org.springframework.core.io;
// Referenced classes of package org.springframework.core.io:
//            Resource
public interface ResourceLoader
{
    public abstract Resource getResource(String s);

    public abstract ClassLoader getClassLoader();

    public static final String CLASSPATH_URL_PREFIX = "classpath:";
}
    Resource接口是Spring资源访问的接口,Resource接口有大量的实现类。例如:
  • URLResource:访问网络资源
  • ClassPathResource:访问类加载路径里资源
  • FileSystemResource:访问文件系统里资源的实现类
    
    当Spring应用需要进行资源访问的时候,并不是直接使用以上Resource的实现类,而是调用ResourceLoader实例的getResource方法来获得资源。ResourceLoader将会负责选择Resource的实现类,也就是确定具体的资源访问策略,从而将应用程序和具体的资源访问策略分离开来。Spring会采用与ApplicationContext相同的策略访问资源。这就是设计模式中的策略模式(不同的策略拥有统一的接口,客户决定使用哪个策略类)

2.BeanDefinition的载入和解析

    把用户定义好的Bean成IOC容器内部的数据结构,完成后IOC容器BeanDefinition中存在的还只是一些静态的配置信息。
解析是一个很复杂的过程,以XML文件对象为例,在读取器XmlBeanDefinitionReader中得到代表XML文件的Resource,然后按照Spring的Bean的定义规则解析XML的文档树。具体的解析在BeanDefinitionParserDelegate中完成,不再详述,打算自己写一个简单的XML解析代码。

3.向IOC容器注册BeanDefinition的过程,通过调用BeanDefinitionRegistry的实现来完成。

    就是把解析得到的BeanDefinition设置到HashMap中。例如,DefaultListableBeanFactory实现了BeanDefinitionRegistry,该接口的实现完成了注册。
技术分享DefaultListableBeanFactory类中registerBeanDefinition如下
	public void registerBeanDefinition(String beanName,BeanDefinition beanDefinition) throws BeanDefinitionStoreException {
		Assert.hasText(beanName, "'beanName' must not be empty");
		Assert.notNull(beanDefinition, "BeanDefinition must not be null");
		if (beanDefinition instanceof AbstractBeanDefinition)
			try {
				((AbstractBeanDefinition) beanDefinition).validate();
			} catch (BeanDefinitionValidationException ex) {
				throw new BeanDefinitionStoreException(
						beanDefinition.getResourceDescription(), beanName,
						"Validation of bean definition failed", ex);
			}
			//加上synchronized
		synchronized (beanDefinitionMap) {
			//检查是否有同名BeanDefinition存在
			Object oldBeanDefinition = beanDefinitionMap.get(beanName);
			if (oldBeanDefinition != null) {
				if (!allowBeanDefinitionOverriding)
					throw new BeanDefinitionStoreException(
							beanDefinition.getResourceDescription(), beanName,
							(new StringBuilder(
									"Cannot register bean definition ["))
									.append(beanDefinition)
									.append("] for bean '").append(beanName)
									.append("': There is already [")
									.append(oldBeanDefinition)
									.append("] bound.").toString());
				if (logger.isInfoEnabled())
					logger.info((new StringBuilder(
							"Overriding bean definition for bean '"))
							.append(beanName).append("': replacing [")
							.append(oldBeanDefinition).append("] with [")
							.append(beanDefinition).append("]").toString());
			} else {
				beanDefinitionNames.add(beanName);
				frozenBeanDefinitionNames = null;
			}
			beanDefinitionMap.put(beanName, beanDefinition);//BeanName为key值,beanDefinition是value值
			resetBeanDefinition(beanName);
		}
	}

三.IOC容器的依赖注入

一般发生在getBean的时候也可以在预实例化的时候,流程图如下
技术分享

1.分析下getBean--->doGetBean的代码

	public <T> T getBean(String name, Class<T> requiredType, Object... args) throws BeansException {
	    return doGetBean(name, requiredType, args, false);
	}

	//这里是实际取得Bean的地方,也是触发依赖注入的地方
	protected <T> T doGetBean(
	            final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
	            throws BeansException {

	    final String beanName = transformedBeanName(name);
	    Object bean;

	    // 先从缓存中获取Bean,处理那些已经被创建过的单件模式的Bean,对这种Bean的请求不需要重复创建
	    Object sharedInstance = getSingleton(beanName);
	    if (sharedInstance != null && args == null) {
	        if (logger.isDebugEnabled()) {
	            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 + "'");
	            }
	        }
	        //FactoryBean相关处理,用来取得FactoryBean生产结果
	        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
	    }

	    else {
	        // Fail if we're already creating this bean instance:
	        // We're assumably within a circular reference.
	        if (isPrototypeCurrentlyInCreation(beanName)) {
	            throw new BeanCurrentlyInCreationException(beanName);
	        }

	        // Check if bean definition exists in this factory.
	        //对BeanDefinition是否存在进行检查。检查能否在当前工厂取到想要的Bean,如果当前工厂找不到,就去双亲工厂去取
	        BeanFactory parentBeanFactory = getParentBeanFactory();
	        if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
	            // Not found -> check parent.
	            String nameToLookup = originalBeanName(name);
	            if (args != null) {
	                // Delegation to parent with explicit args.
	                return (T) parentBeanFactory.getBean(nameToLookup, args);
	            }
	            else {
	                // No args -> delegate to standard getBean method.
	                return parentBeanFactory.getBean(nameToLookup, requiredType);
	            }
	        }

	        if (!typeCheckOnly) {
	            markBeanAsCreated(beanName);
	        }

	        try {
	            //根据Bean名字获取BeanDefinition
	            final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
	            checkMergedBeanDefinition(mbd, beanName, args);

	            // Guarantee initialization of beans that the current bean depends on.
	            //保证这些Bean依赖的Bean全部被初始化,可能会触发递归调用,直到取到无任何依赖的Bean为止!
	            String[] dependsOn = mbd.getDependsOn();
	            if (dependsOn != null) {
	                for (String dependsOnBean : dependsOn) {
	                    if (isDependent(beanName, dependsOnBean)) {
	                        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
	                                "Circular depends-on relationship between '" + beanName + "' and '" + dependsOnBean + "'");
	                    }
	                    registerDependentBean(dependsOnBean, beanName);
	                    getBean(dependsOnBean);
	                }
	            }

	            // Create bean instance.
	            if (mbd.isSingleton()) {
	                //通过createBean方法创建SingleTon Bean实例,有一个回调函数getObject,会在getSingleTon中调用ObjectFactory的createBean
	                sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
	                    @Override
	                    public Object getObject() throws BeansException {
	                        try {
	                            return createBean(beanName, mbd, args);
	                        }
	                        catch (BeansException ex) {
	                            destroySingleton(beanName);
	                            throw ex;
	                        }
	                    }
	                });
	                bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
	            }
	            //创建protoType的Bean
	            else if (mbd.isPrototype()) {
	                // It's a prototype -> create a new instance.
	                Object prototypeInstance = null;
	                try {
	                    beforePrototypeCreation(beanName);
	                    prototypeInstance = createBean(beanName, mbd, args);
	                }
	                finally {
	                    afterPrototypeCreation(beanName);
	                }
	                bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
	            }

	            else {
	                String scopeName = mbd.getScope();
	                final Scope scope = this.scopes.get(scopeName);
	                if (scope == null) {
	                    throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
	                }
	                try {
	                    Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
	                        @Override
	                        public Object getObject() throws BeansException {
	                            beforePrototypeCreation(beanName);
	                            try {
	                                return createBean(beanName, mbd, args);
	                            }
	                            finally {
	                                afterPrototypeCreation(beanName);
	                            }
	                        }
	                    });
	                    bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
	                }
	                catch (IllegalStateException ex) {
	                    throw new BeanCreationException(beanName,
	                            "Scope '" + scopeName + "' is not active for the current thread; consider " +
	                            "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
	                            ex);
	                }
	            }
	        }
	        catch (BeansException ex) {
	            cleanupAfterBeanCreationFailure(beanName);
	            throw ex;
	        }
	    }

	    // Check if required type matches the type of the actual bean instance.
	    //检查Bean的类型是不是需要的类型,如果是,就返回Bean,这个Bean已经是包含了依赖关系的Bean了。
	    if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
	        try {
	            return getTypeConverter().convertIfNecessary(bean, requiredType);
	        }
	        catch (TypeMismatchException ex) {
	            if (logger.isDebugEnabled()) {
	                logger.debug("Failed to convert bean '" + name + "' to required type [" +
	                        ClassUtils.getQualifiedName(requiredType) + "]", ex);
	            }
	            throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
	        }
	    }
	    return (T) bean;
	}

2.有两种实例化Java对象的方法:

  • 通过BeanUtils,使用了JVM的反射功能
  • 通过CGLIB(一个常用的字节码生成器的类库)生成、
	public Object instantiate(RootBeanDefinition beanDefinition,String beanName, BeanFactory owner) {
		//1.若没有配置lookup-method采用JVM的反射功能
		if (beanDefinition.getMethodOverrides().isEmpty()) {
			//取得指定的构造器或者是生成对象的工厂方法来对Bean进行实例化
			Constructor constructorToUse = (Constructor) beanDefinition.resolvedConstructorOrFactoryMethod;
			if (constructorToUse == null) {
				final Class clazz = beanDefinition.getBeanClass();
				if (clazz.isInterface())
					throw new BeanInstantiationException(clazz,"Specified class is an interface");
				try {
					if (System.getSecurityManager() != null)
						constructorToUse = (Constructor) AccessController.doPrivileged(new PrivilegedExceptionAction() {

									public Constructor run() throws Exception {
										return clazz.getDeclaredConstructor(null);
									}

									public volatile Object run()throws Exception {
										return run();
									}

									final SimpleInstantiationStrategy this$0;
									private final Class val$clazz;

									{
										this$0 = SimpleInstantiationStrategy.this;
										clazz = class1;
										super();
									}
								});
					else
						constructorToUse = clazz.getDeclaredConstructor(null);//利用反射获取构造函数
					beanDefinition.resolvedConstructorOrFactoryMethod = constructorToUse;
				} catch (Exception ex) {
					throw new BeanInstantiationException(clazz,"No default constructor found", ex);
				}
			}
			return BeanUtils.instantiateClass(constructorToUse, new Object[0]);
		} else {//2.如果配置了lookup-method使用CGLIB来实例化对象
			return instantiateWithMethodInjection(beanDefinition, beanName,
					owner);
		}
	}

3.lookup-method的应用

    如果一个singleton的调用者A依赖于一个prototype实例B,初始化singleton的时候会先实例化prototype,但是以后每次通过singleton调用prototype的时候,调用的永远是最开始的prototype。怎么解决呢?这种时候就要采用方法注入,即使用lookup-method的方法。Spring会采用运行时动态增强的方式CGLIB实现lookup-method。
    如下实例,Singleton的A依赖prototype的B。
普通
被依赖的Aprototype
package Sample;

public class Aprototype {
	private double a=0d;
	public Aprototype(){
		a=Math.random();
	}
	public void getRandom(){
		System.out.println("Prototype输出:"+a);
	}
}
Bsingleton(依赖Aprototype
package Sample;

public class Bsingleton {
	private Aprototype aprototype;
	public void setAprototype(Aprototype aprototype){
		this.aprototype=aprototype;
	}
	//public abstract Aprototype getAprototype();
	public void usePrototype(){
		aprototype.getRandom();
	}
}

 测试类
public class Test {
	public static void main(String[] args) {		
		ApplicationContext ctx = new FileSystemXmlApplicationContext("bin/applicationContext.xml");
		System.out.println("=====第一次调用Bsingleton======");
		Bsingleton b=(Bsingleton) ctx.getBean("bsingleton");
		b.usePrototype();
		
		System.out.println();
		
		System.out.println("=====第二次调用Bsingleton======");
		Bsingleton c=(Bsingleton) ctx.getBean("bsingleton");
		c.usePrototype();
	}      
}
配置文件
<bean id="bsingleton" class="Sample.Bsingleton">  
        <property name="aprototype" ref="aprototype" />
    </bean>     
    <bean id="aprototype" class="Sample.Aprototype" scope="prototype"></bean>


结果
=====第一次调用Bsingleton======
Prototype输出:0.6096473576637916


=====第二次调用Bsingleton======
Prototype输出:0.6096473576637916

分析:每次输出的结果一样,可见调用的始终是初始的prototype


采用lookup-method
Aprototype不变,测试类不变

    Bsingleton添加抽象方法,修改为抽象类
package Sample;

public abstract class Bsingleton {
	//private Aprototype aprototype;
	//public void setAprototype(Aprototype aprototype){
		//this.aprototype=aprototype;
	//}
	public abstract Aprototype getAprototype();
	public void usePrototype(){
		getAprototype().getRandom();
	}
}
    修改配置文件,改为lookup-method
<bean id="bsingleton" class="Sample.Bsingleton">  
        <lookup-method name="getAprototype" bean="aprototype" />
    </bean>     
    <bean id="aprototype" class="Sample.Aprototype" scope="prototype"></bean>


步骤:
  • 定义Bsingleton为抽象类,在Bsingleton中添加一个抽象的方法,该方法用于获取被依赖的Bean
  • 设置目标Bean为prototype  
  • Bsingleton的Bean中添加<lookup-method name="XX" bean="BB" />,name是需要让Spring实现的方法,bean指定该方法实现的返回值。
结果
=====第一次调用Bsingleton======
Prototype输出:0.7520596008690802


=====第二次调用Bsingleton======
Prototype输出:0.8769954010509483

分析:可以看到每次获取的值是不一样的,而不是始终是最初的prototype



文章参考资料:《Spring 技术内幕》

Spring IOC基于源码的理解(二)

标签:

原文地址:http://blog.csdn.net/ruobing2011/article/details/51556030

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!