Spring入门(1)—— ioc原理与源码

Spring介绍

什么是spring

参考百度百科:https://baike.baidu.com/item/spring/85061

Spring框架是一个开放源代码的J2EE应用程序框架,由Rod Johnson发起,是针对bean的生命周期进行管理的轻量级容器(lightweight container)。 Spring解决了开发者在J2EE开发中遇到的许多常见的问题,提供了功能强大IOC、AOP及Web MVC等功能。Spring可以单独应用于构筑应用程序,也可以和Struts、Webwork、Tapestry等众多Web框架组合使用,并且可以与 Swing等桌面应用程序AP组合。因此, Spring不仅仅能应用于JEE应用程序之中,也可以应用于桌面应用程序以及小应用程序之中。Spring框架主要由七部分组成,分别是 Spring Core、 Spring AOP、 Spring ORM、 Spring DAO、Spring Context、 Spring Web和 Spring Web MVC。

耦合和内聚介绍

耦合性(Coupling),也叫耦合度,是对模块间关联程度的度量。
在软件工程中,耦合指的就是就是对象之间的依赖性。对象之间的耦合越高,维护成本越高。因此对象的设计应使类和构件之间的耦合最小。软件设计中通常用耦合度和内聚度作为衡量模块独立程度的标准。划分模块的一个准则就是高内聚低耦合。

内聚标志一个模块内各个元素彼此结合的紧密程度,它是信息隐蔽和局部化概念的自然扩展。内聚是从功能角度来度量模块内的联系,一个好的内聚模块应当恰好做一件事。
内聚和耦合是密切相关的,同其他模块存在高耦合的模块意味着低内聚,而高内聚的模块意味着该模块同其他模块之间是低耦合。在进行软件设计时,应力争做到高内聚,低耦合

Spring体系结构

Spring核心概念介绍

IoC(核心中的核心):Inverse of Control,控制反转。对象的创建权力由程序反转给Spring框架。
AOP:Aspect Oriented Programming,面向切面编程。在不修改目标对象的源代码情况下,增强IoC容器中Bean的功能。
DI:Dependency Injection,依赖注入。在Spring框架负责创建Bean对象时,动态的将依赖对象注入到Bean组件中!
Spring容器:指的就是IoC容器。


Spring IoC

1. 什么是IoC容器

所谓的IoC容器就是指的Spring中Bean工厂里面的Map存储结构(存储了Bean的实例)。

2. Spring框架中的工厂有哪些

ApplicationContext接口
实现ApplicationContext接口的工厂,可以获取到容器中具体的Bean对象

BeanFactory工厂(是Spring框架早期的创建Bean对象的工厂接口)
实现BeanFactory接口的工厂也可以获取到Bean对象

其实通过源码分析,不管是BeanFactory还是ApplicationContext,其实最终的底层BeanFactory都是DefaultListableBeanFactory

3. ApplicationContext和BeanFactory的区别

创建Bean对象的时机不同:

BeanFactory采取延迟加载,第一次getBean时才会初始化Bean。

ApplicationContext是加载完applicationContext.xml时,就创建具体的Bean对象的实例。(只对BeanDefition中描述为是单例的bean,才进行饿汉式加载

 

如何创建Web环境中的IoC容器

1. ApplicationContext接口常用实现类

ClassPathXmlApplicationContext

       它是从类的根路径下加载配置文件,推荐使用这种。

FileSystemXmlApplicationContext

       它是从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置。

AnnotationConfigApplicationContext:

       当我们使用注解配置容器对象时,需要使用此类来创建 spring 容器。它用来读取注解。

2. Java应用中创建IoC容器

ApplicationContext context = new ClassPathXmlApplicationContext(xml路径);

3.  Web应用中创建IoC容器:(重点)

web.xml中配置ContextLoaderListener接口,并配置ContextConfigLocation参数

web容器启动之后加载web.xml,此时加载ContextLoaderListener监听器(实现了ServletContextListener接口,该接口的描述请见下面《三类八种监听器》)

ContextLoaderListener监听器会在web容器启动的时候,触发contextInitialized()方法。

contextInitialized()方法会调用initWebApplicationContext()方法,该方法负责创建Spring容器(DefaultListableBeanFactory)。
 

【Web三类八种监听器】:
***监听域对象的生命周期:
    *ServletContextListener:
        *创建:服务器启动
        *销毁:服务器正常关闭
        *spring ContextLoaderListener(服务器启动时负责加载Spring配置文件)
    *HttpSessionListener
        *创建:第一次访问request.getHttpSession();
        *销毁:调用invalidate();非法关闭;过期
    *ServletRequestListener
        *创建:每一次访问
        *销毁:响应结束
***监听域对象的属性:(添加、删除、替换)
    * ServletContextAttributeListener
    * HttpSessionAttributeListener
    * ServletRequestAttributeListener
***监听HttpSession中JavaBean的改变:
    * HttpSessionBindingListener(HttpSession和JavaBean对象的绑定和解绑)
    * HttpSessionActivationListener(HttpSession的序列化,活化、钝化)

4. 创建spring IoC容器源码分析

web服务器(tomcat)启动会加载web.xml(启动ContextLoaderListener监听器)

 

调用ContextLoaderListener类的contextInitialized方法,创建Web环境中的Spring上下文对象

调用ContextLoader类的initWebApplicationContext方法 -- 初始化spring中的web容器

继续调用ContextLoader类的configureAndRefreshWebApplicationContext方法,该方法中调用最终初始化Bean的refresh方法。

spring容器真正初始化的方法就是refresh方法,不管是web环境还是java环境都是这个方法

创建Spring容器图示

spring容器初始化源码分析

主流程

1. 入口

ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");

2. ClassPathXmlApplicationContext中,重载构造方法会进入下面的方法,而后进入refresh方法

3. AbstractApplicationContext的refresh方法:初始化spring容器的核心代码

@Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // 1、Prepare this context for refreshing.
            prepareRefresh();

            //创建DefaultListableBeanFactory(真正生产和管理bean的容器)
            //加载BeanDefition并注册到BeanDefitionRegistry
            //通过NamespaceHandler解析自定义标签的功能(比如:context标签、aop标签、tx标签)
            //2、Tell the subclass to refresh the internal bean factory.
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            //3、 Prepare the bean factory for use in this context.
            prepareBeanFactory(beanFactory);

            try {
                //4、 Allows post-processing of the bean factory in context subclasses.
                postProcessBeanFactory(beanFactory);

                //实例化并调用实现了BeanFactoryPostProcessor接口的Bean
                //比如:PropertyPlaceHolderConfigurer(context:property-placeholer)
                //就是此处被调用的,作用是替换掉BeanDefinition中的占位符(${})中的内容
                //5、 Invoke factory processors registered as beans in the context.
                invokeBeanFactoryPostProcessors(beanFactory);

                //创建并注册BeanPostProcessor到BeanFactory中(Bean的后置处理器)
                //比如:AutowiredAnnotationBeanPostProcessor(实现@Autowired注解功能)
                //      RequiredAnnotationBeanPostProcessor(实现@d注解功能)
                //这些注册的BeanPostProcessor
                //6、 Register bean processors that intercept bean creation.
                registerBeanPostProcessors(beanFactory);

                //7、 Initialize message source for this context.
                initMessageSource();

                //8、 Initialize event multicaster for this context.
                initApplicationEventMulticaster();

                //9、 Initialize other special beans in specific context subclasses.
                onRefresh();

                //10、 Check for listener beans and register them.
                registerListeners();

                //创建非懒加载方式的单例Bean实例(未设置属性)
                //填充属性
                //初始化实例(比如调用init-method方法)
                //调用BeanPostProcessor(后置处理器)对实例bean进行后置处理
                //11、 Instantiate all remaining (non-lazy-init) singletons.
                finishBeanFactoryInitialization(beanFactory);

                //12、 Last step: publish corresponding event.
                finishRefresh();
            }

            catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                }

                // Destroy already created singletons to avoid dangling resources.
                destroyBeans();

                // Reset 'active' flag.
                cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            }

            finally {
                // Reset common introspection caches in Spring's core, since we
                // might not ever need metadata for singleton beans anymore...
                resetCommonCaches();
            }
        }
    }

图示:

创建BeanFactory流程分析

获取BeanFactory的子流程

1. 入口

主流程的第二步的obtainFreshBeanFactory()方法

//2、Tell the subclass to refresh the internal bean factory.
 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

2. 进入AbstractApplicationContext类,调用refreshBeanFactory方法

3. 进入AbstractRefreshableApplicationContext类,调用createBeanFactory方法

加载解析BeanDefinition的子流程(loadDefinitions方法)

1. 入口

上图中第3步的AbstractRefreshableApplicationContext类的refreshBeanFactory方法中:loadBeanDefinitions方法

此处依次调用多个类的loadBeanDefinitions方法(AbstractXmlApplicationContext -> AbstractBeanDefinitionReader -> XmlBeanDefinitionReader),一直调用到XmlBeanDefinitionReader 类的doLoadBeanDefinitions方法

2. 进入AbstractXmlApplicationContext,调用loadBeanDefinitions方法

继续调用 loadBeanDefinitions方法 

3. 进入AbstractBeanDefinitionReader,调用loadBeanDefinitions

4. 进入XmlBeanDefinitionReader,调用loadBeanDefinitions

找到doLoadBeanDefinitions方法

5.  对于doLoadDocument方法不是我们关注的重点,我们进入到该类的registerBeanDefinitions方法看看

6. 此处有两个地方是我们关注的:一个createRederContext方法,一个是DefaultBeanDefinitionDocumentReader类的registerBeanDefinitions方法,先进入createRederContext方法看看

至此,14个NamespaceHandlerResolver初始化成功。

7. 然后回到第5步,进入DefaultBeanDefinitionDocumentReader类的registerBeanDefinitions方法

8. 继续进入到该类的doRegisterBeanDefinitions方法,这是真正干活的方法

9. 继续进入到该类的parseBeanDefinitions方法

10. 两种解析方案,先看parseDefaultElement方法

重点看BeanDefinitionParserDelegate类的parseCustomElement方法

(AOP标签、tx标签的解析都是在该步骤中完成的)

11. 进入DefaultNamespaceHandlerResolver类的resolve方法

12. namespaceHandler.init();这个方法是很重要。

它实现了自定义标签到处理类的注册工作,不过NamespaceHandler是一个接口,具体的init方法需要不同的实现类进行实现。

我们通过AopNamespaceHandler了解一下init的作用,其中aop:config标签是由ConfigBeanDefinitionParser类进行处理:

13. 至此,我们了解到了xml中的aop标签都是由哪些类进行处理的了。不过init方法只是注册了标签和处理类的对应关系,那么什么时候调用处理类进行解析的呢?

我们再回到BeanDefinitionParserDelegate类的parseCustomElement方法,找到最后一行的parse方法

14. 我们看到,最后一行执行了parse方法,那么parse方法,在哪呢?

我们需要到NamespaceHandlerSupport类中去看看,它是实现NamespaceHandler接口的,并且AopNamespaceHandler是继承了NamespaceHandlerSupport类,那么该方法也会继承到AopNamespaceHandler类中。

至此,整个XML文档的解析工作,包括bean标签以及自定义标签如何解析为BeanDefinition信息的过程,我们已经了解了。

后续具体想了解哪个自定义标签的处理逻辑,可以自行去查找xxxNamespaceHandler类进行分析。

图示


创建Bean流程分析

1. 子流程入口

主流程第11步,即AbstractApplicationContext类的refresh方法

//创建非懒加载方式的单例Bean实例(未设置属性)
//填充属性
//初始化实例(比如调用init-method方法)
//调用BeanPostProcessor(后置处理器)对实例bean进行后置处理

//11、 Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);

2. 进入此类的finishBeanFactoryInitialization方法,在最后一行找到preInstantiateSingletons方法

3. 进入DefaultListableBeanFactory类的preInstantiateSingletons方法

4. 继续跟踪下去,我们进入到了AbstractBeanFactory类的doGetBean方法,找到核心方法

5. 进入到AbstractAutowireCapableBeanFactory类的createBean方法

6. 进入此类的doCreateBean方法,有两个关注点

7. 看看initializeBean方法是如何调用BeanPostProcessor的,因为这个牵扯到我们对于AOP动态代理的理解

至此,如何创建Bean,以及AOP在哪产生代理的步骤,已经分析

 

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值