Spring笔记

启动流程

  • Tomcat运行时会去读取web.xml文件,web.xml文件中引用了Spring,SpringMVC核心两大类(ContextLoaderListener,DispatcherServlet)
  • 初始化上下文(ContextLoaderListener的contextInitialized—>ContextLoader.initWebApplicationContext)
  • 创建ApplicationContext
  • 创建ConfigurableWebApplicationContext,ApplicationContext属性setter.
  • 实例化ApplicationContext属性
  • BeanFactory IOC容器构建
  • Bean载入

//ContextLoader
/**
 *  初始化上下文
 * */
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
          .......
               //创建ApplicationContext引用
               this.context = this.createWebApplicationContext(servletContext);

                if (this.context instanceof ConfigurableWebApplicationContext) {
                    ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext)this.context;
                    if (!cwac.isActive()) {
                        if (cwac.getParent() == null) {
                            ApplicationContext parent = this.loadParentContext(servletContext);
                            cwac.setParent(parent);
                        }
                        //初始化ApplicationContext、国际化,Bean加载。(此刻就进入了SpringBean初始化流程)
                        this.configureAndRefreshWebApplicationContext(cwac, servletContext);
                    }
                }

                servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
                ClassLoader ccl = Thread.currentThread().getContextClassLoader();
                if (ccl == ContextLoader.class.getClassLoader()) {
                    currentContext = this.context;
                } else if (ccl != null) {
                    currentContextPerThread.put(ccl, this.context);
                }
                ......
                return this.context;
                ......
}

/***
 * 初始化ApplicationContext
 * */
 protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
        String configLocationParam;
        configLocationParam = sc.getInitParameter("contextId");
        wac.setId(configLocationParam);
        wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + ObjectUtils.getDisplayString(sc.getContextPath()));
        //上下文切换,可以说是ConfigurableWebApplicationContext对ServletContext进行属性添加。
        //不在ServletContext添加代码
        wac.setServletContext(sc);
        //此处获取到xml中的contextConfigLocation配置对象,
        configLocationParam = sc.getInitParameter("contextConfigLocation");
        if (configLocationParam != null) {
            wac.setConfigLocation(configLocationParam);
        }

        ConfigurableEnvironment env = wac.getEnvironment();
        if (env instanceof ConfigurableWebEnvironment) {
            ((ConfigurableWebEnvironment)env).initPropertySources(sc, (ServletConfig)null);
        }

        this.customizeContext(sc, wac);
        
        //Spring bean 初始化
        wac.refresh();  // ---->ConfigurableApplicationContext.refresh ---->AbstractApplicationContext.refresh
    }
    

//AbstractApplicationContext
public void refresh() throws BeansException, IllegalStateException {
         .....
                //BeanDefinition(IOC容器创建,Springbean加载)
                ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
                //允许在上下文的子类中对bean factory进行后处理
                this.postProcessBeanFactory(beanFactory);
                //调用bean factory 后置方法
                this.invokeBeanFactoryPostProcessors(beanFactory);
                //注册BeanPostProcessor
                this.registerBeanPostProcessors(beanFactory);
                //初始国际化文件 i18n
                this.initMessageSource();
                // 初始化事件监听多路广播器
                this.initApplicationEventMulticaster();
                // 模板方法而已,可以根据不同的spring容器做不同的事情
                //比如web程序的容器ServletWebServerApplicationContext中会调用createWebServer方法去创建内置的Servlet容器。
                this.onRefresh();
                //注册监听器
                this.registerListeners();
                //初始化所有的单例bean
                this.finishBeanFactoryInitialization(beanFactory);
                //刷新完成工作
                this.finishRefresh();
          ....
          
    /**
     *  bean工厂初始化
     * */
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
        .......
        beanFactory.setTempClassLoader((ClassLoader)null);
        beanFactory.freezeConfiguration();
        //预实例化所有非懒加载单例Bean  传说中的spring bean 循环依赖问题,spring bean加载 
        //就是在此处。下方有专门介绍
        beanFactory.preInstantiateSingletons();
        //---->ConfigurableListableBeanFactory.preInstantiateSingletons
        //---->DefaultListableBeanFactory.preInstantiateSingletons
    }
    
    
  protected final void refreshBeanFactory() throws BeansException {
    //如果已经有了Bean工厂,直接摧毁重建
        if (this.hasBeanFactory()) {
            this.destroyBeans();
            this.closeBeanFactory();
        }

        try {
            //DefauliListableBeanFactory 就是IOC容器
            DefaultListableBeanFactory beanFactory = this.createBeanFactory();
            beanFactory.setSerializationId(this.getId());
            this.customizeBeanFactory(beanFactory);
            //用IOC容器构建Bean。Bean的初始化流程就在这里,核心之核弹级重点。
            //该方法有支持XML读取,注解形式读取Bean。核心就是根据path遍历读取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
  public void preInstantiateSingletons() throws BeansException {
        

        while(true) {
            while(true) {
                String beanName;
                RootBeanDefinition bd;
                do {
                    do {
                        do {
                            .......
                            }
                            beanName = (String)var2.next();
                            bd = this.getMergedLocalBeanDefinition(beanName);
                        } while(bd.isAbstract()); //是否是抽象
                    } while(!bd.isSingleton()); //是否是单例模式
                } while(bd.isLazyInit()); //是否是懒加载
                //如果同时满足以上条件,则会进行实例化操作
                if (this.isFactoryBean(beanName)) {
                  //判断bean是否实现了 FactoryBean接口,实现了进行一 次&前缀初始化,一次本类实例化 isFactoryBean(beanName)
                  //大多数普通类直接调用 getBean(beanName);
                    final FactoryBean<?> factory = (FactoryBean)this.getBean("&" + beanName);
                    boolean isEagerInit;
                    if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                        isEagerInit = (Boolean)AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
                            public Boolean run() {
                                return ((SmartFactoryBean)factory).isEagerInit();
                            }
                        }, this.getAccessControlContext());
                    } else {
                        isEagerInit = factory instanceof SmartFactoryBean && ((SmartFactoryBean)factory).isEagerInit();
                    }

                    if (isEagerInit) {
                        this.getBean(beanName);
                    }
                } else {
                    this.getBean(beanName); //--->AbstractBeanFactory.getBean.doGetBean
                }
            }
        }
    }

//AbstractBeanFactory
protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
        String beanName = this.transformedBeanName(name);
        //尝试性从缓存中获取bean对象
        Object sharedInstance = this.getSingleton(beanName);
        Object bean;
        
     
        if (sharedInstance != null && args == null) {
            if (this.logger.isTraceEnabled()) {
                if (this.isSingletonCurrentlyInCreation(beanName)) {
                    this.logger.trace("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference");
                } else {
                    this.logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
                }
            }
      
            bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
        } else {
          
           //查看当前的bean是否在创建中并且是prototype作用域
           // 如果是创建中,此处又引用到了bean,着是判定为循环引用
            if (this.isPrototypeCurrentlyInCreation(beanName)) {
                throw new BeanCurrentlyInCreationException(beanName);
            }

             ........
            
              //这里也比较重要,这里涉及到当前创建的bean是什么作用域的
                //单例模式
                if (mbd.isSingleton()) {
                  //创建bean。能走到这里来,就说明当前操作的bean没有在三级缓存之中!
           
                    //原型模式
                } else if (mbd.isPrototype()) {
                   
                } else {
                  //如果既不是单例Bean,也不是原型,则获取其Scope
                    String scopeName = mbd.getScope();
                }
            } 


三级缓存源码

DefaultSingletonBeanRegistry

    /**
     * 此方法只是尝试性的从缓存获取。
     * */
  @Nullable
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        /**  从一级缓存找,是否有实例化好的Bean对象   **/
        Object singletonObject = this.singletonObjects.get(beanName);
        /** 如果一级缓存找不到**/
        if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
          /** 从二级缓存找,是否有提前曝光的Bean对象引用  **/
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
                synchronized(this.singletonObjects) {
                    singletonObject = this.singletonObjects.get(beanName);
                    if (singletonObject == null) {
                        singletonObject = this.earlySingletonObjects.get(beanName);
                        if (singletonObject == null) {
                          /** 从三级缓存找,找到Bean对象的工厂。然后进行构建对象,存放到二级缓存。在删掉三级缓存 **/
                            ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
                            if (singletonFactory != null) {
                                singletonObject = singletonFactory.getObject();
                                this.earlySingletonObjects.put(beanName, singletonObject);
                                this.singletonFactories.remove(beanName);
                            }
                        }
                    }
                }
            }
        }
        return singletonObject;
    }
    
    /**
     * 如果在缓存中获取不到,则会调用该方法,进行创建bean
     * */
    public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
       .....
        synchronized(this.singletonObjects) {
                ......
                //便于对循环依赖进行检测的,可能由于创建的时候没有暴露出来对象
                this.beforeSingletonCreation(beanName);
                ......
                try {
                    //创建单例bean对象.Bean的生命周期以及依赖注入添加到三级缓存的真正入口。非常庞大设计
                    // 下面单独写出
                    singletonObject = singletonFactory.getObject();
                    .......
                    //
                    this.afterSingletonCreation(beanName);
                }

                ......
            }

            return singletonObject;
        }
    }



五种作用域

  • singleton:单例模式,当spring创建applicationContext容器的时候,spring会欲初始化所有的该作用域实例,加上lazy-init就可以避免预处理;

  • prototype:原型模式,每次通过getBean获取该bean就会新产生一个实例,创建后spring将不再对其管理;


  • request:搞web的大家都应该明白request的域了吧,就是每次请求都新产生一个实例,和prototype不同就是创建后,接下来的管理,spring依然在监听

  • session:每次会话,同上

  • global session:全局的web域,类似于servlet中的application

Spring 默认的Bean是为单例模式。在spring开发中,本身就是线程不安全的,但线程执行的方法隔绝了数据共享。如果在全局引用变量,则会引发并发问题。


BeanFactory 与 FactoryBean

  • BeanFactory是Spring IOC 容器接口基本定义。
  • FactoryBean是Spring 对 Bean创建自定义处理的类。本身就是一个工厂和装饰。主要还是为了解决XML bean配置的繁琐问题。

Spring中运用到的设计模式

  • BeanFactory工厂模式
    • Spring启动时,加载Class文件转换成Bean元素,Bean元素在转换成BeanDefinition对象。通过不同的BeanName能获取到Ioc不同的实例对象。经典的工厂模式
  • getSingleton单列模式
    • Spring在获取Bean的时候,会去三级缓存中寻找Bean。并且加了双重锁,双重判断的单例模式
  • SpringMVC中的HandlerAdatper 适配器
  • AOP代理模式
    • 动态代理在内存中构建,不需要额外的去创建代理类
  • 模板设计
    • 在Spring中,很多父类定义了抽象方法,子类在集成中都用得到,并且可以通过模板设计控制父类的方法元素。
    • Map也有这个设计,Map定义了模板方法,HashMap进行了实现,LinkedHashMap 实现HashMap,用钩子方法控制HashMap的属性

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值