Insight task:annotation-driven 解析 | Insight 常识

疑问:1、spring 配置,容器启动过程中是怎样解析,做了哪些工作?

2、@Scheduled 是怎样find,解析,将注解的method 加入调度任务中?

...

注:Insight 版本3.2.13.RELEASE

首先明确的基本常识:

a.从spring的初始化开始,首先会根据xml 配置文件够造bean-factory,然后注册各种各样的bean-post-processor和bean-factory-post-processor,最后才是bean 的初始化。

b.配置文件的解析根据element namespace分为两部分实现:bean、import基础类的namespace默认内部实现,其他类型的namespace委托给各自的xxx-NameSpaceHandler实现。

c.bean初始化过程中涉及dependency 解析inject调用,递归进行bean初始化的过程,从而实现context中所有bean-definination的初始化。

...

ok,然后Insight code,可以解答问题1:

// 1、按照惯例,context 初始化入口,:)
AbstractApplicationContext.refresh()
// 2、定义beanFactory,真正的实现交给subClass
// application.xml 解析全部在此完成,
obtainFreshBeanFactory()
// 3、实现new beanFactory subClass来啦,此方法定义了一系列的步骤,其中loadBean 逻辑交给 subClass
AbstractRefreshableApplicationContext.refreshBeanFactory()
// 4、load application.xml Bean 真正实现
// Loads the bean definitions via an XmlBeanDefinitionReader.
XmlWebApplicationContext.loadBeanDefinitions()
// 5、!core Parse the elements. (default : "import", "alias", "bean")	
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
    // 判断namespace 是否属于 http://www.springframework.org/schema/beans
    if (delegate.isDefaultNamespace(root)) {
    	NodeList nl = root.getChildNodes();
    	for (int i = 0; i < nl.getLength(); i++) {
    		Node node = nl.item(i);
    		Element ele = (Element) node;
    		if (delegate.isDefaultNamespace(ele)) {
    			parseDefaultElement(ele, delegate);
    		}
    		else {
    		    // 我们的task:annotation-driven 就是从这里开始解析
    			delegate.parseCustomElement(ele);
    		}
    	}
    }
    // ...
}
// 6、对于customElement,按照惯例,委托给对应的Handler小弟们去实现解析。
// @see BeanDefinitionParserDelegate
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
    String namespaceUri = getNamespaceURI(ele);
    // 根据element's namespace 获取对应的处理ClassName,通过反射newInstance()生成handler
    // ClassName:namespace mapping参考组件jar META-INF/spring.handlers
    NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
    if (handler == null) {
    	error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
    	return null;
    }
    return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
// 7、根据TaskNamespaceHandler终于找到主角AnnotationDrivenBeanDefinitionParser,解析
public BeanDefinition parse(Element element, ParserContext parserContext) {
    // ...
    // 注意ScheduledAnnotationBeanPostProcessor bean的初始化,@Scheduled 注解就是他解析的,后续讲到
    BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition("org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor");
    builder.getRawBeanDefinition().setSource(source);
    String scheduler = element.getAttribute("scheduler");
    if (StringUtils.hasText(scheduler)) {
    	builder.addPropertyReference("scheduler", scheduler);
    }
    registerPostProcessor(parserContext, builder, AnnotationConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME);
    // ...

}
// 8、Finally 解析完毕,解析@Scheduled 注解的Processor准备,注册完毕。
// happy ending.../**
 * http://www.springframework.org/schema/task Custom解析器
 * 实现  解析 
 * (其中)
 * 
 * @author Mark Fisher
 * @since 3.0
 */
public class TaskNamespaceHandler extends NamespaceHandlerSupport {
    
    // 该方法在Locate NameSpaceHandler过程中调用。@see DefaultNamespaceHandlerResolver.resolve()
	public void init() {
		this.registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
		this.registerBeanDefinitionParser("executor", new ExecutorBeanDefinitionParser());
		this.registerBeanDefinitionParser("scheduled-tasks", new ScheduledTasksBeanDefinitionParser());
		this.registerBeanDefinitionParser("scheduler", new SchedulerBeanDefinitionParser());
	}

}

总结:AnnotationDrivenBeanDefinitionParser 实现解析,解析的过程可以直接跳过Insight,直接看parse() 即可。

对于问题2,parse过程中注册了PostProcessor,待bean初始化完成后,会触发post事件,ScheduledAnnotationBeanPostProcessor就会上场,find @Scheduled method,完成Scheduled 的解析,下回Insight。


你可能感兴趣的:(读书笔记)