AbstractApplicationContext类中refresh()方法为spring容器启动的核心方法,是spring容器启动的核心流程,是一个典型的父类模板设计模式,根据不同的上下文对象,会调用到不同的上下文对象子类方法中。
核心的上下文子类有:
1、ClassPathXmlApplicationContext(标签)
2、FileSystemXmlApplicationContext(导入)
3、AnnotationConfigApplicationContext(注解)
4、EmbeddedWebApplicationContext(springboot)
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
}
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
return getBeanFactory();
}
obtainFreshBeanFactory方法的作用总结:
1、创建BeanFactory对象
2、xm解析:传统标签解析、自定义标签解析,比如<context:component-scan …>
3、把解析的xml标签封装成BeanDefinition对象
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();//创建bean工厂
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);//设置是否允许循环依赖和相同名称的BeanDefinition是否允许覆盖
loadBeanDefinitions(beanFactory);//解析xml,并把xml中的标签封装成BeanDefinition
this.beanFactory = beanFactory;
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
xml解析过程:
1、把字符串类型的xml文件路径,形如:classpath*:user/**/*-context.xml,转换成Resource对象类型,其实就是用流的方式加载配置文件,然后封装成Resource对象
2、获取Resource对象中的xml文件流对象,并封装成InputSource对象
3、把InputSource解析成Document文件对象(采用的是sax解析,按sax解析规则解析成Document)
4、将Document对象的root节点作为参数进行解析,如图所示:
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
//默认标签解析
parseDefaultElement(ele, delegate);
}
else {
//自定义标签解析
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
一、自定义标签解析流程
以<context:component-scan base-package…>为例:
1、根据当前解析标签的头信息找到对应的namespaceUri
2、加载spring所有jar中spring.handlers文件,并建立映射关系
3、根据namespaceUri从映射关系中找到对应的实现了NameSpaceHandler接口的类
4、调用init()方法并返回NamespaceHandler(注:init()注册了各种自定义标签的解析类)
5、调用NamespaceHandler(和namespaceUri进行了映射)根据标签注册的解析类(ComponentScanBeanDefinitionParser)的parse()方法
6、获取base-package属性
7、创建注解扫描器ClassPathBeanDefinitionScanner
8、扫描路径下有@Component注解的class文件(@Controller、@Service等父注解为@Component;spring注册了注解类型过滤,将@Component注册到了集合includeFilters中,扫描时会根据includeFilters注册的注解过滤),并封装成ScannedGenericBeanDefinition放入set集合
9、循环set集合,将ScannedGenericBeanDefinition封装成BeanDefinitionHolder并注册BeanDefinition
10、注册组件:
ConfigurationClassPostProcessor
AutowiredAnnotationBeanPostProcessor
CommonAnnotationBeanPostProcessor
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
//获取basePackage属性
String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);
basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
//可以用逗号分开
String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
//创建注解扫描器
// Actually scan for bean definitions and register them.
ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
//扫描并把扫描的类封装成beanDefinition对象
Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
//注册组件
registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
return null;
}
...
...
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
//扫描到有注解的类并封装成BeanDefinition对象
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
//支持了@Lazy @DependOn注解
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
//BeanDefinition注册
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
二、默认标签解析流程
以<bean …>为例:
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//解析<bean>,封装成BeanDefinition
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
//完成document到BeanDefinition对象转换后,对BeanDefinition对象进行缓存注册
// Register the final decorated instance.
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
解析bean标签,封装成BeanDefinition过程:
1、获取bean标签的id和name属性;
2、检查beanName是否重复;
3、创建GenericBeanDefinition,完成其他属性解析并设置到BeanDefinition中,如图所示:
@Nullable
public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, @Nullable BeanDefinition containingBean) {
...
//解析出className和parent,className为需要实例化的类
...
try {
//创建GenericBeanDefinition对象
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
//解析bean标签的属性,并把解析出来的属性设置到BeanDefinition中,比如init-method、depends-on等
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
//解析bean中的meta标签
parseMetaElements(ele, bd);
//解析bean中的lookup-method标签
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
//解析bean中的replaced-method标签
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
//解析bean中的constructor-arg标签
parseConstructorArgElements(ele, bd);
//解析bean中的property标签
parsePropertyElements(ele, bd);
...
...
4、完成BeanDefinition的注册
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/13831.html