Spring技术内幕----------01IOC

  1. 1.spring使用转义符“&”来得到FactoryBean本身
  2. 2.区分FactoryBean和BeanFactory:在Spring种,所有的Bean都是由BeanFactory(也就是IOC容器管理的),但是对应FactoryBean而言,这个不是普通的Bean,而是能产生或修饰对象生成给工厂Bean
  3. 3.BeanFacroty接口
  4. public interface BeanFactory {
    
    
        String FACTORY_BEAN_PREFIX = "&";
        Object getBean(String name) throws BeansException;
        <T> T getBean(String name, Class<T> requiredType) throws BeansException;
        <T> T getBean(Class<T> requiredType) throws BeansException;
        Object getBean(String name, Object... args) throws BeansException;
        <T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
        boolean containsBean(String name);
        boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
        boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
        boolean isTypeMatch(String name, Class<?> targetType) throws              NoSuchBeanDefinitionException;
        Class<?> getType(String name) throws NoSuchBeanDefinitionException;
        String[] getAliases(String name);
    }
  5. 4.编程式使用IOC容器
ClassPathResource res=new ClassPathResource("beans.xml");
DefaultListableBeanFactory factory=new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader=new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinitions(res);
  1. 创建Ioc配置文件的抽象资源,这个抽象资源包括BeanDefinition的定义信息
  2. 创建一个BeanFactory,这里使用DefaultListableBeanFactory
  3. 创建一个载入BeanDefinition的读取器,这里使用XmlBeanDefinitionReader来载入XML文件形式的BeanDefiniiton,通过一个回调配置给BEanFactory
  4. 通过XmlBeanDefinitionReader来完成解析,完成整个载入和注册Bean后,需要的Ioc容器就建立起来了。

6.通常使用FileSystemXmlApplicationContext的实现来说明ApplicationContext的设计原理

 

  • 在FileSystemXmlApplicationContext种,ApplicationContext的主要功能已经在FileSystemXmlApplicationContext的基类AbstractXmlApplicationContext种实现了,所以FileSystemXmlApplicationContext只需要实现自身的两个功能:
  • //refresh函数载入BeanDefinition
    public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
    			throws BeansException {
    
    		super(parent);
    		setConfigLocations(configLocations);
    		if (refresh) {
    			refresh();
    		}
    	}
    //在BeanDefinitionReader的loadBeanDefinition中被调用
    @Override
    	protected Resource getResourceByPath(String path) {
    		if (path != null && path.startsWith("/")) {
    			path = path.substring(1);
    		}
    		return new FileSystemResource(path);
    	}
    

    简单来说IOC容器的初始化是从refresh()方法来启动的,具体来说这个启动包括:

  • BeanDefinition的Resource定位

  • BeanDefinition的载入,把用户定义好的Bean表示成Ioc容器的内部的数据结构(BeanDefinition)

  • 注册,向Ioc容器注册这些BeanDefinition,通过调用BeanDefinitionRegistry接口实现的

在这个方法中,我们可以看到FileSystemXmlApplicationContext的refresh()会去调用父类的refresh方法(),在refresh()中的obtainFreshBeanFactory()方法经过层层调用,最终会调用FileSystemXmlApplicationContext的getResourceByPath()方法

步骤:进入refresh(),再进入obtainFreshBeanFactor()方法,再进入refreshBeanFactory(),可以看到

protected final void refreshBeanFactory() throws BeansException {
		//如果创建了BeanFactory,则销毁并关闭BeanFactory
        if (hasBeanFactory()) {
			destroyBeans();
			closeBeanFactory();
		}
        //这里是创建持有的DefaultListableBeanFactory的地方同时调用
		try {
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			beanFactory.setSerializationId(getId());
			customizeBeanFactory(beanFactory);
			//启动对BeanDefinition的载入,在载入的过程中定位资源,
            loadBeanDefinitions(beanFactory);
			synchronized (this.beanFactoryMonitor) {
				this.beanFactory = beanFactory;
			}
		}
		catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}

createBeanFactory()方法会创建一个IOC容器供ApplicationContext使用,同时启动loadBeanDefinitions来载入,在载入的过程中定位资源,
   

先回到refresh()方法:

@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			prepareRefresh();

			//这里是在子类中启动refreshBeanFactory()的地方
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);

			try {
				//设置BeanFactory的后置处理
				postProcessBeanFactory(beanFactory);

				//调用BeanFactory后置处理器,这些后置处理器是在Bean定义中向容器注册的
				invokeBeanFactoryPostProcessors(beanFactory);

				// 注册Bean的后置处理器,在Bean创建过程中调用
				registerBeanPostProcessors(beanFactory);

				// 对上下文中的消息源进行初始化
				initMessageSource();

				//初始化上下文中的事件机制
				initApplicationEventMulticaster();

				//初始化其他特殊的Bean
				onRefresh();

				// 检测监听Bean并将这些Bean向容器注册
				registerListeners();

				// 实例化所以的(noon-lazy-init)单件
				finishBeanFactoryInitialization(beanFactory);

				// 发布容器事件,结束refresh过程
				finishRefresh();
			}

			catch (BeansException ex) {
				logger.warn("Exception encountered during context initialization - cancelling refresh attempt", ex);

				//销毁
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}
		}
	}

loadBeanDefinitions()方法中,会得到resource的inputStream,再得到解析xml的文档流对象(使用documentLoader完成),然后按照Spring定义的Bean的规则来对这个XML的文档树进行解析

总的来说,BeanDefinition的载入分成两部分,

①得到document对象(读取<bean>.读取<property>(若里面为list,则遍历解析)),

②按照Bean规则进行解析

在得到文档流对象后,完成对BeanDefinition的处理,处理的结果由BeanDefinitionHolder对象来持有(除了持有BeanDefinition对象外,还有Bean的名字,别名集合等),然后就向Ioc容器注册解析得到的BeanDefinition

具体的文档解析过程:

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
        //这里取得<bean>元素走红定义的id,name和aliase属性的值
		String id = ele.getAttribute(ID_ATTRIBUTE);
		String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

		List<String> aliases = new ArrayList<String>();
		if (StringUtils.hasLength(nameAttr)) {
			String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
			aliases.addAll(Arrays.asList(nameArr));
		}

		String beanName = id;
		if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
			beanName = aliases.remove(0);
			if (logger.isDebugEnabled()) {
				logger.debug("No XML 'id' specified - using '" + beanName +
						"' as bean name and " + aliases + " as aliases");
			}
		}

		if (containingBean == null) {
			checkNameUniqueness(beanName, aliases, ele);
		}

        //开始详细的解析
		AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
		if (beanDefinition != null) {
			if (!StringUtils.hasText(beanName)) {
				try {
					if (containingBean != null) {
						beanName = BeanDefinitionReaderUtils.generateBeanName(
								beanDefinition, this.readerContext.getRegistry(), true);
					}
					else {
						beanName = this.readerContext.generateBeanName(beanDefinition);
						// Register an alias for the plain bean class name, if still possible,
						// if the generator returned the class name plus a suffix.
						// This is expected for Spring 1.2/2.0 backwards compatibility.
						String beanClassName = beanDefinition.getBeanClassName();
						if (beanClassName != null &&
								beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
								!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
							aliases.add(beanClassName);
						}
					}
					if (logger.isDebugEnabled()) {
						logger.debug("Neither XML 'id' nor 'name' specified - " +
								"using generated bean name [" + beanName + "]");
					}
				}
				catch (Exception ex) {
					error(ex.getMessage(), ele);
					return null;
				}
			}
			String[] aliasesArray = StringUtils.toStringArray(aliases);
			return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
		}

		return null;
	}

开始读取定义的<Bean>

public AbstractBeanDefinition parseBeanDefinitionElement(
			Element ele, String beanName, BeanDefinition containingBean) {

		this.parseState.push(new BeanEntry(beanName));

        //这里只读取<bean>中设置由class名字的,然后载入到BeanDefinition中去
        //注意,并不涉及对象的实例化,实例化是在依赖注入时完成的
		String className = null;
		if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
			className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
		}

		try {
			String parent = null;
			if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
				parent = ele.getAttribute(PARENT_ATTRIBUTE);
			}
            //生成需要的BeanDefinition对象,为Bean定义信息的载入做准备
			AbstractBeanDefinition bd = createBeanDefinition(className, parent);
            
            //对Bean元素进行解析,并设置description的信息
			parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
			bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
            //对各种<bean>元素的信息进行解析的地方
			parseMetaElements(ele, bd);
			parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
			parseReplacedMethodSubElements(ele, bd.getMethodOverrides());

            //解析<bean>的构造函数设置
			parseConstructorArgElements(ele, bd);
            //解析<bean>的property设置
			parsePropertyElements(ele, bd);
			parseQualifierElements(ele, bd);

			bd.setResource(this.readerContext.getResource());
			bd.setSource(extractSource(ele));

			return bd;
		}
		catch (ClassNotFoundException ex) {
			error("Bean class [" + className + "] not found", ele, ex);
		}
		catch (NoClassDefFoundError err) {
			error("Class that bean class [" + className + "] depends on not found", ele, err);
		}
		catch (Throwable ex) {
			error("Unexpected failure during bean definition parsing", ele, ex);
		}
		finally {
			this.parseState.pop();
		}

		return null;
	}

这里列举对property进行解析的例子:

//遍历property元素,再调用parsePropertyElement进行解析
public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
		NodeList nl = beanEle.getChildNodes();
		for (int i = 0; i < nl.getLength(); i++) {
			Node node = nl.item(i);
			if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) {
				parsePropertyElement((Element) node, bd);
			}
		}
	}

解析某个property

	public void parsePropertyElement(Element ele, BeanDefinition bd) {
		String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
		if (!StringUtils.hasLength(propertyName)) {
			error("Tag 'property' must have a 'name' attribute", ele);
			return;
		}
		this.parseState.push(new PropertyEntry(propertyName));
		try {
            //如果同一个Bean中已经由同名的property设置,那么起作用的只是第一个
			if (bd.getPropertyValues().contains(propertyName)) {
				error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
				return;
			}
            //解析结果,封装到PropertyValue对象中,然后设置到BeanDefinitionHolder中
			Object val = parsePropertyValue(ele, bd, propertyName);
			PropertyValue pv = new PropertyValue(propertyName, val);
			parseMetaElements(ele, pv);
			pv.setSource(extractSource(ele));
			bd.getPropertyValues().addPropertyValue(pv);
		}
		finally {
			this.parseState.pop();
		}
	}

取得property元素的值,也许是一个list或其他的

public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) {
	
String elementName = (propertyName != null) ?
						"<property> element for property '" + propertyName + "'" :
						"<constructor-arg> element";

		// Should only have one child element: ref, value, list, etc.
		NodeList nl = ele.getChildNodes();
		Element subElement = null;
		for (int i = 0; i < nl.getLength(); i++) {
			Node node = nl.item(i);
			if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) &&
					!nodeNameEquals(node, META_ELEMENT)) {
				// Child element is what we're looking for.
				if (subElement != null) {
					error(elementName + " must not contain more than one sub-element", ele);
				}
				else {
					subElement = (Element) node;
				}
			}
		}

        //判断property的属性是ref还是value,不允许同时存在ref和value
		boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
		boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
		if ((hasRefAttribute && hasValueAttribute) ||
				((hasRefAttribute || hasValueAttribute) && subElement != null)) {
			error(elementName +
					" is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);
		}
//如果是ref,创建RuntimeBeanReference,存放erf信息
		if (hasRefAttribute) {
			String refName = ele.getAttribute(REF_ATTRIBUTE);
			if (!StringUtils.hasText(refName)) {
				error(elementName + " contains empty 'ref' attribute", ele);
			}
			RuntimeBeanReference ref = new RuntimeBeanReference(refName);
			ref.setSource(extractSource(ele));
			return ref;
		}
//如果是value,创建一个value的数据对象TypedStringValue 存放值
		else if (hasValueAttribute) {
			TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));
			valueHolder.setSource(extractSource(ele));
			return valueHolder;
		}
//对子元素进行解析
		else if (subElement != null) {
			return parsePropertySubElement(subElement, bd);
		}
		else {
			// Neither child element nor "ref" or "value" attribute found.
			error(elementName + " must specify a ref or value", ele);
			return null;
		}
	}

对list进行解析,加入到target中,target的一个ManageList,除非对下一层子元素的解析

这样,XML文件中定义的BEanDefinition就被载入到Ioc容器了,并建立了数据映射

BeanDefinition再Ioc容器中的注册

这些BeanDefinition信息的使用map存储的,在DefaultListableBeanFactory中

private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(64);

依赖注入:

@Override
    public Object getBean(String name) throws BeansException {
        return doGetBean(name, null, null, 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,这种不需要重复创建
		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的生产结果
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}

		else {
			//检查能否再当前的BeanFactory中取得所需的Bean,若取不到,则一直往双亲找
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}

			// Check if bean definition exists in this factory.
			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);

				//取得当前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()) {
					sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
						@Override
						public Object getObject() throws BeansException {
							try {
								return createBean(beanName, mbd, args);
							}
							catch (BeansException ex) {
								// Explicitly remove instance from singleton cache: It might have been put there
								// eagerly by the creation process, to allow for circular reference resolution.
								// Also remove any beans that received a temporary reference to the bean.
								destroySingleton(beanName);
								throw ex;
							}
						}
					});
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}

				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 '" + 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;
			}
		}

		// 对创建的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;
	}

依赖注入步骤:

1.首先判断是否单例并且已经存在,若存在,则返回

2.若不存在,判断当前能否生产bean,不能则向双亲请求,直到找到能生产该bean的工厂

     2.1判断当前bean是否有依赖,如果有则递归创建

     2.2判断是单例,多例还是其他,然后创建bean

           2.2.1判断是否实例化,是否能由类加载器载入

            2.2.2判断是否bean有配置PostProcessor,有则返回一个proxy

            2.2.3没有的话则去创建实例bean

                       2.2.3.1如果是单例,先清除缓存中同名的Bean

                        2.2.3.2创建bean

                               2.2.3.2.1判断是否能实例化

                               2.2.3.2.2使用工厂实例化,不行则使用构造函数实例化,(使用jdk动态代理或CGLIB)

                                2.2.3.2.3实例化成功后则设置参数,比如基类,回调方法等

                          2.2.3.3开始依赖注入

                                  2.2.3.3.1autowire注入的处理,可以根据Bean的名字或类型

                                   2.2.3.3.2对属性进行解析(如果是array和list需要遍历),再解析的过程中,如果有依赖,要去获取

                                           2.2.3.3.2.1通过getPropertyValue取得Bean中对注入对象的引用,例如Array,List,Map,set等,然后注入,取得注入属性的                                                                set方法,通过反射机制,注入进入

最后返回即可获得注入的bean

 

容器的实现通过IOC管理Bean的生命周期实现,提供了对生命周期内各个时间点的回调

简单介绍Bean的生命周期:

  • Bean实例的创建
  • 为Bean实例设置属性
  • 调用Bean的(一系列,如果有的话)初始化方法
  • 应用通过Ioc容器使用Bean
  • 当容器关闭时,调用Bean的销毁方法

在调用Bean的初始化方法之前,会调用一系统的aware接口实现,把相关的BeanName,BeanClassLoader以及BeanFactory注入到Bean中去,接着调用inVokeInitMethods若实现了InitializingBean接口,会去调用agterPropertiesSet。若bean设置了initMethod,则会通过JDK的反射机制得到Method对象,之间调用Bean定义的初始化方法。

 

若定义了lazy-init属性,则在初始化的时候就预实例化

这里的预实例化巧妙的委托给容器,如果需要预实例化,则在refersh的过程中直接调用getBean去触发依赖注入

@autowire

以autowireByNam的实现过程来看

使用取得的当前Bean的属性名作为Bean的名字,向IOC容器索取bean,然后把得到的bean设置到当前Bean的属性中去

 

Bean对IOC容器的感知:

一般Bean不需要对ioc容器进行操作,但也可以通过aware接口来实现:

  • BeanNameAware,可以在Bean中得到它在IOC容器中的bean实例名
  • BeanFactoryAware,可以得到Bean所在的IOC容器,从而直接在Bean中使用ico容器的服务
  • ApplicationContextAware,得到Bean所在应用上下文,从而直接在Bean中使用应用上下文服务
  • MessageSourceAware,在Bean中得到消息源
  • ApplicationEvenPublisherAware,在Bean中得到应用上下文的事件发布器,从而直接在Bean中发布应用上下文的事件
  • ResourceLoaderAware,在Bean中得到ResourceLoader,从而在Bean中使用ResourceLoader加载外部的Resource资源

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值