首先,Spring上下文分为父Spring上下文和子Spring上下文。
**子Spring就是SpringMVC的WebApplicationContext,同理服上下文就是spring框架本事的上下文Root上下文**
** 父Spring的监听器是ContextLoaderListener这个Listener,SpringMVC的入口就在DispatcherServlet。**
ContextLoaderListener父类方法
**ContextLoader#initWebApplicationContext()**
**ContextLoader#configureAndRefreshWebApplicationContext()**
**AbstractApplicationContext#refresh()**
首先解读ApplicationContext中的refresh()方法。
设置容器的一些状态:设置容器处于未关闭状态,设置active为激活状态,注入环境
调用到AbstractRefreshableApplicationContext#obtainFreshBeanFactory()方法
调用到AbstractRefreshableApplicationContext#refreshBeanFactory()方法
调用到AbstractXmlApplicationContext#loadBeanDefinitions()方法
调用到XmlBeanDefinitionReader#loadBeanDefinitions()方法
在loadBeanDefinitions方法中获取spring的配置文件流
然后调用到XmlBeanDefinitionReader#doLoadBeanDefinitions()
把xml转换成Document对象
调用到XmlBeanDefinitionReader#registerBeanDefinitions()方法
调用到DefaultBeanDefinitionDocumentReader#parseBeanDefinitions()方法
**此方法中有一个对子元素的for循环会调到此类中的#parseDefaultElement()方法 **
** 如果nodename 等于 bean 的话 也就是bean 的解析,对应着processBeanDefinition()方法,会在此进行解析下面会跟到BeanDefinitionParserDelegate#parseBeanDefinitionElement();**
** 重点解释parseBeanDefinitionElement()方法(开头用@表示,@1表示第一步…):**
** @1首先获取bean的id和name,对name进行别名处理**
** @2到本类的parseBeanDefinitionElement()方法:(开头用*表示,1表示第一步…):*
** * 1在本类的parseState栈中push一个beanname**
** * 2创建一个AbstractBeanDefinition类型**
** * 3parseBeanDefinitionAttributes()方法是对bean设置是否单例,是否懒加载**
** @3对AbstractBeanDefinition对象封装成BeanDefinitionHolder对象进行返回**
** DefaultBeanDefinitionDocumentReader#processBeanDefinition()方法的第一行,这里返回一个BeanDefinitionHolder对象**
下面接着看:
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
这一行代码是对BeanDefinition的一个注册进入到BeanDefinitionReaderUtils#registerBeanDefinition()方法在跟入到DefaultListableBeanFactory#registerBeanDefinition()方法,
下面重点解释这个方法(以*开头,*1代表第一步):
** *1.这里的oldBeanDefinition对象肯定为空直接走else,往当前map里写入 **
** this.beanDefinitionMap.put(beanName, beanDefinition)**
** 并且把beanName写入到名字为beanDefinitionNames的list中**
** 把beanName也写入到名字为manualSingletonNames的list中**
** 到这里BeanDefinitionReaderUtils#registerBeanDefinition()方法已经执行完了 registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());**
** 行下面该注册别名在SimpleAliasRegistry类的aliasMap中注册别名,这里就不细说了。**
** 到此,AbstractApplicationContext#refresh()方法的obtainFreshBeanFactory()方法主要bean执行完毕**
** 抛开以上思路,上面解释了xml解析bean。下面解释解析Annotation标签。我先介绍怎么手写Spring插件:首先,在META-INF文件夹下建立两个文件,名字分别为spring.handlers,spring.schemas**
1.3.1 spring.handlers文件
[http://www.lgq.com/mt/tag=com.custom.tag.www.customTag.handel.NameSpaceHand](http://www.lgq.com/mt/tag=com.custom.tag.www.customTag.handel.NameSpaceHandel)le
就这么一行信息等号前面的url是自定义的,后面的类是继承自NamespaceHandlerSupport类的手写类,其中有个init方法
** registerBeanDefinitionParser(“reference”, new ReferenceBeanDefiniitonparser(Reference.class));**
** 自定义一个ReferenceBeanDefiniitonparser类,实现BeanDefinitionParser接口,实现paBeanDefinition方法,其中Element对象就是reference 标签的封装对象,**
** ParserContext是对Spring容器的扩展,自定义一个BeanDefinition对象,通过parserContext.getRegistry().registerBeanDefinition(“reference”+id, beanDefinition);**
就可以注入Spring
1.3.2 spring.schemas
http://www.lgq.com/mt/tag/mytag.xsd=com/custom/tag/www/customTag/config/mytag.xsd
也是一行信息,主要的是对应的mytag.xsd(名字随便起的)文件
mytag.xsd文件
可以定义多个对象
下面就是熟悉的spring的配置文件了
1.3.3 在顶部的beans里增加两行信息
xmlns:nihao=”http://www.lgq.com/mt/tag” 和http://www.lgq.com/mt/tag http://www.lgq.com/mt/tag/mytag.xsd 信息
到此,就可以在spring的配置文件中使用自定义的标签
<nihao:reference id=“userService” interface=“com.custom.tag.www.customTag.service.UserService” ></dubbo:reference>
是spring自定义标签的内容(dubbo和Spring无缝融接就是这么干的)
下面我解释怎么进行Annotation标签的扫描
1.3.4 Annotation解析bean
** 首先打开ContextNamespaceHandler类(继承了NamespaceHandlerSupport类)**
** 你应该已经看到了“component-scan”标签了,这就是spring配置文件里面的扫描包文件的标签**
** 跟入到ComponentScanBeanDefinitionParser(此类实现了BeanDefinitionParser接口)#parse()方法**
下面1.3.5和1.3.6和1.3.7 中解释下列三
ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
Set beanDefinitions = scanner.doScan(basePackages);
registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
1.3.5 解释configureScanner(parserContext, element);
跟入到ComponentScanBeanDefinitionParser#configureScanner()方法,看到有一个判断是否有use-default-filters属性的判断,如果此属性为false的话,是不会进行
Annotion的扫描的:
跟到 createScanner(parserContext.getReaderContext(),` useDefaultFilters);方法在跟到
if (useDefaultFilters) {
registerDefaultFilters();
}
//这个useDefaultFilters就是use-default-filters的设置,默认为true,如果设置为false的话就不会执行下面这个方法就得另外配置需要扫描的标签了.
下面解释registerDefaultFilters()方法;
this.includeFilters.add(new AnnotationTypeFilter(Component.class));
这一行代码就是吧ClassPathScanningCandidateComponentProvider#includeFilters的list里面添加需要扫描的标签,其实@Controller @Service @Repository 标签都是继承自Component 没有什么区别的
下面再看parseTypeFilters(element, scanner, parserContext); 方法
如果use-default-filters设置为false的话,就得配置include-filter 标签,同样也会加入到ClassPathScanningCandidateComponentProvider#includeFilters的list中去,还有一个exclude-filter标签(排除标签)
到这里configureScanner(parserContext, element);这句话就解释完毕。
1.3.6 解释Set beanDefinitions = scanner.doScan(basePackages);
首先看到了doScan方法,里面会调用findCandidateComponents(basePackage);下面解释findCandidateComponents方法,(用%表示%1表示第一步…)
%1.首先会把com.study.www这种包名中的.换成/,
%2.会递归调用所有包下面的文件,具体递归实现在PathMatchingResourcePatternResolver#findPathMatchingResources()方法里
%3.MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource); 执行到这里的时候会对Resource进行读取流
看SimpleMetadataReader(Resource resource, ClassLoader classLoader) 的构造方法就可以知道吧Resource读取成流,然后封装成 AnnotationMetadataReadingVisitor对象
%4.ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);把刚才封装成的AnnotationMetadataReadingVisitor对象进行转化成ScannedGenericBeanDefinition对象
到此这个findCandidateComponents(basePackage);就获取到了所有的ScannedGenericBeanDefinition对象
在返回到doScan()方法中,对ScannedGenericBeanDefinition对象循环
首先ScannedGenericBeanDefinition对象是实现了AnnotatedBeanDefinition接口的
所以for循环里肯定走
if (candidate instanceof AnnotatedBeanDefinition) {
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
)代码块
这里processCommonDefinitionAnnotations 方法对bean进行一些设置,比如是否懒加载,比较容易
然后把ScannedGenericBeanDefinition转化成了BeanDefinitionHolder
再看方法registerBeanDefinition(definitionHolder, this.registry);
此方法在BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());在xml解析bean的时候分析过,也是注册到两个set,一个map中,达到了殊途同归的效果
到此,scanner.doScan(basePackages);方法就完全执行完毕
1.3.7 解释registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
在registerComponents方法中看到了是否有annotation-config标签的设置,默认为true,如果设置为false的话就不会执行registerAnnotationConfigProcessors()方法了
当然,如果只是设置了component的话,即便没设置annotation-config,默认也是true的
在registerAnnotationConfigProcessors()方法中就是注入了一些bean ,比如说AutowiredAnnotationBeanPostProcessor的bean,就是对@autowire标签的支持,
在这里注入的时候和之前说的xml和Annotion注入不是走的一个方法,在这里走的是DefaultListableBeanFactory#registerBeanDefinition()方法,其实效果也是一样的,就是给两个list增加了值,一个map增加了 ,相对比较简单
再就是在CompositeComponentDefinition 类的nestedComponents的list中增加了BeanComponentDefinition对象。
|