Spring源码探究——Spring如何帮我们创建bean(上)

准备工作

首先准备测试用的类,我们使用最简单的xml配置的方式来进行源码的探究

1.准备Person类

public class person {
    String name;
    int age;

    person() {
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

2.准备测试类

    @Test
    public void test(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:bean.xml");
        person person = applicationContext.getBean("person", person.class);
    }

3.准备配置文件

        <bean id="person" class="com.core.pojo.person">
        </bean>

上——Spring如何解析我们的配置文件

试想,如果让你来简单实现Spring的IoC功能,你会怎么做?
我们可以

  • 1 通过IO流读取配置信息,并解析其中的内容
  • 根据配置信息,通过反射来创建类
  • 将创建的类放入一个Map中,供用户调用
    实际上Spring的实现IoC的思路也是这样的,不过Spring为了优雅解耦与可扩展和提供更强大更稳健的功能,封装了许多其他的辅助类,使用了多种设计模式来实现这个功能。

开始我们的源码探索
此时在ClassPathXmlApplicationContext类中

  public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
        this(new String[]{configLocation}, true, (ApplicationContext)null);
    }
    public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException {
        super(parent);
        this.setConfigLocations(configLocations);
        if (refresh) {
            this.refresh();
        }

    }

首先是两个构造方法,来构造ClassPathXmlApplicationContext即IoC容器对象。从debug中,我们可以发现configLocations参数的值即为我们传入的路径"bean.xml"。
这个构造方法的核心即为refresh()方法。在这里我们可以把它看作是创建IoC容器的方法。
继续向下探究
此时在AbstractApplicationContext类中,该类为ClassPathXmlApplicationContext的父类

    public void refresh() throws BeansException, IllegalStateException {
        synchronized(this.startupShutdownMonitor) {
            this.prepareRefresh();
            //顾名思义 得到BeanFactory
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            this.prepareBeanFactory(beanFactory);
            try {
            	//注册各种组件,完成各种任务,这里我们以后会提到
                this.postProcessBeanFactory(beanFactory);
                this.invokeBeanFactoryPostProcessors(beanFactory);
                this.registerBeanPostProcessors(beanFactory);
                this.initMessageSource();
                this.initApplicationEventMulticaster();
                this.onRefresh();
                this.registerListeners();
                this.finishBeanFactoryInitialization(beanFactory);
                //直到这里,我们在真正完成了IoC容器的初始化
                this.finishRefresh();
            } catch (BeansException var9) {
                //省略
                }
                //销毁beanFactory 省略
            } finally {
                this.resetCommonCaches();
            }
        }
    }

进入obtainFreshBeanFactory()方法

    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        this.refreshBeanFactory();
        ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();
        if (this.logger.isDebugEnabled()) {
		//日志相关,省略
        }
        return beanFactory;
    }

到这里还是没有看出Spring干了什么“实事”,继续向下调用
此时在AbstractRefreshableApplicationContext
类中,该类为AbstractApplicationContext的子类

 protected final void refreshBeanFactory() throws BeansException {
        //如果已经存在bean工厂,则直接销毁
        if (this.hasBeanFactory()) {
            this.destroyBeans();
            this.closeBeanFactory();
        }
        try {
        	//这里来创建我们标题中的DefaultListableBeanFactory,this.createBeanFactory()方法可以看作new DefaultListableBeanFactory(),不过它初始化了一些参数,这里暂不讨论。
            DefaultListableBeanFactory beanFactory = this.createBeanFactory();
            beanFactory.setSerializationId(this.getId());
            //“自定义beanFactory” 主要是设置是否允许循坏依赖与是否允许bean覆盖的参数的配置
            this.customizeBeanFactory(beanFactory);
            //加载bean定义信息
            this.loadBeanDefinitions(beanFactory);
            synchronized(this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        } catch (IOException var5) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var5);
        }
    }

这个方法中,终于出现我们小标题里的一个组件DefaultListableBeanFactory,似乎Spring要开始搞事情了。再忘下来到loadBeanDefinitions()方法
此时来到AbstractXmlApplicationContext,该类为AbstractRefreshableApplicationContext的子类

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
		//顾名思义,解读Xml文件的类
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
        //设置环境 环境即为我们主机的一些信息,包括JAVA_HOME,系统版本等。
        beanDefinitionReader.setEnvironment(this.getEnvironment());
        beanDefinitionReader.setResourceLoader(this);
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
        this.initBeanDefinitionReader(beanDefinitionReader);
        this.loadBeanDefinitions(beanDefinitionReader);
    }
    //上面方法主要的做的事情即初始化XmlReader
    protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
        Resource[] configResources = this.getConfigResources();
        if (configResources != null) {
            reader.loadBeanDefinitions(configResources);
        }
        //我们是通过配置文件的路径来获取类信息的,所以来到这个逻辑
        //同样的此处的configLocations长度为1,即”bean.xml“
        String[] configLocations = this.getConfigLocations();
        if (configLocations != null) {
        	//来到加载Bean定义方法
            reader.loadBeanDefinitions(configLocations);
        }

    }

来到AbstractBeanDefinitionReader类,该类为XmlBeanDefinitionReader的父类

    public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
        Assert.notNull(locations, "Location array must not be null");
        int counter = 0;
        //这里的location即为我没传入的配置文件的路经”classpath:bean.xml“
        String[] var3 = locations;
        int var4 = locations.length;
        for(int var5 = 0; var5 < var4; ++var5) {
            String location = var3[var5];
            counter += this.loadBeanDefinitions(location);
        }
        return counter;
    }
   
    public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
    	//获取资源解析器
        ResourceLoader resourceLoader = this.getResourceLoader();
        if (resourceLoader == null) {
            throw new BeanDefinitionStoreException("Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
        } else {
            int loadCount;
            if (!(resourceLoader instanceof ResourcePatternResolver)) {
            //如果解析器为该类型,则执行另一套逻辑,我们这里非该类型,所以省略了这部分代码。
                return loadCount;
            } else {
                try {
                	
                    Resource[] resources = ((ResourcePatternResolver)resourceLoader).getResources(location);
                    //重载方法,继续调用
                    loadCount = this.loadBeanDefinitions(resources);
                    //省略部分代码
                    return loadCount;
                } catch (IOException var10) {
                    throw new BeanDefinitionStoreException("Could not resolve bean definition resource pattern [" + location + "]", var10);
                }
            }
        }
    }
    public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
        Assert.notNull(resources, "Resource array must not be null");
        int counter = 0;
        Resource[] var3 = resources;
        int var4 = resources.length;
        //遍历所有的resource,一一进行解析,此时只有一个resource
        for(int var5 = 0; var5 < var4; ++var5) {
            Resource resource = var3[var5];
            //继续重载调用加载单个Resource的方法。
            counter += this.loadBeanDefinitions((Resource)resource);
        }

        return counter;
    }

此时我们传入的bean.xml已经被封装成了Resource对象,里面包括了类加载器已经项目中各种引入的类的信息。
在这里插入图片描述
此时回到XmlBeanDefinitionReader

 public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
 //包装resource后,继续调用重载方法
        return this.loadBeanDefinitions(new EncodedResource(resource));
    }
    
        public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
        //省略部分代码
        //初始化资源集合
        Set<EncodedResource> currentResources = (Set)this.resourcesCurrentlyBeingLoaded.get();
        if (currentResources == null) {
            currentResources = new HashSet(4);
            this.resourcesCurrentlyBeingLoaded.set(currentResources);
        }

        //如果添加失败,则说明发生循环依赖,报错。
        if (!((Set)currentResources).add(encodedResource)) {
            throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");
        } else {
            int var5;
            try {
            //经过一系列的包装,我们最初传入的"classpath:bean.xml"字符串已经被封装成了一个EncodedResource对象,终于在此处获取到了它的流对象"
                InputStream inputStream = encodedResource.getResource().getInputStream();
                try {
                   //包装
                    InputSource inputSource = new InputSource(inputStream);
                    if (encodedResource.getEncoding() != null) {
                        inputSource.setEncoding(encodedResource.getEncoding());
                    }
					//开始解析流对象!!
                    var5 = this.doLoadBeanDefinitions(inputSource, encodedResource.getResource());
                } finally {
                    inputStream.close();
                }
            } catch (IOException var15) {
                throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), var15);
            } finally {
                ((Set)currentResources).remove(encodedResource);
                if (((Set)currentResources).isEmpty()) {
                    this.resourcesCurrentlyBeingLoaded.remove();
                }
            }
            return var5;
        }
    }
 //解析流对象的方法
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
        try {
        	//将xml解析成为DOM对象
            Document doc = this.doLoadDocument(inputSource, resource);
            //将DOM对象进行注册
            return this.registerBeanDefinitions(doc, resource);
        } catch (BeanDefinitionStoreException var4) {
            //捕获各种异常,这里省略。
            throw var4;
        } 
        }
    }
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
		//省略...
		//继续调用注册方法
        documentReader.registerBeanDefinitions(doc, this.createReaderContext(resource));
        return this.getRegistry().getBeanDefinitionCount() - countBefore;
    }

解析的DOM对象所包含的信息
在这里插入图片描述

    public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
        this.readerContext = readerContext;
        this.logger.debug("Loading bean definitions");
        //获取DOM对象的根元素,这里可以理解为<beans>标签所对应的内容
        Element root = doc.getDocumentElement();
        //继续调用注册
        this.doRegisterBeanDefinitions(root);
    }
protected void doRegisterBeanDefinitions(Element root) {
		//委托者模式,创建一个委托者来帮忙解析Element对象
        BeanDefinitionParserDelegate parent = this.delegate;
        this.delegate = this.createDelegate(this.getReaderContext(), root, parent);
        if (this.delegate.isDefaultNamespace(root)) {
        	//首先解析profile标签,该标签主要用来指定使用哪个配置文件(生产环境/开发环境)
            String profileSpec = root.getAttribute("profile");
				//解析过程省略
                }
            }
        }
		//这里是个空方法,可能是用来标记开始解析节点
        this.preProcessXml(root);
        //解析节点的方法
        this.parseBeanDefinitions(root, this.delegate);
        //空方法,标记解析节点结束
        this.postProcessXml(root);
        this.delegate = parent;
    }
    
  protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
  		//判断是否为默认的命名空间,即bean,alias,import等
        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)) {
                        this.parseDefaultElement(ele, delegate);
                    } else {
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        } else {
            delegate.parseCustomElement(root);
        }
    }
    
    private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
    //运用大量if else来判断ele的类型
        if (delegate.nodeNameEquals(ele, "import")) {
            this.importBeanDefinitionResource(ele);
        } else if (delegate.nodeNameEquals(ele, "alias")) {
            this.processAliasRegistration(ele);
        } else if (delegate.nodeNameEquals(ele, "bean")) {
            //我们只有bean标签,所以走这个逻辑
            this.processBeanDefinition(ele, delegate);
        } else if (delegate.nodeNameEquals(ele, "beans")) {
            this.doRegisterBeanDefinitions(ele);
        }
    }
    
    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    //BeanDefinitionHolder 该类主要用于保存beanDefinition与BeanName
	//调用委托者来进行解析
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if (bdHolder != null) {
       //包装bdHolder,主要是给beanDefinition中的一些属性赋值,包括是否懒加载,全类名等,
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);

            try {//解析结束,此时已经解析出了xml中的所有信息。
                BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());
            } catch (BeanDefinitionStoreException var5) {
                this.getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, var5);
            }

            this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }

    }
/**
我们先去看一看
*/

委托者对象中包含了各种标签的定义信息,我们可以确认xml中各元素的解析发生在该类中。
在这里插入图片描述

	//支线
    //来看一看真正的解析方法
    public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
    	//这里id对应<bean>标签中id的值,即"person"
        String id = ele.getAttribute("id");
        String nameAttr = ele.getAttribute("name");
        List<String> aliases = new ArrayList();
        //解析别名,这里没设置
        if (StringUtils.hasLength(nameAttr)) {
            String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, ",; ");
            aliases.addAll(Arrays.asList(nameArr));
        }
        String beanName = id;
        //这里判断别名与bean名称是否能对应
        if (!StringUtils.hasText(id) && !aliases.isEmpty()) {
            beanName = (String)aliases.remove(0);
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("No XML 'id' specified - using '" + beanName + "' as bean name and " + aliases + " as aliases");
            }
        }

        if (containingBean == null) {
            this.checkNameUniqueness(beanName, aliases, ele);
        }
		//将其封装成BeanDefination对象的方法
        AbstractBeanDefinition beanDefinition = this.parseBeanDefinitionElement(ele, beanName, containingBean);
       //省略
                }
            }

            String[] aliasesArray = StringUtils.toStringArray(aliases);
            return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
        } else {
            return null;
        }
    }

 public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean) {
        this.parseState.push(new BeanEntry(beanName));
        String className = null;
        if (ele.hasAttribute("class")) {
        //通过class标签获取全类名	
            className = ele.getAttribute("class").trim();
        }

        String parent = null;
        if (ele.hasAttribute("parent")) {
            parent = ele.getAttribute("parent");
        }

        try {
     		//通过全类名获取bean信息,并
            AbstractBeanDefinition bd = this.createBeanDefinition(className, parent);
            this.parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
            bd.setDescription(DomUtils.getChildElementValueByTagName(ele, "description"));
            //解析其他的各种标签。
            this.parseMetaElements(ele, bd);
            this.parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
            this.parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
            this.parseConstructorArgElements(ele, bd);
            this.parsePropertyElements(ele, bd);
            this.parseQualifierElements(ele, bd);
            bd.setResource(this.readerContext.getResource());
            bd.setSource(this.extractSource(ele));
            AbstractBeanDefinition var7 = bd;
            return var7;
        } catch (ClassNotFoundException var13) {
            this.error("Bean class [" + className + "] not found", ele, var13);
        } catch (NoClassDefFoundError var14) {
            this.error("Class that bean class [" + className + "] depends on not found", ele, var14);
        } catch (Throwable var15) {
            this.error("Unexpected failure during bean definition parsing", ele, var15);
        } finally {
            this.parseState.pop();
        }

        return null;
    }

在这里插入图片描述
我们可以看到,beandefinition中包含了bean类的所有信息,在实例化对象时所用的对应信息都从该类中取。我们可以把它看作bean的设计图纸。

继续我们的主线,此时我们已经或的bean的定义信息并将其封装进了后holder中,现在要做的就是将其保存到一个东西里,以便以后调用。
一个Util类

public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
        String beanName = definitionHolder.getBeanName();
       	//将bean的名字与bean的信息注册
        registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
        String[] aliases = definitionHolder.getAliases();
        if (aliases != null) {
            String[] var4 = aliases;
            int var5 = aliases.length;

            for(int var6 = 0; var6 < var5; ++var6) {
                String alias = var4[var6];
                //将别名也注册
                registry.registerAlias(beanName, alias);
            }
        }
    }

来到DefaultListableBeanFactory类,它是一个至关重要的组件

//真正的注册方法
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {
        Assert.hasText(beanName, "Bean name must not be empty");
        Assert.notNull(beanDefinition, "BeanDefinition must not be null");
   //省略
		//从高map中获取beanDefinition,如果注册过,则根据isAllowBeanDefinitionOverriding(是否允许beanDefinition信息重写)参数的情况来抛出异常,这里我们第一次注册,该old为空
        BeanDefinition oldBeanDefinition = (BeanDefinition)this.beanDefinitionMap.get(beanName);
        if (oldBeanDefinition != null) {
            if (!this.isAllowBeanDefinitionOverriding()) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName + "': There is already [" + oldBeanDefinition + "] bound.");
            }
            //打印日志相关,省略
            this.beanDefinitionMap.put(beanName, beanDefinition);
        } else {
        	//是否已经开始创建bean,依据是其维护的set对象是否为空
            if (this.hasBeanCreationStarted()) {
            //若已经开始,则需要进行一些同步措施
                synchronized(this.beanDefinitionMap) {
                    this.beanDefinitionMap.put(beanName, beanDefinition);
                    List<String> updatedDefinitions = new ArrayList(this.beanDefinitionNames.size() + 1);
                    updatedDefinitions.addAll(this.beanDefinitionNames);
                    updatedDefinitions.add(beanName);
                    this.beanDefinitionNames = updatedDefinitions;
                    if (this.manualSingletonNames.contains(beanName)) {
                        Set<String> updatedSingletons = new LinkedHashSet(this.manualSingletonNames);
                        updatedSingletons.remove(beanName);
                        this.manualSingletonNames = updatedSingletons;
                    }
                }
            } else {
            //最后,将name与beanMap放入一个Map中,供以后调用
                this.beanDefinitionMap.put(beanName, beanDefinition);
                //单独将name放到一个集合
                this.beanDefinitionNames.add(beanName);
                //将该bean从“手册”中删除,标名已创建成功。
                this.manualSingletonNames.remove(beanName);
            }

            this.frozenBeanDefinitionNames = null;
        }

        if (oldBeanDefinition != null || this.containsSingleton(beanName)) {
            this.resetBeanDefinition(beanName);
        }

    }

从源码中我们发现,DefaultListableBeanFactory内部维护了相当多的Map
在这里插入图片描述
它其实就是SpringIoC容器的"图纸工厂",维护各种与Bean定义有关的信息。

 Spring's default implementation of the {@link ConfigurableListableBeanFactory}
 * and {@link BeanDefinitionRegistry} interfaces: a full-fledged bean factory
 * based on bean definition metadata, extensible through post-processors.

官方给的定义是“一个成熟的,包含了所有bean定义元数据的,可以通过后置处理器扩展的工厂”。

结语

这篇文章我们主要分析了Spring是如何把我们的xml配置文件解析成一个个与类相关的BeanDefinition对象的。至于有了该BeanDefinition对象后,Spring怎么将其实例化,又怎么进行自动注入,我们留到以后再说。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值