Spring IOC源码解读

本文解析了Spring框架中IOC容器的实现原理,包括BeanFactory接口及其子接口的功能,ApplicationContext接口的高级特性,以及Bean的生命周期管理等核心概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

beanFactory接口继承关系

spring IOC部分的接口、抽象类继承关系非常复杂。想要读懂spring源码,首先要理清IOC部分的类继承关系。理解每个接口的作用。
这里写图片描述
如上图所示,BeanFactory类如其名,是真正实现了IOC容器的基类接口。它提供了bean容器的基本操作。如getBean()方法,containsBean()方法判断是否存在该bean,isSingleton()和isPrototype()方法分别判断bean的作用范围是容器中单例还是prototype,prototype这里运用了原型设计模式,即通过clone创建多个对象。除此之外,还包括isTypeMatch()方法用于判断bean的类型是否匹配,getType()方法获取bean的类型,getAliases()方法获取bean的别名。
有三个子接口继承了beanFactory。分别是:

  1. HierarchicalBeanFactory:类似一个中间接口,提供了getParentBeanFactory()方法。继承它的configurableBeanFactory接口负责对beanFactory的配置功能,如加载后置处理器(BeanPostProcessor)
  2. ListableBeanFactory:最常用的beanFactory,细化了一些beanFactory的操作,比如提供了getBeanDefinationNames()方法,封装了一些bean的高级操作。
  3. AutowireCapableBeanFactory:和上面一样,也是在beanFactory之上提供了一些对bean的操作(具体是干嘛的我也不知道)。
    这个接口系统以beanFactory和ApplicationContext为核心,而中间部分的接口关系对开发者并不友好,beanFactory提供了基础的容器功能,而ApplicationContext是spring面向开发者开放的真正“接口”,它在继承了三大BeanFactory接口之上,又继承了MessageSource(国际化相关接口)、ResourceLoader接口(资源读取,spring中的配置文件是以Resource形式存在的)以及ApplicationEventPublisher接口(事件处理),这些接口给予ApplicationContext更高级的特性。

如果不使用封装好的ApplicationContext,而使用ConfigurableBeanFactory下的DefaultListableBeanFactory实现类,需要我们手动加载配置文件并读取,过程较为繁琐,增加了一些灵活性(比如可以手动注册自定义的bean后置处理器),

 //加载配置文件并启动容器
        Resource resource = new ClassPathResource("spring-beans.xml");
        //DefaultListableBeanFactory实现了configurationBeanFactory和ListableBeanFactory接口,是IOC的一个重要实现,ApplicationContext也是基于它
        BeanFactory bf = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader((DefaultListableBeanFactory) bf);
        reader.loadBeanDefinitions(resource);
        //加载beanPostProcessor    后置bean处理器
        ((ConfigurableListableBeanFactory) bf).addBeanPostProcessor(new MyBeanPostProcessor());
        ((ConfigurableListableBeanFactory) bf).addBeanPostProcessor(new MyInstantiationAwareBeanPostProcessor());
        //从beanFactory中获取bean时对bean进行实例化。而是用applicationContext则是在容器启动时初始化所有bean
        Car car = (Car) bf.getBean("car");
        car.setColor("blue");
        //从容器缓存池中获取bean
        Car car1 = (Car) bf.getBean("car");
        System.out.println("是否为统一引用?" + (car == car1));
        //关闭容器
        ((ConfigurableListableBeanFactory) bf).destroySingletons();

但如果使用ApplicationContext,两行代码就完成了。

ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:spring-beans.xml");
ctx.getBean("car");

常用ClassPathXmlApplicationContext从classpath中读取配置文件,也可以使用FileSystemXmlApplicationContext从文件系统中读取,除此之外,spring也提供了在web环境下的WebApplicationContext,它继承了ApplicationContext,具备了ApplicationContext的所有功能。

IOC过程

IOC初始化:

1.资源位置解析(定位)
2.资源文件载入、解析
3.注册资源文件
在spring中,这三个操作是独立的,并不交给ApplicationContext处理,
我们从FileSystemXmlApplicationContext入手,看看IOC是怎么实现的,首先进入FileSystemXmlApplicationContext加载配置文件的重载方法。

public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException {
        super(parent);
        this.setConfigLocations(configLocations);
        if (refresh) {
            this.refresh();
        }
    }

这部分和ClappPathXmlApplicationContext一摸一样,
refresh是Bean初始化的核心方法,控制其初始化过程。

public void refresh() throws BeansException, IllegalStateException {
        Object var1 = this.startupShutdownMonitor;
        //加锁
        synchronized(this.startupShutdownMonitor) {
        //记录startTime,打开日志debug,初始化属性池
            this.prepareRefresh();
            //确保有且只有一个beanFactory初始化(默认DefaultListableBeanFactory)
            ConfigurableListableBeanFactory beanFactory = 
               this.obtainFreshBeanFactory();
               //为beanFactory注入配置信息
            this.prepareBeanFactory(beanFactory);

            try {
                //初始化bean后置处理器
                this.postProcessBeanFactory(beanFactory);
                //调用
                this.invokeBeanFactoryPostProcessors(beanFactory);
                //注册
                this.registerBeanPostProcessors(beanFactory);
                //初始化国际化支持
                this.initMessageSource();
                //初始化事件处理
                this.initApplicationEventMulticaster();
                this.onRefresh();
                this.registerListeners();
                this.finishBeanFactoryInitialization(beanFactory);
                this.finishRefresh();
            } catch (BeansException var5) {
                this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt", var5);
                this.destroyBeans();
                this.cancelRefresh(var5);
                throw var5;
            }

        }
    }
//上图中obtainFreshBeanFactory()方法调用的refreshBeanFactory()方法
protected final void refreshBeanFactory() throws BeansException {
//如果已存在beanFactory,则销毁,重建
        if (this.hasBeanFactory()) {
            this.destroyBeans();
            this.closeBeanFactory();
        }

        try {
        //以DefaultListableBeanFactory创建默认的beanFactory
            DefaultListableBeanFactory beanFactory = this.createBeanFactory();
            //设置唯一ID
            beanFactory.setSerializationId(this.getId());
            this.customizeBeanFactory(beanFactory);
            //加载beanDefinitions
            this.loadBeanDefinitions(beanFactory);
            Object var2 = this.beanFactoryMonitor;
            synchronized(this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        } catch (IOException var5) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var5);
        }
    }
//上图中loadBeanDefinitions()方法调用AbstractXmlApplicationContext实现类的方法
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
        beanDefinitionReader.setEnvironment(this.getEnvironment());
        beanDefinitionReader.setResourceLoader(this);
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
        this.initBeanDefinitionReader(beanDefinitionReader);
        this.loadBeanDefinitions(beanDefinitionReader);
    }

    //ApplicationContext并不处理配置文件的解析,加载。而是交给AbstractBeanDefinitionReader处理。
    protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
        Resource[] configResources = this.getConfigResources();
        if (configResources != null) {
            reader.loadBeanDefinitions(configResources);
        }
        //加载配置文件并计数
        String[] configLocations = this.getConfigLocations();
        if (configLocations != null) {
            reader.loadBeanDefinitions(configLocations);
        }

    }
//AbstractBeanDefinitionReader类处理配置文件
    public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
        Assert.notNull(locations, "Location array must not be null");
        int counter = 0;
        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, 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;
            //如果不是ResourcePatternResolver,使用默认resourceLoader定位资源
            //ResourcePatternResolver是专用来解析ant风格路径的
            //比如* ** ?:在资源加载中分别代表本目录,多级目录,任意字符
            if (!(resourceLoader instanceof ResourcePatternResolver)) {
                Resource resource = resourceLoader.getResource(location);
                loadCount = this.loadBeanDefinitions((Resource)resource);
                if (actualResources != null) {
                    actualResources.add(resource);
                }

                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
                }

                return loadCount;
            } else {
                try {
                //使用ResourcePatternResolver定位资源
                    Resource[] resources = ((ResourcePatternResolver)resourceLoader).getResources(location);
                    loadCount = this.loadBeanDefinitions(resources);
                    //actualResources用于保存实际的resource
                    if (actualResources != null) {
                        Resource[] var6 = resources;
                        int var7 = resources.length;

                        for(int var8 = 0; var8 < var7; ++var8) {
                            Resource resource = var6[var8];
                            actualResources.add(resource);
                        }
                    }

                    if (this.logger.isDebugEnabled()) {
                        this.logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
                    }

                    return loadCount;
                } catch (IOException var10) {
                    throw new BeanDefinitionStoreException("Could not resolve bean definition resource pattern [" + location + "]", var10);
                }
            }
        }
    }
//默认的资源加载器
//判断 文件系统路径 classpath路径  url风格 做相应处理
public Resource getResource(String location) {
        Assert.notNull(location, "Location must not be null");
        if (location.startsWith("/")) {
            return this.getResourceByPath(location);
        } else if (location.startsWith("classpath:")) {
            return new ClassPathResource(location.substring("classpath:".length()), this.getClassLoader());
        } else {
            try {
                URL url = new URL(location);
                return new UrlResource(url);
            } catch (MalformedURLException var3) {
            //做了异常处理,如果既不是classoath又不是url资源
                return this.getResourceByPath(location);
            }
        }
    }

//未完待续。。。

getBean()

先从bean的生命周期入手,分析一下getBean()方法的调用过程。
bean的生命周期
从图中可以看到,bean的生命周期经过四部分的方法处理
* 1.bean本身的方法,构造方法,getter/setter,自定义的init-method ,destroy-method(需在xml文件中配置)
* 2.bean实现生命周期接口的方法,如:
* BeanFactoryAware(setBeanFactory方法)
* BeanNameAware(setBeanName方法)
* InitializingBean(afterPropertiesSet方法,bean实例化前调用)
* DisposableBean(destroy方法,bean销毁时调用)
* 3.容器级声明周期方法:
* InstantiationAwareBeanPostAware接口的postProcessBeforeInstantiation方法(实例化前调用)、postProcessAfterInstantiation方法(实例化后调用)、postProcessPropertyValues方法(注入属性值时调用)
* BeanPostProcessor接口的postProcessBeforeInitialization方法、postProcessAfterInitialization方法。
以上生命周期的执行过程如图,但以上的接口与bean生命周期耦合的过于严重,除非开发spring的bean插件,否则完全可以抛弃除了BeanPostProcessor接口的其他生命周期接口。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值