spring是如何加载bean的?

来源:互联网 发布:妍霓丝黄金水知乎 编辑:程序博客网 时间:2024/05/19 16:05

我debug的是3.1.1版本的spring,因为刚好一个项目中用的是这个版本的源码,所以就直接拿这个版本的debug一下,了解一下spring加载bean的过程。

debug用的测试代码

测试类

public class Hello {    public void sayHello(String name){        System.out.println("Hello " + name);    }}
public class Test {    public static void main(String[] args) {        ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:spring.xml");        Hello h = (Hello) ac.getBean("hello");        h.sayHello("Mr zou");    }}

配置文件

<?xml version="1.0" encoding="UTF-8" ?><beans xmlns="http://www.springframework.org/schema/beans"       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       xsi:schemaLocation="http://www.springframework.org/schema/beans       http://www.springframework.org/schema/beans/spring-beans.xsd">    <bean id=" hello" class="com.zs.Hello"/></beans>

debug源码

spring中加载配置文件的代码主要过程在AbstractApplicationContext.refresh()这个方法中,在这个方法中通过obtainFreshBeanFactory()方法

public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// Prepare this context for refreshing.prepareRefresh();// Tell the subclass to refresh the internal bean factory.ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// Prepare the bean factory for use in this context.prepareBeanFactory(beanFactory);try {// Allows post-processing of the bean factory in context subclasses.postProcessBeanFactory(beanFactory);// Invoke factory processors registered as beans in the context.invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.registerBeanPostProcessors(beanFactory);// Initialize message source for this context.initMessageSource();// Initialize event multicaster for this context.initApplicationEventMulticaster();// Initialize other special beans in specific context subclasses.onRefresh();// Check for listener beans and register them.registerListeners();// Instantiate all remaining (non-lazy-init) singletons.finishBeanFactoryInitialization(beanFactory);// Last step: publish corresponding event.finishRefresh();}catch (BeansException ex) {// Destroy already created singletons to avoid dangling resources.destroyBeans();// Reset 'active' flag.cancelRefresh(ex);// Propagate exception to caller.throw ex;}}}

这个方法创建了beanfactory,并加载xml配置文件,并解析xml配置文件,最后把相应的解析完成后把生成的beandefinition放入DefaultListableBeanFactory的beanDefinitionMap中,在这个beandefinition保存着配置文件中bean的相关信息。

下面我们来看看是如何完成这个过程的。

加载配置文件

在debug进上面的方法后,继续debug,在XmlBeanDefinitionReader .loadBeanDefinitions()中,spring生成了一个配置文件的inputstream

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {Assert.notNull(encodedResource, "EncodedResource must not be null");if (logger.isInfoEnabled()) {logger.info("Loading XML bean definitions from " + encodedResource.getResource());}Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();if (currentResources == null) {currentResources = new HashSet<EncodedResource>(4);this.resourcesCurrentlyBeingLoaded.set(currentResources);}if (!currentResources.add(encodedResource)) {throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");}try {InputStream inputStream = encodedResource.getResource().getInputStream();try {InputSource inputSource = new InputSource(inputStream);if (encodedResource.getEncoding() != null) {inputSource.setEncoding(encodedResource.getEncoding());}return doLoadBeanDefinitions(inputSource, encodedResource.getResource());}finally {inputStream.close();}}catch (IOException ex) {throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), ex);}finally {currentResources.remove(encodedResource);if (currentResources.isEmpty()) {this.resourcesCurrentlyBeingLoaded.remove();}}}

然后我们发现实际的加载这个配置文件的方法在doLoadBeanDefinitions(inputSource, encodedResource.getResource())方法中。

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)throws BeanDefinitionStoreException {try {int validationMode = getValidationModeForResource(resource);Document doc = this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());return registerBeanDefinitions(doc, resource);}......

在这个方法中,第一行getValidationModeForResource()这个方法是用来获取xml配置文件的验证方式,了解xml验证的同学都知道xml文件有两种验证方式DTD和XSD,一些xml文件如果格式错误就会报错,比如web.xml,如果你不按一定的格式去配置xml文件,编译器就会报相应的错误。在返回去看最开始的spirng配置文件,可以发现采用的是xsd的方式。
下面开始获取这个配置文件的domcument对象,在获取配置文件的domcument对象的方法中,有一个参数是getEntityResolver(),用来获取EntityResolver的方法,那这个EntityResolver是用来干什么的呢?在上面我们已经获取到验证xml文件的方式,在构建这个dom对象的时候,会去网络上去加载这个xsd或dtd文件去验证xml,如果网络出现问题加载不到xsd或dtd文件,就可以用EntityResolver去加载本地的xsd或dtd文件去验证xml文件。最后是通过sax方式去解析的xml文件构建的这个dom对象。

解析并注册beandefinitions

继续往下debug,在XmlBeanDefinitionReader.registerBeanDefinitions()的方法中完成了注册beandefinitions。

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();//设置环境变量documentReader.setEnvironment(this.getEnvironment());//获得注册前的BeanDefinition数量int countBefore = getRegistry().getBeanDefinitionCount();//注册BeanDefinitionsdocumentReader.registerBeanDefinitions(doc, createReaderContext(resource));return getRegistry().getBeanDefinitionCount() - countBefore;}

下面在看看到底是如何注册BeanDefinitions,往下debug,发现注册的实现在DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions()方法中,在这个方法中进行下面相关主要操作

//                //解析前相关操作,留给子类去做   preProcessXml(root);parseBeanDefinitions(root, this.delegate);//解析后相关操作,留给子类去做postProcessXml(root);

除了解析前后的相关操作外,最后解析操作由parseBeanDefinitions这个方法来实现,在spring中有两种解析的处理操作。一种操作方法是处理配置文件中默认声明bean的,另一种操作方法是处理自定义bean声明

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {if (delegate.isDefaultNamespace(root)) {NodeList nl = root.getChildNodes();for (int i = 0; i < nl.getLength(); i++) {Node node = nl.item(i);if (node instanceof Element) {Element ele = (Element) node;if (delegate.isDefaultNamespace(ele)) {        //默认bean声明方式解析操作parseDefaultElement(ele, delegate);}else {        //自定义配置解析方式delegate.parseCustomElement(ele);}}}}else {delegate.parseCustomElement(root);}}

我们这里是用默认的bean配置,所以在debug时走的是上面的那一条线。

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {        //处理import标签if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {importBeanDefinitionResource(ele);}//处理alias标签else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {processAliasRegistration(ele);}//处理bean标签else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {processBeanDefinition(ele, delegate);}//处理beans标签else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {// recursedoRegisterBeanDefinitions(ele);}}

这里我们的配置的bean是bean标签

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);if (bdHolder != null) {bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);try {// Register the final decorated instance.BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());}catch (BeanDefinitionStoreException ex) {getReaderContext().error("Failed to register bean definition with name '" +bdHolder.getBeanName() + "'", ele, ex);}// Send registration event.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));}}

在processBeanDefinition方法中,第一行是通过这个配置文件构建一个BeanDefinitionHolder对象,这个时候bdHolder这个对象中已经有bean的id、name、class和alias等信息,在这个方法中spring解析了bean里面可能出现的一切的配置信息,具体的解析操作,感兴趣可以debug进行看看是如何解析各个元素的。这个bdHolder的包含内容如下图片:


第二个操作decorateBeanDefinitionIfRequired()方法是用来解析自定义标签。这里我们没有用自定义标签。 最后一步注册BeanDefinition,debug发现最终在DefaultListableBeanFactory.registerBeanDefinition()完成注册,其实注册就是把生成的beandefinition put到我们前面说的DefaultListableBeanFactory的beanDefinitionMap中。 最后调用fireComponentRegistered()方法完成事件的通知。

生成那些非延迟加载的bean

回到最初的refresh()方法,在

finishBeanFactoryInitialization(beanFactory);

这行代码中实现了非延迟加载bean的实例化。下面就是生成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;// Eagerly check singleton cache for manually registered singletons.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 + "'");}}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.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);}final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);checkMergedBeanDefinition(mbd, beanName, args);// Guarantee initialization of beans that the current bean depends on.String[] dependsOn = mbd.getDependsOn();if (dependsOn != null) {for (String dependsOnBean : dependsOn) {getBean(dependsOnBean);registerDependentBean(dependsOnBean, beanName);}}// Create bean instance.if (mbd.isSingleton()) {sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {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>() {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);}}}// Check if required type matches the type of the actual bean instance.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;}

在doGetBean()这个方法中,1、首先根据传入的name获取真实的beanname;2、尝试从缓存中获取bean对象;3、获取最开始构造的hbd对象;4、生成bean对象。生成bean的代码主要在下面这个doCreateBean()中

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {// Instantiate the bean.BeanWrapper instanceWrapper = null;if (mbd.isSingleton()) {instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);}if (instanceWrapper == null) {instanceWrapper = createBeanInstance(beanName, mbd, args);}final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);Class beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);// Allow post-processors to modify the merged bean definition.synchronized (mbd.postProcessingLock) {if (!mbd.postProcessed) {applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);mbd.postProcessed = true;}}// Eagerly cache singletons to be able to resolve circular references// even when triggered by lifecycle interfaces like BeanFactoryAware.boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&isSingletonCurrentlyInCreation(beanName));if (earlySingletonExposure) {if (logger.isDebugEnabled()) {logger.debug("Eagerly caching bean '" + beanName +"' to allow for resolving potential circular references");}addSingletonFactory(beanName, new ObjectFactory() {public Object getObject() throws BeansException {return getEarlyBeanReference(beanName, mbd, bean);}});}// Initialize the bean instance.Object exposedObject = bean;try {populateBean(beanName, mbd, instanceWrapper);if (exposedObject != null) {exposedObject = initializeBean(beanName, exposedObject, mbd);}}catch (Throwable ex) {if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {throw (BeanCreationException) ex;}else {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);}}if (earlySingletonExposure) {Object earlySingletonReference = getSingleton(beanName, false);if (earlySingletonReference != null) {if (exposedObject == bean) {exposedObject = earlySingletonReference;}else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {String[] dependentBeans = getDependentBeans(beanName);Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);for (String dependentBean : dependentBeans) {if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {actualDependentBeans.add(dependentBean);}}if (!actualDependentBeans.isEmpty()) {throw new BeanCurrentlyInCreationException(beanName,"Bean with name '" + beanName + "' has been injected into other beans [" +StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +"] in its raw version as part of a circular reference, but has eventually been " +"wrapped. This means that said other beans do not use the final version of the " +"bean. This is often the result of over-eager type matching - consider using " +"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");}}}}// Register bean as disposable.try {registerDisposableBeanIfNecessary(beanName, bean, mbd);}catch (BeanDefinitionValidationException ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);}return exposedObject;}
最终生成bean的方法就在这个doCreateBean()中,在这个方法中:1、首先创建一个bean的包装类beanwrapper,在生成这个包装类的时候,如果工厂方法不为空,则会使用工厂方法初始化bean,若已经解析过,ze则使用相应的构造方法去构造,否则则使用默认构造函数去构造,在使用默认构造方法构造的时候,如果这个类中没有override方法,则直接使用java反射,否则使用cglib字节码增强,生成一个含有override的代理类;2、在生成完bean后,然后开始注入属性,把配置文件中的属性都注入进去;3、最后初始化bean。

总结

到此,spring加载xml配置文件,并生成bean的大概过程就完成了。总的来说,首先开始加载xml配置文件,然后开始使用sax解析并校验xml配置文件,在解析xml文件,生成beandefinitions缓存起来,当我们去加载生成bean的时候,然后去加载这个缓存起来的beandefinitions,在根据不同的配置情况去生成bean,最后把bean加入缓存中缓存起来。


0 0
原创粉丝点击