




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、上面我们分析了IOC容器本身的实现,下面我们看看在典型的web环境中,Spring IOC容器是怎样被载入和起作用的。 简单的说,在web容器中,通过ServletContext为Spring的IOC容器提供宿主环境,对应的建立起一个IOC容器的体系。其中,首先需要建立的是根上下文,这个上下文持有的对象可以有业务对象,数据存取对象,资源,事物管理器等各种中间层对象。在这个上下文的基础上,和web MVC相关还会有一个上下文来保存控制器之类的MVC对象,这样就构成了一个层次化的上下文结构。在web容器中启动Spring应用程序就是一个建立这个上下文体系的过程。Spring为web应用提供了上下文
2、的扩展接口 WebApplicationContext: Java代码 1. public interface WebApplicationContext extends ApplicationContext 2. /这里定义的常量用于在ServletContext中存取根上下文 4. . 5. /对WebApplicationC
3、ontext来说,需要得到Web容器的ServletContext 6. ServletContext getServletContext(; 7. public interface WebApplicationContext extends ApplicationContext /这里定义的常量用于在ServletContext中存取根上下文./对WebApplicationContext来说,需要得到Web容器的ServletContextServletCont
4、ext getServletContext(;而一般的启动过程,Spring会使用一个默认的实现,XmlWebApplicationContext - 这个上下文实现作为在web容器中的根上下文容器被建立起来,具体的建立过程在下面我们会详细分析。 Java代码 1. public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext 2. 3.
5、;/* 这是和web部署相关的位置信息,用来作为默认的根上下文bean定义信息的存放位置*/ 4. public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml" 5. public static final String
6、60;DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/" 6. public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml" 7. 8. /我们又看到了熟悉的loa
7、dBeanDefinition,就像我们前面对IOC容器的分析中一样,这个加载工程在容器的refresh(的时候启动。 9. protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory throws IOException 10. /对于XmlWebAppl
8、icationContext,当然使用的是XmlBeanDefinitionReader来对bean定义信息来进行解析 11. XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory; 12. 13.
9、 beanDefinitionReader.setResourceLoader(this; 14. beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this; 15. 16. initBeanDefinitionRead
10、er(beanDefinitionReader; 17. loadBeanDefinitions(beanDefinitionReader; 18. 19. 20. protected void initBeanDefinitionReader(XmlBeanDefinitionReade
11、r beanDefinitionReader 21. 22. /使用XmlBeanDefinitionReader来读入bean定义信息 23. protected void loadBeanDefinitions(XmlBeanDefinitionReader reader throws BeansExce
12、ption, IOException 24. String configLocations = getConfigLocations(; 25. if (configLocations != null 26.
13、0; for (int i = 0; i < configLocations.length; i+ 27. reader.loadBeanDefinitions(configLoc
14、ationsi; 28. 29. 30. 31. /这里取得bean定义信息位置,默认的地方是/WEB-INF/applicationContext.xml
15、160; 32. protected String getDefaultConfigLocations( 33. if (getNamespace( != null 34. ret
16、urn new String DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace( + DEFAULT_CONFIG_LOCATION_SUFFIX; 35. 36. else 37. &
17、#160; return new String DEFAULT_CONFIG_LOCATION; 38. 39. 40. public class XmlWebApplicationContext extends Abs
18、tractRefreshableWebApplicationContext /* 这是和web部署相关的位置信息,用来作为默认的根上下文bean定义信息的存放位置*/public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml"public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/"public static final String DEFAULT_CONFI
19、G_LOCATION_SUFFIX = ".xml"/我们又看到了熟悉的loadBeanDefinition,就像我们前面对IOC容器的分析中一样,这个加载工程在容器的refresh(的时候启动。protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory throws IOException /对于XmlWebApplicationContext,当然使用的是XmlBeanDefinitionReader来对bean定义信息来进行解析XmlBeanDefinitionReader bea
20、nDefinitionReader = new XmlBeanDefinitionReader(beanFactory;beanDefinitionReader.setResourceLoader(this;beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this;initBeanDefinitionReader(beanDefinitionReader;loadBeanDefinitions(beanDefinitionReader;protected void initBeanDefinitionReade
21、r(XmlBeanDefinitionReader beanDefinitionReader /使用XmlBeanDefinitionReader来读入bean定义信息protected void loadBeanDefinitions(XmlBeanDefinitionReader reader throws BeansException, IOException String configLocations = getConfigLocations(;if (configLocations != null for (int i = 0; i < configLocations.len
22、gth; i+ reader.loadBeanDefinitions(configLocationsi;/这里取得bean定义信息位置,默认的地方是/WEB-INF/applicationContext.xmlprotected String getDefaultConfigLocations( if (getNamespace( != null return new String DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace( + DEFAULT_CONFIG_LOCATION_SUFFIX;else return new String DEFA
23、ULT_CONFIG_LOCATION;对于一个Spring激活的web应用程序,可以通过使用Spring代码声明式的指定在web应用程序启动时载入应用程序上下文(WebApplicationContext,Spring的ContextLoader是提供这样性能的类,我们可以使用 ContextLoaderServlet或者ContextLoaderListener的启动时载入的Servlet来实例化Spring IOC容器 - 为什么会有两个不同的类来装载它呢,这是因为它们的使用需要区别不同的Servlet容器支持的Serlvet版本。但不管是 ContextLoaderSevlet还是 C
24、ontextLoaderListener都使用ContextLoader来完成实际的WebApplicationContext的初始化工作。这个ContextLoder就像是Spring Web应用程序在Web容器中的加载器booter。当然这些Servlet的具体使用我们都要借助web容器中的部署描述符来进行相关的定义。 下面我们使用ContextLoaderListener作为载入器作一个详细的分析,这个Servlet的监听器是根上下文被载入的地方,也是整个 Springweb应用加载上下文的第一个地方;从加载过程我们可以看到,首先从Servlet事件中得到ServletContext,然
25、后可以读到配置好的在web.xml的中的各个属性值,然后ContextLoder实例化WebApplicationContext并完成其载入和初始化作为根上下文。当这个根上下文被载入后,它被绑定到web应用程序的ServletContext上。任何需要访问该ApplicationContext的应用程序代码都可以从WebApplicationContextUtils类的静态方法来得到: Java代码 1. WebApplicationContext getWebApplicationContext(ServletContext sc WebApplic
26、ationContext getWebApplicationContext(ServletContext sc以Tomcat作为Servlet容器为例,下面是具体的步骤: 1.Tomcat 启动时需要从web.xml中读取启动参数,在web.xml中我们需要对ContextLoaderListener进行配置,对于在web应用启动入口是在ContextLoaderListener中的初始化部分;从Spring MVC上看,实际上在web容器中维护了一系列的IOC容器,其中在ContextLoader中载入的IOC容器作为根上下文而存在于 ServletContext中。 Java代码 1. /
27、这里对根上下文进行初始化。 2. public void contextInitialized(ServletContextEvent event 3. /这里创建需要的ContextLoader 4. this.contextLoader = createContextLoader(; 5. /
28、这里使用ContextLoader对根上下文进行载入和初始化 7. /这里对根上下文进行初始化。public void contextInitialized(ServletContextEvent event /这里创建需要的ContextLoaderthis.contextLoader = createContextLoader(;/这里使用ContextLoader对根上下文进行载入和初始化通过ContextLoader建立起根上下文的过程,我们可以在ContextLoader中看到: Java代码 1. public WebApp
29、licationContext initWebApplicationContext(ServletContext servletContext 2. throws IllegalStateException, BeansException 3. /这里先看看是不是已经在ServletContext中存在上下文,如果有说明前面已经被载入过,或者是配置文件有
30、错误。 4. if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE != null 5. /直接抛出异常 6. . 7. &
31、#160;8. 9. . 10. try 11. / 这里载入根上下文的父上下文 12. ApplicationContext parent =
32、160;loadParentContext(servletContext; 13. 14. /这里创建根上下文作为整个应用的上下文同时把它存到ServletContext中去,注意这里使用的ServletContext的属性值是 15. /ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,以后的应用都是根据
33、这个属性值来取得根上下文的 - 往往作为自己上下文的父上下文 16. this.context = createWebApplicationContext(servletContext, parent; 17. servletContext.setAttribute( 18.
34、0; WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context; 19. . 20. 21.
35、; return this.context; 22. 23. . 24. public WebApplicationContext initWebApplicationContext(ServletContext servletContextthrows IllegalStateException, BeansExcepti
36、on /这里先看看是不是已经在ServletContext中存在上下文,如果有说明前面已经被载入过,或者是配置文件有错误。if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE != null /直接抛出异常.try / 这里载入根上下文的父上下文ApplicationContext parent = loadParentContext(servletContext;/这里创建根上下文作为整个应用的上下文同时把它存到ServletContext中去,注意这里使用的S
37、ervletContext的属性值是/ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,以后的应用都是根据这个属性值来取得根上下文的 - 往往作为自己上下文的父上下文this.context = createWebApplicationContext(servletContext, parent;servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context;.return this.context;.建立根上下文的父上下文使
38、用的是下面的代码,取决于在web.xml中定义的参数:locatorFactorySelector,这是一个可选参数: Java代码 1. protected ApplicationContext loadParentContext(ServletContext servletContext 2. throws BeansException 3. 4.
39、 ApplicationContext parentContext = null; 5. 6. String locatorFactorySelector = servletContext.getInitParameter(LOCATOR_FACTORY_SELECTOR_PARAM; 7. String parentContextKey
40、 = servletContext.getInitParameter(LOCATOR_FACTORY_KEY_PARAM; 8. 9. if (locatorFactorySelector != null 10. BeanFactoryLocator locator = ContextSin
41、gletonBeanFactoryLocator.getInstance(locatorFactorySelector; 11. . 12. /得到根上下文的父上下文的引用 13. this.parentContextRef =&
42、#160;locator.useBeanFactory(parentContextKey; 14. /这里建立得到根上下文的父上下文 16. 17. 18. return parentContext; 19. protected Application
43、Context loadParentContext(ServletContext servletContextthrows BeansException ApplicationContext parentContext = null;String locatorFactorySelector = servletContext.getInitParameter(LOCATOR_FACTORY_SELECTOR_PARAM;String parentContextKey = servletContext.getInitParameter(LOCATOR_FACTORY_KEY_PARAM;if (
44、locatorFactorySelector != null BeanFactoryLocator locator = ContextSingletonBeanFactoryLocator.getInstance(locatorFactorySelector;./得到根上下文的父上下文的引用this.parentContextRef = locator.useBeanFactory(parentContextKey;/这里建立得到根上下文的父上下文return parentContext;得到根上下文的父上下文以后,就是根上下文的创建过程: Java代码 1. protected W
45、ebApplicationContext createWebApplicationContext( 2. ServletContext servletContext, ApplicationContext parent throws BeansException 3. /这里需要确定我们载入的根WebApplication的类型,由在
46、web.xml中配置的contextClass中配置的参数可以决定我们需要载入什么样的ApplicationContext, 4. /如果没有使用默认的。 5. Class contextClass = determineContextClass(servletContext; 6. . 7.
47、; /这里就是上下文的创建过程 8. ConfigurableWebApplicationContext wac = 9. (ConfigurableWebApplicationContext BeanUtils.instantiateClass(contextClass; 10.
48、 /这里保持对父上下文和ServletContext的引用到根上下文中 11. wac.setParent(parent; 12. wac.setServletContext(servletContext; 13. 14. /这里从web.xml中取得相关的初始化参数 15.
49、 String configLocation = servletContext.getInitParameter(CONFIG_LOCATION_PARAM; 16. if (configLocation != null 17. wac.setConfigLocations(StringUtils.tokeniz
50、eToStringArray(configLocation, 18. ConfigurableWebApplicationContext.CONFIG_LOCATION_DELIMITERS; 19. 20. /这里对WebApplicationCo
51、ntext进行初始化,我们又看到了熟悉的refresh调用。 21. wac.refresh(; 22. return wac; 23. protected WebApplicationContext createWebApplicationContext(ServletContext servletContext, ApplicationContext parent throws BeansE
52、xception /这里需要确定我们载入的根WebApplication的类型,由在web.xml中配置的contextClass中配置的参数可以决定我们需要载入什么样的ApplicationContext,/如果没有使用默认的。Class contextClass = determineContextClass(servletContext;./这里就是上下文的创建过程ConfigurableWebApplicationContext wac =(ConfigurableWebApplicationContext BeanUtils.instantiateClass(contextClass
53、;/这里保持对父上下文和ServletContext的引用到根上下文中wac.setParent(parent;wac.setServletContext(servletContext;/这里从web.xml中取得相关的初始化参数String configLocation = servletContext.getInitParameter(CONFIG_LOCATION_PARAM;if (configLocation != null wac.setConfigLocations(StringUtils.tokenizeToStringArray(configLocation,Configur
54、ableWebApplicationContext.CONFIG_LOCATION_DELIMITERS;/这里对WebApplicationContext进行初始化,我们又看到了熟悉的refresh调用。wac.refresh(;return wac;初始化根ApplicationContext后将其存储到SevletContext中去以后,这样就建立了一个全局的关于整个应用的上下文。这个根上下文会被以后的DispatcherServlet初始化自己的时候作为自己ApplicationContext的父上下文。这个在对 DispatcherServlet做分析的时候我们可以看看到。 3.完成
55、对ContextLoaderListener的初始化以后, Tomcat开始初始化DispatchServlet,- 还记得我们在web.xml中队载入次序进行了定义。DispatcherServlet会建立自己的ApplicationContext,同时建立这个自己的上下文的时候会从ServletContext中得到根上下文作为父上下文,然后再对自己的上下文进行初始化,并最后存到 ServletContext中去供以后检索和使用。 可以从DispatchServlet的父类FrameworkServlet的代码中看到大致的初始化过程,整个ApplicationContext的创建过程和Con
56、textLoder创建的过程相类似: Java代码 1. protected final void initServletBean( throws ServletException, BeansException 2. . 3. try 4. /这里是
57、对上下文的初始化过程。 5. this.webApplicationContext = initWebApplicationContext(; 6. /在完成对上下文的初始化过程结束后,根据bean配置信息建立MVC框架的各个主要元素 7. &
58、#160; initFrameworkServlet(; 8. 9. . 10. protected final void initServletBean( throws ServletException, BeansException .try /这里是对上下文的初始化过程。this.webApplicationContext = initWebApplicationContext(;/在完成对上下文的
59、初始化过程结束后,根据bean配置信息建立MVC框架的各个主要元素initFrameworkServlet(;.对initWebApplicationContext(调用的代码如下: Java代码 1. protected WebApplicationContext initWebApplicationContext( throws BeansException 2. /这里调用WebApplicationContextUtils静态类来得到根上下文
60、0;3. WebApplicationContext parent = WebApplicationContextUtils.getWebApplicationContext(getServletContext(; 4. 5. /创建当前DispatcherServlet的上下文,其上下文种类使用默认的在FrameworkServlet定义好的:DEFAULT_CONTEXT_CLAS
61、S = XmlWebApplicationContext.class; 6. WebApplicationContext wac = createWebApplicationContext(parent; 7. . 8. if (isPublishContext( 9.
62、160; /把当前建立的上下文存到ServletContext中去,注意使用的属性名是和当前Servlet名相关的。 10. String attrName = getServletContextAttributeName(; 11. getServletCo
63、ntext(.setAttribute(attrName, wac; 12. 13. return wac; 14. protected WebApplicationContext initWebApplicationContext( throws BeansException /这里调用WebApplicationContextUtils静态类来得到根上下文WebApplicati
64、onContext parent = WebApplicationContextUtils.getWebApplicationContext(getServletContext(;/创建当前DispatcherServlet的上下文,其上下文种类使用默认的在FrameworkServlet定义好的:DEFAULT_CONTEXT_CLASS = XmlWebApplicationContext.class;WebApplicationContext wac = createWebApplicationContext(parent;.if (isPublishContext( /把当前建立的上下
65、文存到ServletContext中去,注意使用的属性名是和当前Servlet名相关的。String attrName = getServletContextAttributeName(;getServletContext(.setAttribute(attrName, wac;return wac;其中我们看到调用了WebApplicationContextUtils的静态方法得到根ApplicationContext: Java代码 1. public static WebApplicationContext g
66、etWebApplicationContext(ServletContext sc 2. /很简单,直接从ServletContext中通过属性名得到根上下文 3. Object attr = sc.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATIO
67、N_CONTEXT_ATTRIBUTE; 4. . 5. return (WebApplicationContext attr; 6. 7. 然后创建DispatcherServlet自己的WebApplicationContext:
68、60; 8. protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent 9. throws BeansException 10.
69、 . 11. /这里使用了BeanUtils直接得到WebApplicationContext,ContextClass是前面定义好的DEFAULT_CONTEXT_CLASS =
70、160; 12. /XmlWebApplicationContext.class; 13. ConfigurableWebApplicationContext wac = 14.
71、160; (ConfigurableWebApplicationContext BeanUtils.instantiateClass(getContextClass(; 15. 16. /这里配置父上下文,就是在ContextLoader中建立的根上下文 17.
72、160; wac.setParent(parent; 18. 19. /保留ServletContext的引用和相关的配置信息。 20. wac.setServletContext(getServletContext(; 21.
73、 wac.setServletConfig(getServletConfig(; 22. wac.setNamespace(getNamespace(; 23. 24. /这里得到ApplicationContext配置文件的位置 25. &
74、#160; if (getContextConfigLocation( != null 26. wac.setConfigLocations( 27.
75、 StringUtils.tokenizeToStringArray( 28. getContextConfigLocation(, ConfigurableWebApplicatio
76、nContext.CONFIG_LOCATION_DELIMITERS; 29. 30. 31. /这里调用ApplicationContext的初始化过程,同样需要使用refresh( 32.
77、160; wac.refresh(; 33. return wac; 34. public static WebApplicationContext getWebApplicationContext(ServletContext sc /很简单,直接从ServletContext中通过属性名得到根上下文Object
78、 attr = sc.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE;.return (WebApplicationContext attr;然后创建DispatcherServlet自己的WebApplicationContext:protected WebApplicationContext createWebApplicationContext(WebApplicationContext parentthrows BeansException ./这里使用了BeanUtils直接得到Web
79、ApplicationContext,ContextClass是前面定义好的DEFAULT_CONTEXT_CLASS = /XmlWebApplicationContext.class;ConfigurableWebApplicationContext wac =(ConfigurableWebApplicationContext BeanUtils.instantiateClass(getContextClass(;/这里配置父上下文,就是在ContextLoader中建立的根上下文wac.setParent(parent;/保留ServletContext的引用和相关的配置信息。wac.
80、setServletContext(getServletContext(;wac.setServletConfig(getServletConfig(;wac.setNamespace(getNamespace(;/这里得到ApplicationContext配置文件的位置if (getContextConfigLocation( != null wac.setConfigLocations(StringUtils.tokenizeToStringArray(getContextConfigLocation(, ConfigurableWebApplicationContext.CONFIG_
81、LOCATION_DELIMITERS;/这里调用ApplicationContext的初始化过程,同样需要使用refresh(wac.refresh(;return wac;4. 然后就是DispatchServlet中对Spring MVC的配置过程,首先对配置文件中的定义元素进行配置 - 请注意这个时候我们的WebApplicationContext已经建立起来了,也意味着DispatcherServlet有自己的定义资源,可以需要从web.xml中读取bean的配置信息,通常我们会使用单独的xml文件来配置MVC中各个要素定义,这里和web容器相关的加载过程实际上已经完成了,下面的处理
82、和普通的Spring应用程序的编写没有什么太大的差别,我们先看看MVC的初始化过程: Java代码 1. protected void initFrameworkServlet( throws ServletException, BeansException 2. initMultipartResolver(; 3. initLocaleResolver(; 4. &
83、#160; initThemeResolver(; 5. initHandlerMappings(; 6. initHandlerAdapters(; 7. initHandlerExceptionResolvers(; 8. initRequestToViewNameTran
84、slator(; 9. initViewResolvers(; 10. protected void initFrameworkServlet( throws ServletException, BeansException initMultipartResolver(;initLocaleResolver(;initThemeResolver(;initHandlerMappings(;initHandlerAdapters(;initHandlerExceptionResolvers(;initRequestToViewNameTranslator(;initViewResolvers(;5. 这样MVC的框架就建立起来了,DispatchServlet对接受到的HTTP Request进行分发处理由doService(完成,具体的MVC处理过程我们在doDispatch(中完成,其中包括使用Command模式建立执行链,显
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2024年福建南平邵武市金鑫林业发展有限公司招聘24人笔试参考题库附带答案详解
- 2024山西转型综合改革示范区晋中开发区产业投资有限公司竞聘上岗笔试参考题库附带答案详解
- 四年级语文上册 第二单元 7 呼风唤雨的世纪教学实录 新人教版五四制
- 3.2 世界的人种(练习)-【上好课】2021-2022学年七年级地理上册同步备课系列(湘教版)
- 小学信息技术三年级上册第16课《月夜思故乡-图形组合》教学设计
- Module 6 Unit 1 Ill draw the pictures. 教学设计(教学设计)-2023-2024学年外研版(一起)英语四年级下册
- 中国古代文学知到课后答案智慧树章节测试答案2025年春浙江工业大学
- 7 什么比猎豹的速度更快教学设计-2024-2025学年五年级上册语文统编版
- 2024-2025学年高中生物 第五章 基因突变及其它变异 第1节 基因突变和基因重组教学实录 新人教版必修2
- 九年级语文上册 第四单元 15 我的叔叔于勒教学实录 新人教版
- 2024中煤陕西能源化工集团有限公司招聘笔试冲刺题(带答案解析)
- MOOC 心理学与生活-华东师范大学 中国大学慕课答案
- 教科版小学二年级科学下册教案(全册)
- 医疗器械安全知识培训
- 2024年度-小米米家智能家居入门指南
- 2024年大唐杯5G必考试题库 (带答案)
- (高清版)DZT 0279.30-2016 区域地球化学样品分析方法 第30部分:钨量测定 碱熔-电感耦合等离子体质谱法
- 摄影基础知识入门与技术
- 从局部到整体:5G系统观-完整版
- 留置溶栓导管的护理
- 弦乐团教学方案
评论
0/150
提交评论