Spring IOC源码分析


1、建立一个上下文-------ApplicationContext 一般是这两种

        //ClassPathXmlApplicationContext默认从classpath下查找xml文件,也就是打包了的项目路径
        //FileSystemXmlApplicationContext在指定的文件系统路径下查找xml文件
        ApplicationContext context = new ClassPathXmlApplicationContext();
        ApplicationContext context1 = new FileSystemXmlApplicationContext();

然后从容器中获取bean也就是 context.getBean();
异曲同工,功能几乎都差不多,所以本文从ClassPathXmlApplicationContext入手


2、ClassPathXmlApplicationContext源码,乍一看吓一跳,仔细看看,都基本上是构造方法,肯定会有人对于configResources的作用有疑问,这里我在比较了FileSystemXmlApplicationContext的源码后,本人推测应当是整个项目的配置信息,应该就是传递资源绝对路径给这个类。

public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {
    @Nullable//表示这个字段可以为空
    private Resource[] configResources;

    public ClassPathXmlApplicationContext() {
    }

    public ClassPathXmlApplicationContext(ApplicationContext parent) {
        super(parent);
    }

    public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
        this(new String[]{configLocation}, true, (ApplicationContext)null);
    }

    public ClassPathXmlApplicationContext(String... configLocations) throws BeansException {
        this(configLocations, true, (ApplicationContext)null);
    }

    public ClassPathXmlApplicationContext(String[] configLocations, @Nullable ApplicationContext parent) throws BeansException {
        this(configLocations, true, parent);
    }

    public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh) throws BeansException {
        this(configLocations, refresh, (ApplicationContext)null);
    }

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

    }

    public ClassPathXmlApplicationContext(String path, Class<?> clazz) throws BeansException {
        this(new String[]{path}, clazz);
    }

    public ClassPathXmlApplicationContext(String[] paths, Class<?> clazz) throws BeansException {
        this(paths, clazz, (ApplicationContext)null);
    }

    public ClassPathXmlApplicationContext(String[] paths, Class<?> clazz, @Nullable ApplicationContext parent) throws BeansException {
        super(parent);
        Assert.notNull(paths, "Path array must not be null");
        Assert.notNull(clazz, "Class argument must not be null");
        this.configResources = new Resource[paths.length];

        for(int i = 0; i < paths.length; ++i) {
            this.configResources[i] = new ClassPathResource(paths[i], clazz);
        }

        this.refresh();
    }

    @Nullable
    protected Resource[] getConfigResources() {
        return this.configResources;
    }
}

而上面这么多构造方法其实最终可能执行的就这三个

   1、父类的带parent的参数的方法
      AbstractXmlApplicationContext->.......->最终执行的便是AbstractApplicationContext的无参构造方法和setParent()方法
      AbstractApplicationContext(@Nullable ApplicationContext parent) {
        this();//调用无参构造方法
        this.setParent(parent);//设置parent属性为空则不合并环境信息
    }
        public AbstractApplicationContext() {
        this.logger = LogFactory.getLog(this.getClass());//获取日志
        this.id = ObjectUtils.identityToString(this);
        this.displayName = ObjectUtils.identityToString(this);
        this.beanFactoryPostProcessors = new ArrayList();//beanpostprocessor这个东西是bean生命周期的一个接口
        this.active = new AtomicBoolean();
        this.closed = new AtomicBoolean();
        this.startupShutdownMonitor = new Object();//这个做的是一个syn的锁
        this.applicationListeners = new LinkedHashSet();//监听器
        this.resourcePatternResolver = this.getResourcePatternResolver();
    }
        public void setParent(@Nullable ApplicationContext parent) {
        this.parent = parent;
        if (parent != null) {
            Environment parentEnvironment = parent.getEnvironment();
            if (parentEnvironment instanceof ConfigurableEnvironment) {
                this.getEnvironment().merge((ConfigurableEnvironment)parentEnvironment);
            }
        }

    }
   2、configLocations 配置信息  refresh 是否刷新工厂,也就是重新弄个beanFactory对象  parent一个可谓为空的 ApplicationContext 对象
    public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException {
        super(parent);
        this.setConfigLocations(configLocations);
        if (refresh) {
            this.refresh();
        }

    }

   3、paths 路径信息    clazz 传递了这个这个类编译过后的信息    parent 同上
   public ClassPathXmlApplicationContext(String[] paths, Class<?> clazz, @Nullable ApplicationContext parent) throws BeansException {
        super(parent);
        Assert.notNull(paths, "Path array must not be null");
        Assert.notNull(clazz, "Class argument must not be null");
        this.configResources = new Resource[paths.length];

        for(int i = 0; i < paths.length; ++i) {
            this.configResources[i] = new ClassPathResource(paths[i], clazz);
        }

        this.refresh();
    }

3、!!!不难发现,这些构造方法都调用了一个关键性的refresh()方法的调用,这个就是重点了。
(1)BeanPostProcessor 与 postProcessBeanFactory:
两者都是IOC特意留下来为了拓展功能而做的,但是BeanPostProcessor是在bean的创建之前或者之后执行一些开发着想要执行的功能,可以定义多个BeanPostProcessor,并根据order建立优先级(0为最高);而postProcessBeanFactory则是通过beanfactory可以获取到bean的定义信息,并且可以修改

public void refresh() throws BeansException, IllegalStateException {
        Object var1 = this.startupShutdownMonitor;
        synchronized(this.startupShutdownMonitor) {
        //为刷新做准备工作,如日志,将原本的内容存储到一个hashset里面
            this.prepareRefresh();
            //刷新beanFactory
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            //顾名思义,进行准备创建前的准备工作,
            //如各种依赖,添加BeanPostProcessor(通过order设置优先级0为最高)这种拓展IOC功能的方法,获取类加载器等等
            this.prepareBeanFactory(beanFactory);

            try {
            //这里有一个postProcessBeanFactory与上面的BeanPostProcessor略有不同
                this.postProcessBeanFactory(beanFactory);
                this.invokeBeanFactoryPostProcessors(beanFactory);
                this.registerBeanPostProcessors(beanFactory);
                this.initMessageSource();
                this.initApplicationEventMulticaster();
                this.onRefresh();
                this.registerListeners();
                this.finishBeanFactoryInitialization(beanFactory);
                this.finishRefresh();
            } catch (BeansException var9) {
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
                }

                this.destroyBeans();
                this.cancelRefresh(var9);
                throw var9;
            } finally {
                this.resetCommonCaches();
            }

        }
    }

4、再好好看看ClassPathXmlApplicationContext 的生成树
这个就你们自己去找了,这图可能不清晰


Spring IOC源码分析
5、spring bean的生命周期

相关文章: