导航:首页 > 源码编译 > context源码大全

context源码大全

发布时间:2023-02-03 09:27:27

1. Spring源码9. refreshContext()刷新应用上下文

上一篇 prepareContext()准备应用上下文 中分析了spring容器的准备, 共计执行了如下8步:

准备刷新, 执行了两步:

清空CachingMetadataReaderFactory中的缓存

设置刷新开始事件, 设置closed为false, active为true, 标记容器处于active状态

AbstractApplicationContext中定义了模板方法, refreshBeanFactory和getBeanFactory调用的是GenericApplicationContext中实现的方法

更新this.refreshed字段为true, 表示已经更新了, 然后beanFactory设置serializationId, 最后返回beanFactory

beanFactory是GenericApplicationContext中DefaultListableBeanFactory类型的成员变量, 设置beanFactory, 一共执行了

后续处理各个beanFactory, 当前applicationContext是的实例, postProcessBeanFactory执行了三步

进行了两个操作, 首先添加了一个的Aware Bean处理器, ServletContextAware的子类Bean在实例化过程中, 会被注入servletContext和servletConfig对象, 然后beanFactory中注册了request和session两个scopes, 注册了几个Autowired依赖类

注册了request, session两个scope, 然后注册ServletRequest, ServletResponse, HttpSession, WebRequest

BeanFactoryPostProcessor是一个接口, 处理beanFactory中所有的bean, 在所有的beanDefinition加载完成之后, BeanFactoryPostProcessor可以对beanDefinition进行属性的修改, 之后再进行bean实例化

是BeanFactoryPostProcessor的子接口, 定义了方法, 会在postProcessBeanFactory方法执行之前, 获取bean定义, 并注册到spring容器中

如果beanFactory是BeanDefinitionRegistry的子类, 按优先级处理类型的后置处理器, 最后处理传入的其他类型后置处理器, 处理流程如下:

如果beanFactory不是BeanDefinitionRegistry的子类, 那么直接遍历传入的传入的beanFactoryPostProcessors, 调用元素的postProcessBeanFactory方法

最后处理beanFactory中注册的其他类型的BeanFactoryPostProcessor, 获取bean名称, 维护到postProcessorNames列表中, 之后的处理步骤如下:

处理了@Configuration注解, 扫描项目中的BeanDefinition, 这篇文章 详细剖析了的源码

BeanPostProcessor是一个接口, Bean后置处理器, 在bean实例化, 之前执行方法, 在bean实例化之后执行方法, 实现了对bean实例的增强

beanFactory中获取BeanPostProcessor类型的bean名称, 维护到postProcessorNames数组中, 将BeanPostProcessor列表分为四类:

beanFactory先添加一个BeanPostProcessorChecker类型的BeanPostProcessor, 然后在将各类PostProcessors列表排序, 分别添加到beanFactory的beanPostProcessor列表中, 最后再添加一个ApplicationListenerDetector

先判断容器beanFactory中是否包含messageSource bean定义, 存在的话, 直接获取bean, 如果不存在的话, 那么手工注册一个messageSource单例bean, 然后赋值给this.messageSource

先判断容器beanFactory中是否有applicationEventMulticaster bean定义, 存在的话, 获取bean实例, 不存在的话, 实例化一个, 手工注册一个单例bean, 然后赋值给this.applicationEventMulticaster

AbstractApplicationContext没有实现该方法, 用于通知子类刷新容器

调用父类GenericWebApplicationContext#onRefresh方法, 然后创建webServer, 之后调用父类GenericWebApplicationContext#initPropertySources方法, 将servletContext维护到environment的servletContextInitParams属性中

初始化主题, 可以让页面显示不同的样式

首先将硬编码的ApplicationListener先添加this.applicationEventMulticaster.defaultRetriever.applicationListeners中, 然后将注入的listener bean维护到this.applicationEventMulticaster.defaultRetriever.applicationListenerBeans, 最后处理earlyEvent

beanFactory.preInstantiateSingletons() 源码剖析

什么都没有做

打印@Condition注解评估日志

2. 【原创】react-源码解析 - forward-ref&context(4)

通常我们会通过ref去获取Dom节点的实例,或者ClassComponent的实例,但是,如果我么们的组件是一个function类型的component,由于functionComponent是没有实例的所以我们在使用的时候也相应的取不到改组件的this,当然ref也一样。这时react为我们提供了一个forwardRef方法:

          通过这种方式创建的函数类型的组件,使我们能够在函数中继续使用ref属性,当然我们在实际的应用的中也不会傻到去取函数类型组件的ref,因为我们知道它是没有实例的。但是,当我们在使用其他库提供的组件的时候,我们可能并不知道这个这个组件的类型,这时如果能够合理的使用这个方法将会为我们省去不必要的麻烦,同时这里也有HOC的思想在里面。接收一个组件,返回对原组件进行包装的新的组件。接下来我们去看看方法的源码: forwardRef 源码很简单,改方法返回了一个Oject具有render属性,同时$$typeof为"react.forward_ref"的Symbol值。

        这里可能存在对于type属性的概念混淆。我们一定不能认为使用forward创建出的组件的$$typeof属性为:'react.forward_ref'。我们使用forwardRef创建的组建的额时候,实际是将上面例子中的TargetCom作为参数传入到CreateElement方法中的,实际返回的element中的$$typeof还是REACT_ELEMENT_TYPE, 也就是说这里我们将TargetCom{创建出的对象--具有render和$$typeof属性}传入,其中CreateElement的type属性为forward方法返回的那个对象,也就是说在type对象里面有个叫做$$typeof的属性这个属性的键值为:'react.forward_ref',

在后安的渲染过程中有很多判断,其中有一些就是更具$$typeof展开的,这里我们一定要搞清楚凡是通过CreateElement创建的组件的$$typeof属性都为: 'REACT_ELEMENT_TYPE'。

        这里我们还是按照惯例对api进行一下简单的说明,我们知道在react中是通过props属性来实现组件间通信的,这种通信方式存在的问题在于,虽然父子组件之间通信很方便但是当我们的组件嵌套层级很深,这时候如果使用props传参就不太现实了,首先中间层的组件不一定是你自己写的其次中间层组件声明的props对于这些组件本身没有任何意义,这个时候我们就需要使用context方法帮助我们实现多级组件之间的通信。我们在顶层组件中提供了context对象之后,所有的后代组件都可以访问这个对象。以此达到跨越多层组件传递参数的功能。在react当前版本中有两种实现context的方式:

(1)ParentComponent.childContextTypes{} == {不推荐,下个大版本会废弃}

(2)const { Provider, Consumer } = React.createContext('default');

在使用childContextTypes时候我们需要在父级组件中声明一个getChildContext的方法,该方法返回一个对象,这个对象就是我们需要传给后代组件的context对象。当我们在使用第一种方法的时候我们需要在组件上声明context对象中属性的类型,有些类似于react的PropTypes类型检测。同时需要在使用到context的后代组件中声明contextTypes类似于下面这种写法:

如果不这样声明的话,在后代组价中是取不到context对象的。这里我们需要注意的是我们在子组件中使用context的时候,需要哪个属性就必须去contextTypes中声明,因为改组件的上级组件不止一个上级组件中的context也不止一个。而createContext方法的使用就简化了很多,首先我们看到改方法返回两个对象Provider, Consumer分别为context的提供方和订阅方:

在上层组件中声明之后,在想用到context的后代组件中国使用Consumer包括起来就可以访问到之前声明的context: ReactContext

从源码中我们可以看到CreateContext方法创建了一个对象改对象有一个_currenValue属性记录context的变化,这个对象Provider属性中声明context,然后使改对象的Consumer属性指向对象本身,我们在使用Consumer的时候就直接从context的currenValue上去取值。以上就是react中的Createcontext方法的实现原理,当然实际过程并没有这么简单,至于具体的实现我们接着往下看。同时这里我们也需要注意该对象下的$$typeof属性并不是用来替换ReactElement中的$$typeof, 与我们之前将到的forwardRef中声明的$$typeof一样都只是我们传入CreateElement方法中type属性上的内容。

了解更多: react-source-code

3. Spring源码6:createApplicationContext()实例

上一篇 printBanner()打印Banner 中非了springboot如何打印Banner

在 初始化SpringApplication实例 中, 已经分析了当前模块web类型为SERVLET, 所以当前实例化了一个对象

由上面类图,我们可以看出, 类继承关系如下:

用来加载Resource, 初始化的过程中, 实例化了ClassLoader,

抽象ApplicationContext, 定义了ApplicationContext一些模板方法, 在实例化的过程中, 调用了getResourcePatternResolver()方法, 构造了一个, 规定了如何查找资源, 例如从classpath, 根路径, 从war包等查找资源

初始化了一个DefaultListableBeanFactory

由上面类图, 我们可以看出DefaultListableBeanFactory的继承关系:

提供了bean别名的增删改查功能

默认的单例Bean注册器, 提供了单例bean增删改查等功能

提供了FactoryBean的增删改查方法

抽象BeanFactory, 定义了通用的beanFactory的模板方法, 添加了对beanFactory对Scope的支持, scope主要有五种, singleton, prototype, request, session和application,

抽象自动配置BeanFactory, 实现了创建Bean, 实例化Bean, 字段配置Bean, 自动装配依赖Bean的方法

BeanFactory默认实现, spring IOC默认容器类

重写了AbstractApplicationContext的getResourcePatternResolver()方法, 返回一个对象, 构造函数中显示调用父类GenericApplicationContext的构造函数

隐式调用父类GenericWebApplicationContext构造函数, 什么都没有做

首先, 初始化一个AnnotatedBeanDefinitionReader, 然后再实例化一个对象

用于读取和解析bean定义

注解bean名称生成器, 用于生成Bean名称

Scope注解的解析器, 解析出Scope的模式ScopedProxyMode, 以及Scope的名称

@Conditional注解的条件评估器, 评估是否满足条件

注册bean处理器, bean名称需要加上org.springframework.context.annotation前缀:

如果basePackages不为空的话, 扫描basePackages中定义的bean, 当前应用中没有配置basePackages, 所以不会去扫描bean

实例化过程中, 会先调用父类GenericApplicationContext构造函数, 实例化了一个DefaultListableBeanFactory, 作为Spring IOC容器, 的构造函数实例化了AnnotatedBeanDefinitionReader对象, 用于读取Spring的bean定义, 在实例化AnnotatedBeanDefinitionReader的过程中, 注册了几个bean, 用来处理相应的注解

我们将会在下一篇 SpringBootExceptionReporter异常上报 , 继续阅读springboot源码

4. Netty源码_ChannelPipeline和ChannelHandlerContext详解

ChannelPipeline 相当于 ChannelHandler 的集合,用于处理或拦截 Channel 的入站事件和出站操作。

这里就有两个问题:

ChannelPipeline 管理 ChannelHandler 集合,是利用 ChannelHandler 创建一个上下文对象 ChannelHandlerContext , 而 ChannelPipeline 存储的就是这个上下文对象。
这个 ChannelHandlerContext 对象下一节将重点讲解。

ChannelPipeline 管理的 ChannelHandler 集合处理 I/O 事件的流程图如下:

可以看出 ChannelPipeline 将管理的 ChannelHandler 分为两种:

不要看 ChannelPipeline 方法很多,其实主要分为两类:

你会发现每个添加方法都有多一个 EventExecutorGroup 参数的对应方法,它作用是什么呢?

在 ChannelPipeline 实现中:

你会发现 ChannelPipeline 的主要功能就两个:

上下文 ChannelHandlerContext 接口与 ChannelPipeline 联系非常大

ChannelHandlerContext 接口的重要作用:

ChannelHandlerContext 的功能大概分为两类:

5. Gin 的启动过程、路由及上下文源码解读

Engine 是 gin 框架的一个实例,它包含了多路复用器、中间件和配置中心。

gin 通过 Engine.Run(addr ...string) 来启动服务,最终调用的是 http.ListenAndServe(address, engine) ,其中第二个参数应当是一个 Handler 接口的实现,即 engine 实现了此接口:

Engine.ServeHTTP() 会先初始化一个空的上下文,然后挂上请求 c.Reuqest = req ,随后执行 engine.handlerHTTPRequest(c) (包含主要处理逻辑的函数)。

以上就是正常处理一个请求的主要逻辑,其他的就现阶段来说先忽略了。

Engine 组合了 RouterGroup。

RouterGroup 实现了 IRouter 接口,IRouter 接口是 IRoutes 接口和 Group 函数组合而成。

RouterGroup 的结构体只有四个属性:

当新建 Engine 时,会初始化一个 RouterGroup 结构,RouterGroup 是组合在 Engine 中的(所以 Engine 可以调用 RouterGroup 的所有方法),同时 Engine 的引用也记录在了 RouterGroup 上。

如上,RouterGroup 实现了 IRouter 接口,下面是一些方法的实现。

gin 通过上方 RouterGroup 暴露的几个方法添加路由,底层使用的方法是 Engine.addRoute(method, path string, handlers HandlerChain) 。

Engine.trees 属性是存储所有路由信息的总入口。它是一个切片,其中每个元素对应一种 method 并且是一个多叉树的根节点。

当 addRoute 时,先根据 method 找到对应的 tree (Engine.trees[i])。然后会比较 加入者 的 path 和 node 中的 path 相似的部分, 相似的部分 作为 父结点,不同的部分作为 子结点。以 多叉树 的方式存储下来。

这里会把 URL 中的路由变量也当作字符串存入树中,因为相同 URL 他们的变量也是一样的。

当请求进来时,因为 Engine 实现了 Handler 接口,所以最后会调用到 Engine.ServeHTTP 内。

找路径在

root.getValue() 比较复杂,这里就不多解释了。

[email protected] context.go

Context 中定义了一些属性和方法,用于扩展一些功能。

可以看到,这些方法主要用来获取 gin 自身 Context 的一些信息。

Context 中保存了所有 handlers 列表,存在 Context.handlers 数组中,并用下标 Context.index 标记当前执行的位置。
当主动取消调用链时,会将 index 设置成一个最大值 63( math.MaxInt8 / 2 ),也即调用链最大支持 64 个函数。
Context 中还提供了其他一些函数,当取消调用链的时候,可以设置请求返回的状态码和返回数据信息等。

Context 中的 httpWriter 整理一下。

gin 在 Context 中定义了错误信息字段 Context.Errors 切片,可以链式存储错误信息。

Go 原生的 Context 是通过 ValueContext 来存储元数据信息的,每个 ValueContext 只能存储一对信息,存储多个信息对需要将许多 ValueContext 组成链条,读写很不高效。
gin 的 Context 中存的元数据数据是存在 Context.Keys map[string]interface{} 属性中的,比起原生的 Context 使用起来会更高效。

是指用在 URL 路径中设置的参数,如 /user/:id 的 id 参数。
存储在 Context.Params 属性中,其本质是一个切片,每一个元素是一个 K/V 元组。
因此,在 URL 中是可以使用重复的变量名的(如 /test/:id/case/:id ),但获取值就需要自己从属性中获取了(如: c.Params[0] )。

Query 类是用在 URL 后的参数部分(如: ?id=1 )。

gin 通过 Context.queryCache 属性存储 query 参数,在调用获取 Query 参数时以懒加载的方式初始化: c.queryCache = c.Request.URL.Query() 。

需要注意的是它也支持传入 map 和 array,map 的传入需要像这样 ?m[k1]=v1&m[k2]=v2 ,array 的传入像这样 ?a=1&a=2 。

包含 PostForm、FormFile、MultipartForm 等。
先略

gin 为方便使用,通过绑定引擎设置了自动绑定用户输入和结构数据的方法。

这里包含设置状态码、设置响应头以及等信息。

只说一些值得注意的

这些方法除了 .Value() 方法外,其他都是返回的默认空值,略。

6. 源码分析->一个应用到底有几个Context

相信很多人都知道是这样计算的,那到底为什么是这样呢?

源码分析基于android28源码

什么是Context呢?可以理解为上下文、运行环境,当需要获取资源、系统服务以及启动Activity、Service用到,也可以通过它跟系统交互。

通过以下继承关系可以看出,Activity是继承ContextWrapper

ContextWrapper内部有一个Context类型的成员变量mBase

mBase是通过attachBaseContext()方法赋值

是创建Activity的关键,
主要工作
(1)createBaseContextForActivity()内部实例化ContextImpl 对象;
(2)mInstrumentation.newActivity()内部通过反射实例化Activity对象;
(3)activity.attach()内部会调用attachBaseContext()方法给mBase对象赋值;

通过以下继承关系可以看出,Application是继承ContextWrappe

是创建Application的关键,
主要工作:
(1)ContextImpl.createAppContext()实例化ContextImpl ;
(2)mActivityThread.mInstrumentation.newApplication(),内部通过反射实例化Application,并把appContext传递过去,通过attach()方法给mBase赋值;

跟Activity类似就不再做分析。
经过分析发现:
1.每个Activity,Service,Application都有一个ContextImpl 类型的成员变量mBase,ContextImpl是Context的实现类。
2.细心的读者可能发现,Activity,Service,Application都是继承Context,其实他们本身是一个Context,也都实现了Context的抽象方法,
那么一个Activity是否就拥有两个Context呢?
是不是

这样计算比较合适呢?

下面看下Context中常用的三个方法,

ContextImpl继承Context,并实现了这三个方法,

Activity间接继承Context,主要是在ContextWrapper实现了以上三个方法,从源码中可以看出,最终还是调用了ContextImpl的实现。

下图可以看出这几个的关系,ContextWrapper顾名思义就是Context的包装类(有ContextImpl的成员变量),并且实现了Context,这是一种装饰者设计模式。当在Activity中调用getAsset()时,其实最终是调用mBase的getAsset()。

Activity间接继承了Context,是为了拥有跟ContextImpl一样的功能,但真正起作用的是mBase这个成员变量,所以一个Activity其实就只有一个Context起作用,那就是ContextImpl类型的mBase。

这种计算方法应该是没有问题呢。
或许有人有这样的疑问,一个应用不是只有一个Application吗,为什么计算公式是加上Application个数?单进程应用来说,一个应用确实只有一个Application,而多进程应用,那么一个应用就有多个Application,所以应该说一个应用有一个或多个Application,一个进程有一个Application。

另外其他关于Context的常见面试题
1.Activity的this跟getBaseContext区别。
前者是Activity对象本身,后者是通过attachBaseContext传入的ContextImpl对象mBase,两者功能是一样的,通过this最终还是会调到mBase对象中。
2.getApplication和geApplicationContext区别。
两者都是返回Application对象,前者是Activity和Service里面的方法,后者是Context中定义的方法。
3.应用组件的构造,onCreate、attachBaseContext的执行顺序。
先是组件构造化,接着attachBaseContext,传入ContextImpl对象,最后是onCreate方法。
4.谈谈你对Context的理解
先是Context的作用,然后是有几种Context,Application、Service、Activity的Context有什么区别以及继承关系,
最后是mBase变量是如何实例化的。

以上分析有不对的地方,请指出,互相学习,谢谢哦!

7. Application中的 Context 和 Activity 中的Context区别

Context在我们开发中经常用到,不管是Framework提供给我们的四大组件,还是应用级别的Application,还是负责表现层的View相关类,甚至连我们很多时候创建的实体类都会需要持有一个Context的引用。那么Context到底是什么呢?

建议看这个: https://www.jianshu.com/p/b68de4c95b05

Context英文释义是当前上下文,或者当前场景上,
官方文档:Context

public abstractclass Context extends Object

Interface to globalinformation about an application environment. This is an abstract class whoseimplementation is provided by the Android system. It allows access toapplication-specific resources and classes, as well as up-calls forapplication-level operations such as launching activities, broadcasting andreceiving intents, etc.

由官方文档,我们可以知道:
1.该类是一个 抽象(abstract class)类
2.它描述的是一个应用程序环境的信息,即上下文;
3.通过它(Context)我们可以获取应用程序的资源和类,也包括一些应用级别的操作(例如,启动 Activity,广播和服务等);

前面我们讲过 Context 是一个抽象类,通过 Context我们可以获取应用程序的资源和类,调用它们的方法,那么具体定义的方法有哪些呢?我们来看一下 Context 的源码:

源码里的方法太多了,总共 4710 行。我们从以上部分源码看到了熟悉的对象---Application、Activity、Service、Broadcast、这些对象和 Context 的关系到底是什么呢?我们看一下官方文档可知:

1. Acitiivity 继承自ContextThemeWrapper--->再继承ContextWrapper--->Context。
2. Appliction 、Service继承自ContextWrapper--->再继承Context。
3. Application、Service 和 Activity 最终都是继承自Context,所以它们是同一个上下文。

通过以上的继承关系,我们就可以知道,Context的具体作用会包括:
- 启动一个新的Activity
- 启动和停止Service
- 发送广播消息(Intent)
- 注册广播消息(Intent)接收者
- 可以访问APK中各种资源,如Resources和AssetManager
- 创建View
- 访问Package的相关信息
- APK的各种权限管理

由上面分析的继承关系,我们可以知道,Context创建的时机有三个:

①创建Application 对象时, 而且整个App共一个Application对象;

②创建Service对象时;

③创建Activity对象时;

所以应用程序App共有的Context数目公式为:

Service个数 + Activity个数 + 1(Application对应的Context实例)

如上,Android中context可以作很多操作,但是最主要的功能是加载和访问资源。在android中常用的context有两种,一种是application context,一种是activity context,通常我们在各种类和方法间传递的是activity context。

两者的区别:

this 是Activity 的实例,扩展了Context,其生命周期是Activity 创建到销毁。getApplicationContext()返回应用的上下文,生命周期是整个应用,应用摧毁它才被摧毁。Activity.this的context 返回当前activity的上下文,属于activity ,activity摧毁时被摧毁。

使用Context时最需要注意的一个点就是,使用了不正确的context,比如有一个全局的数据操作类用到了context,这个时候就要getApplicationContext 而不是用ACtivity,如果在这个全局操作中引用的是Activity的context,那么就会一直引用Activity的资源,导致GC无法回收这部分内存,从而最终导致了 内存泄漏

内存泄漏是开发中常见的错误之一,能不能发现取决于开发者的经验,当然了我们也会依赖现有的内存泄漏库,但是如果我们在开发的源头减少内存泄漏的概率,那么后期的工作会少很多。

以下是避免context相关的内存泄露,给出的几点建议:

以下的表列举的是三种Context对象的对应使用场景:

从表中可以看到,和UI相关的都使用Activity的Context对象。

小结:如上分析,Context在对应开发里的来源就是三个——Activity、Service和Appliaction,那么我们该如何选择使用哪一个Context对象呢?一个比较简单的方法是,当你无法确定使用某个Context对象是否会造成长引用导致内存泄漏时,那么就使用Appliaction的Context对象,因为Appliaction存在于整个应用的生命周期内。

在实际开发中,我们往往会为项目定义一个Applictaion,然后在AndroidMainfest.xml文件中进行注册,

而且在自定义Application往往会定义好一个静态方法,用以全局获取application实例:

Activity和Application都是Context的子类,但是他们维护的生命周期不一样。前者维护一个Acitivity的生命周期,所以其对应的Context也只能访问该activity内的各种资源。后者则是维护一个Application的生命周期。

1.如何判断context是属于哪个activity?

2.全局不同如何获取对应的context?

静态加载一个Fragment,在onCreateView()方法中通过getActivity获取上下文实例:

3.四大组件可以像普通Java类一样,采用new的方式实例化吗?

Android程序不像Java程序一样,随便创建一个类,写个main()方法就能运行,Android应用模型是基于组件的应用设计模式,组件的运行要有一个完整的Android工程环境,在这个环境下,Activity、Service等系统组件才能够正常工作,而这些组件并不能采用普通的Java对象创建方式,new一下就能创建实例了,而是要有它们各自的上下文环境,也就是我们这里讨论的Context。可以这样讲,Context是维持Android程序中各组件能够正常工作的一个核心功能类。

8. Spring源码分析(一) XmlWebApplicationContext

spring是大家都会用的ioc框架,但是要真的了解spring还是需要好好研究一下才行,为此看了一些spring源码,所以开始写spring源码分析的文章,这个是第一篇,先从ioc容器的启动开始。
我们都知道,spring的ioc容器的最基本的接口就是BeanFactory,而ApplicationContext是包含了BeanFactory的所有信息,所以ioc容器在启动的时候就是从AbstractApplicationContext的refresh方法开始的

具体的启动流程就不说了,主要是这里有一个onRefresh方法,我们来看这个类,在这个类中覆写了onRefresh方法

这是什么东西?别急,我们来看看themeSource是什么。

还是不太明白?那我们来看看的结构

原来ThemeSource是一个接口,而则实现了这个接口,在onRefresh把自己传进去了,好吧,这块就先看到这里。
我们直接到XmlWebApplicationContext这个类里,我们发现类有一个方法loadBeanDefinitions,而XmlWebApplicationContext覆写了这个方法,我们来看看XmlWebApplicationContext是怎么实现的

这里我们要介绍ioc容器里的一个接口BeanDefinitionReader,而XmlBeanDefinitionReader是BeanDefinitionReader的一个实现类,负责对xml的配置文件进行读取,并放到ioc容器中。当读取完配置文件后,通过loadBeanDefinitions方法将bean注册到ioc容器中。

至此,ioc容器就启动完成。
XmlWebApplicationContext的分析就到这里了。

9. Context是什么

                                                                        Context

   Context,翻译是上下文环境,在android应用开发中的地位举足轻重,甚至源码也有一句话:everything needs a context(看到过,但是忘了在哪里了)。

从这个类图中我们看到,Context是一个抽象类,一边是Context的具体实现ContextImpl,一边则是组件的封装类ContextWrapper,便于二者各司其职,我理解是接口和实现分开,这样比较符合开闭原则吧。

  既然要搞清楚Context是干嘛的,得先看Context的实例什么时候创建的。这里有两个我们经常接触的组件,Activity和Service,以及用的较少的Application,它们的关系如下:

    1.Application:保存应用的全局信息的类,它的实例在应用创建的时候被创建,生命周期最长,应用销毁了才会被销毁。

    2.Activity:创建一个Activity便对应一个Context的实例,生命周期随着Activity的周期变化。

    3.Service:创建一个Service便对应一个Context的实例,生命周期随着Service的周期变化。

下面逐一看看它们是什么时候实例Context类的,我们需要知道,一个ContextWrapper类对应一个ContextImpl类的实例,因为具体实现的地方还是在ContextImpl中,ContextWrapper中的mBase变量指向ContextImpl变量的实例。

(1) Application的Context创建:

如图:

  跳过Process创建过程,在我们的应用被zygote进程孵化出来后,被反射调用main函数,这里会创建ActivityThread类的实例,该类并不是一个线程类的子类,但是它的main函数跑在新创建的进程的主线程。 创建后,调用attach方法,与AMS绑定:

这里传入的mAppThread变量为ApplicationThread类,它为ActivityThread的内部类,作用就是作为应用端的binder服务端,负责接收AMS的调度,这里我们传入这个服务端的句柄,让AMS持有,从而AMS可以通过这个句柄来操控应用的行为。我们向AMS请求,则是通过AMS的句柄。接下来就到了AMS的逻辑:

    在ApplicationThread的实现端中,就是把跨进程传递过来的各种数据再用一个AppBindData类保存下来,然后调用Handler对象H发送消息BIND_APPLICATION,最后在app线程中处理此逻辑,让AMS线程可以不必同步阻塞。接下来就到了handleBindApplication:

    Instrumentation类是用于管理Acitivty的工具类。这又有一个比较重要的对象出现,LoadedApk,它里面保存了类加载器ClassLoader,data.info的对象便是它,makeApplication函数中的逻辑:

  这里我们看到了ContextImpl的创建时机,就是在Application实例创建的时候:

  如此就完成了Application的创建,并且调用attach方法把Application的mBase对象赋值给创建的ContextImpl,至此Application的创建就完成了,getApplicationContext() 返回的便是此处我们创建的Application类的对象。

  这里为什么要去LoadedApk类中利用类加载器,把对象创建出来呢?因为我们的Application类是可以自己拓展的,创建的时候是不确定应用自己是否复写了Application对象, 利用类加载器就可以动态决定创建什么类的对象了 ,我们只需要从PMS中获取到application的具体类名即可,这个类名是写在Mainfest文件中的,后面Activity也是利用这种机制去创建对象。

(2)Actvity的启动过程,网上非常多文章分析了,我也就不再重复罗列出来了,大概的过程就是startActivity()被调用,然后检查目标Acitivity的进程是否创建,没创建就先向Zygote进程请求fork应用进程,然后一系列初始化过程后,最后在AMS模块中的ActivityStackSupervisor中realStartActivityLocked()调用IApplicationThread代理类,调用到scheleLaunchActivity(),然后在应用的线程开始执行handleLaunchActivity(),最主要的逻辑在performLaunchActivity:

  至于Activity的生命周期后面怎么走的,这里不在乎,我们只看Context实例化过程。同样的,这里也会创建ContextImpl对象,在Activity对象创建后,调用Attach(),这个函数挺重要的,我们看看都干了什么:

  在attach函数中,也会为ContextWrapper中的mBase对象赋值一个ContextImpl对象,我们这里也能猜想到Service的创建估计也会有这个过程,而事实上Service的创建差不多也是这个过程,所以不再赘述了。

    我们可以知道Context例的实例化都是在我们在Application,Activity和Service创建的时候会实例化,而这些组件的父类都是ContextWrapper,所以在创建的时候还会先创建一个ContextImpl类对象,然后给自己的父类mBase变量赋值,既然如此,Context的引用对应的就是Application,Activity和Service了,Context的用处就是提供了一组抽象的函数,让子类去相对应的实现,当你持有一个Context引用的时候,你可以通过这个引用去获取相对应组件的信息。比如持有一个Activity的Context引用,你可以在别的地方调用startActivity()去启动一个新的activity。

总结:

  1.Context是抽象类,所以实例化要在子类中,Application,Service,Activity是我们实例化的地方,一般应用创建会实例化一个Application类,Service和Activity则是在startService和StartActivity被调用的时候会实例化,它们都会创建一个ContextImpl类实例,给自己的父类ContextWrapper的mBase变量赋值。

  2.Context是组件中通用操作的一组集合,当具体的子类实例化后,可以在别的地方通过保存一个Context引用去获取信息和通用操作等,也就是说,我们可以通过这个引用去获取到这个应用中的重要信息以及这个应用的通用操作。

阅读全文

与context源码大全相关的资料

热点内容
如何修改ie代理服务器 浏览:417
折纸手工解压玩具不用a4纸 浏览:485
怎么双向传输服务器 浏览:286
电脑如何实现跨网段访问服务器 浏览:549
模块化网页源码字节跳动 浏览:485
梯度下降算法中遇到的问题 浏览:605
服务器连接电视怎么接 浏览:323
phploop语句 浏览:502
交叉编译工具链里的库在哪 浏览:781
安卓手q换号怎么改绑 浏览:399
nba球星加密货币 浏览:789
命令看网速 浏览:124
java堆分配 浏览:161
linuxbuiltin 浏览:560
cstpdf 浏览:941
texstudio编译在哪 浏览:352
国家反诈中心app注册登记表怎么注册 浏览:972
加密机默认端口 浏览:101
有哪个网站有免费的python源代码 浏览:305
苹果手机如何导入安卓电话 浏览:915