Spring source code parsing 8: default namespace processor in XML configuration
staySpring source code analysis 5: bean configuration, definition and registrationIn, the default namespace processor in some XML configurations has not been resolved
- SimpleConstructorNamespaceHandler
- SimplePropertyNamespaceHandler
- UtilNamespaceHandler
- ContextNamespaceHandler
- JeeNamespaceHandler
- LangNamespaceHandler
- TaskNamespaceHandler
- CacheNamespaceHandler
- MvcNamespaceHandler
- AopNamespaceHandler
- JdbcNamespaceHandler
- TxNamespaceHandler
Here only a few commonly used are analyzed
SimpleConstructorNamespaceHandler
SimplePropertyNamespaceHandler
ContextNamespaceHandler
TaskNamespaceHandler
CacheNamespaceHandler
MvcNamespaceHandler
Others who are interested can explore by themselves
1. SimpleConstructorNamespaceHandler
SimpleConstructorNamespaceHandler
The main function of is to instantiate the beans configured as follows
<bean id="author" class="..TestBean" c:name="Enescu" c:work-ref="compositions"/>
takename="Enescu", work=bean[compositions]
Instantiate beans as arguments to constructors
public class SimpleConstructorNamespaceHandler implements NamespaceHandler {
@Override
public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) {
if (node instanceof Attr) {
Attr attr = (Attr) node;
//Remove blank on both sides
String argName = StringUtils.trimWhitespace(parserContext.getDelegate().getLocalName(attr));
//Remove blank on both sides
String argValue = StringUtils.trimWhitespace(attr.getValue());
//Constructor parameter set
ConstructorArgumentValues cvs = definition.getBeanDefinition().getConstructorArgumentValues();
boolean ref = false;
//If the field name results with "- ref", it indicates the reference to other beans at run time
if (argName.endsWith(REF_SUFFIX)) {
ref = true;
argName = argName.substring(0, argName.length() - REF_SUFFIX.length());
}
//Encapsulate values with valueholder
ValueHolder valueHolder = new ValueHolder(ref ? new RuntimeBeanReference(argValue) : argValue);
valueHolder.setSource(parserContext.getReaderContext().extractSource(attr));
//With "" If the parameter is passed in the order of the first name, it means there is no parameter
if (argName.startsWith(DELIMITER_PREFIX)) {
String arg = argName.substring(1).trim();
//If no order is specified, add directly
if (!StringUtils.hasText(arg)) {
cvs.addGenericArgumentValue(valueHolder);
}
//If there is a specified order, add in the specified order
else {
int index = -1;
try {
index = Integer.parseInt(arg);
}
catch (NumberFormatException ex) {
// ... Code omission
}
// ... Code omission
//Add to CVS
cvs.addIndexedArgumentValue(index, valueHolder);
}
}
//Parameter with name
else {
// ... Code omission
//Add to CVS
valueHolder.setName(Conventions.attributeNameToPropertyName(argName));
cvs.addGenericArgumentValue(valueHolder);
}
}
return definition;
}
}
2. SimplePropertyNamespaceHandler
SimplePropertyNamespaceHandler
The main function of is to instantiate the beans configured as follows
<bean id="rob" class="..TestBean" p:name="Rob Harrop" p:spouse-ref="sally"/>
takename="Rob Harrop", spouse=bean[sally]
Inject into beans as attributes
public class SimplePropertyNamespaceHandler implements NamespaceHandler {
@Override
public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) {
if (node instanceof Attr) {
Attr attr = (Attr) node;
//Attribute name
String propertyName = parserContext.getDelegate().getLocalName(attr);
//Attribute value
String propertyValue = attr.getValue();
//Attribute Collection
MutablePropertyValues pvs = definition.getBeanDefinition().getPropertyValues();
//If the field name results with "- ref", it indicates the reference to other beans at run time
if (propertyName.endsWith(REF_SUFFIX)) {
propertyName = propertyName.substring(0, propertyName.length() - REF_SUFFIX.length());
//Change the field name from dash - or underscore_ Transformed into a hump
pvs.add(Conventions.attributeNameToPropertyName(propertyName), new RuntimeBeanReference(propertyValue));
}
else {
//Change the field name from dash - or underscore_ Transformed into a hump
pvs.add(Conventions.attributeNameToPropertyName(propertyName), propertyValue);
}
}
return definition;
}
}
3. ContextNamespaceHandler
public class ContextNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
}
}
3.1. context:property-placeholder
PropertyPlaceholderBeanDefinitionParser
The main function of is parsing<context:property-placeholder/>
Element, which is used when defining a bean${}
Properties that reference external sources
Look at the inheritance relationship first
- AbstractBeanDefinitionParser
- AbstractSingleBeanDefinitionParser
- AbstractPropertyLoadingBeanDefinitionParser
- PropertyPlaceholderBeanDefinitionParser
3.1.1. AbstractBeanDefinitionParser
AbstractBeanDefinitionParser
The main function of is to realizeBeanDefinitionParser
Interfacedparse
Method, which provides the basic function of parsing from configuration to object
public abstract class AbstractBeanDefinitionParser implements BeanDefinitionParser {
@Override
public final BeanDefinition parse(Element element, ParserContext parserContext) {
//Parse element
AbstractBeanDefinition definition = parseInternal(element, parserContext);
try {
//Get the ID of the bean
String id = resolveId(element, definition, parserContext);
String[] aliases = null;
//Gets the name attribute, separated by commas into multiple aliases
if (shouldParseNameAsAliases()) {
String name = element.getAttribute(NAME_ATTRIBUTE);
if (StringUtils.hasLength(name)) {
aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name));
}
}
//Encapsulated as beandefinitionholder
BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases);
//Register in registry
registerBeanDefinition(holder, parserContext.getRegistry());
// ... Code omission
}
catch (BeanDefinitionStoreException ex) {
// ... Code omission
}
return definition;
}
//Parse element,由子类实现
protected abstract AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext);
//Get the ID of the bean,先获取id属性,其次name属性,都没有,生成默认的名字
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext)
throws BeanDefinitionStoreException {
// ... Code omission
}
}
3.1.2. AbstractSingleBeanDefinitionParser
AbstractSingleBeanDefinitionParser
The main function of is to support beans that are parsed into singletons
public abstract class AbstractSingleBeanDefinitionParser extends AbstractBeanDefinitionParser {
@Override
protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
//Create a constructor
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
//Parent element
String parentName = getParentName(element);
if (parentName != null) {
builder.getRawBeanDefinition().setParentName(parentName);
}
// beanClass
Class<?> beanClass = getBeanClass(element);
if (beanClass != null) {
builder.getRawBeanDefinition().setBeanClass(beanClass);
}
// beanClassName
else {
String beanClassName = getBeanClassName(element);
if (beanClassName != null) {
builder.getRawBeanDefinition().setBeanClassName(beanClassName);
}
}
// ... Code omission
//Resolve to constructor
doParse(element, parserContext, builder);
return builder.getBeanDefinition();
}
//Resolve to constructor,由子类实现
protected void doParse(Element element, BeanDefinitionBuilder builder) {}
}
3.1.3. AbstractPropertyLoadingBeanDefinitionParser
AbstractPropertyLoadingBeanDefinitionParser
The main function of is parsingcontext:property-...
element
abstract class AbstractPropertyLoadingBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
//Location attribute
String location = element.getAttribute("location");
if (StringUtils.hasLength(location)) {
location = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(location);
String[] locations = StringUtils.commaDelimitedListToStringArray(location);
builder.addPropertyValue("locations", locations);
}
//Properties ref property
String propertiesRef = element.getAttribute("properties-ref");
if (StringUtils.hasLength(propertiesRef)) {
builder.addPropertyReference("properties", propertiesRef);
}
//File encoding attribute
String fileEncoding = element.getAttribute("file-encoding");
if (StringUtils.hasLength(fileEncoding)) {
builder.addPropertyValue("fileEncoding", fileEncoding);
}
//Order attribute
String order = element.getAttribute("order");
if (StringUtils.hasLength(order)) {
builder.addPropertyValue("order", Integer.valueOf(order));
}
//Ignore resource not found attribute
builder.addPropertyValue("ignoreResourceNotFound",
Boolean.valueOf(element.getAttribute("ignore-resource-not-found")));
//Local override property
builder.addPropertyValue("localOverride",
Boolean.valueOf(element.getAttribute("local-override")));
}
}
3.1.4. PropertyPlaceholderBeanDefinitionParser
PropertyPlaceholderBeanDefinitionParser
The main function of is parsingcontext:property-placeholder
element
class PropertyPlaceholderBeanDefinitionParser extends AbstractPropertyLoadingBeanDefinitionParser {
@Override
protected Class<?> getBeanClass(Element element) {
//Use this class to implement beans
return org.springframework.beans.factory.config.PropertyPlaceholderConfigurer.class;
}
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
super.doParse(element, parserContext, builder);
//Ignore unresolved property
builder.addPropertyValue("ignoreUnresolvablePlaceholders",
Boolean.valueOf(element.getAttribute("ignore-unresolvable")));
//System properties mode property
String systemPropertiesModeName = element.getAttribute(SYSTEM_PROPERTIES_MODE_ATTRIBUTE);
if (StringUtils.hasLength(systemPropertiesModeName) &&
!systemPropertiesModeName.equals(SYSTEM_PROPERTIES_MODE_DEFAULT)) {
builder.addPropertyValue("systemPropertiesModeName", "SYSTEM_PROPERTIES_MODE_" + systemPropertiesModeName);
}
//Value separator attribute
if (element.hasAttribute("value-separator")) {
builder.addPropertyValue("valueSeparator", element.getAttribute("value-separator"));
}
//Trim values attribute
if (element.hasAttribute("trim-values")) {
builder.addPropertyValue("trimValues", element.getAttribute("trim-values"));
}
//Null value attribute
if (element.hasAttribute("null-value")) {
builder.addPropertyValue("nullValue", element.getAttribute("null-value"));
}
}
}
3.2. context:property-override
PropertyOverrideBeanDefinitionParser
The main function of is parsing<context:property-override/>
Element to specify the final result for the attributes of the bean in the XML configuration file
class PropertyOverrideBeanDefinitionParser extends AbstractPropertyLoadingBeanDefinitionParser {
@Override
protected Class<?> getBeanClass(Element element) {
//Use this class to implement beans
return PropertyOverrideConfigurer.class;
}
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
super.doParse(element, parserContext, builder);
//Ignore unresolved property
builder.addPropertyValue("ignoreInvalidKeys",
Boolean.valueOf(element.getAttribute("ignore-unresolvable")));
}
}
3.3. context:annotation-config
AnnotationConfigBeanDefinitionParser
The main function of is parsing<context:annotation-config/>
Element, using@Autowired
Auto assemble bean
public class AnnotationConfigBeanDefinitionParser implements BeanDefinitionParser {
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
Object source = parserContext.extractSource(element);
//Get all relevant bean definitions of registry
Set<BeanDefinitionHolder> processorDefinitions =
AnnotationConfigUtils.registerAnnotationConfigProcessors(parserContext.getRegistry(), source);
// ... Code omission
//Register bean definitions
for (BeanDefinitionHolder processorDefinition : processorDefinitions) {
parserContext.registerComponent(new BeanComponentDefinition(processorDefinition));
}
// ... Code omission
return null;
}
}
3.4. context:component-scan
ComponentScanBeanDefinitionParser
The main function of is parsing<context:component-scan/>
Element to automatically scan the annotation beans under the specified package
public class ComponentScanBeanDefinitionParser implements BeanDefinitionParser {
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
//Base package attribute
String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);
basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
//Separating multiple packages
String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
//Create and configure scanned objects
ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
//Scan components in package
Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
//Register components into context
registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
return null;
}
}
aboutcontext:
That’s all for the analysis of command space. Others who are interested can explore it by themselves
4. TaskNamespaceHandler
public class TaskNamespaceHandler extends NamespaceHandlerSupport {
@Override
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());
}
}
4.1. task:annotation-driven
AnnotationDrivenBeanDefinitionParser
The main function of is parsing<task:annotation-driven/>
Element, turn on the timer switch, and automatically scan the annotated timer in the program
public class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
Object source = parserContext.extractSource(element);
// ... Code omission
//Get registry
BeanDefinitionRegistry registry = parserContext.getRegistry();
//Mode attribute
String mode = element.getAttribute("mode");
//Use AspectJ to perform asynchronous tasks
if ("aspectj".equals(mode)) {
// mode="aspectj"
registerAsyncExecutionAspect(element, parserContext);
}
//Use built-in functions to perform asynchronous tasks
else {
//The bean "org. Springframework. Context. Annotation. Internalasyncannotationprocessor" already exists
if (registry.containsBeanDefinition(TaskManagementConfigUtils.ASYNC_ANNOTATION_PROCESSOR_BEAN_NAME)) {
// ... Code omission
}
else {
//Use the class "org. Springframework. Scheduling. Annotation. Asyncannotationbeanpostprocessor"
//To configure the bean "org. Springframework. Context. Annotation. Internalasyncannotationprocessor"
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(
"org.springframework.scheduling.annotation.AsyncAnnotationBeanPostProcessor");
builder.getRawBeanDefinition().setSource(source);
//Executor property
String executor = element.getAttribute("executor");
if (StringUtils.hasText(executor)) {
builder.addPropertyReference("executor", executor);
}
//Exception handler property
String exceptionHandler = element.getAttribute("exception-handler");
if (StringUtils.hasText(exceptionHandler)) {
builder.addPropertyReference("exceptionHandler", exceptionHandler);
}
//Proxy target class attribute
if (Boolean.parseBoolean(element.getAttribute(AopNamespaceUtils.PROXY_TARGET_CLASS_ATTRIBUTE))) {
builder.addPropertyValue("proxyTargetClass", true);
}
//Register components to registry and context
registerPostProcessor(parserContext, builder, TaskManagementConfigUtils.ASYNC_ANNOTATION_PROCESSOR_BEAN_NAME);
}
}
//The bean "org. Springframework. Context. Annotation. Internalscheduledannotationprocessor" already exists
if (registry.containsBeanDefinition(TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
// ... Code omission
}
else {
//Use the class "org. Springframework. Scheduling. Annotation. Scheduledannotationbeanpostprocessor"
//To configure the bean "org. Springframework. Context. Annotation. Internalscheduledannotationprocessor"
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(
"org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor");
builder.getRawBeanDefinition().setSource(source);
//Scheduler properties
String scheduler = element.getAttribute("scheduler");
if (StringUtils.hasText(scheduler)) {
builder.addPropertyReference("scheduler", scheduler);
}
//Register components to registry and context
registerPostProcessor(parserContext, builder, TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME);
}
// ... Code omission
return null;
}
//Use AspectJ to perform asynchronous tasks
private void registerAsyncExecutionAspect(Element element, ParserContext parserContext) {
//The bean "org. Springframework. Scheduling. Config. Internalasyncexecutionaspect" does not exist
if (!parserContext.getRegistry().containsBeanDefinition(TaskManagementConfigUtils.ASYNC_EXECUTION_ASPECT_BEAN_NAME)) {
//Use the class "org. Springframework. Scheduling. AspectJ. Annotationasyncexecutionaspect"
//To configure the bean "org. Springframework. Scheduling. Config. Internalasyncexecutionaspect"
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(ASYNC_EXECUTION_ASPECT_CLASS_NAME);
//Use factorymethod to initialize the bean
builder.setFactoryMethod("aspectOf");
//Executor property
String executor = element.getAttribute("executor");
if (StringUtils.hasText(executor)) {
builder.addPropertyReference("executor", executor);
}
//Exception handler property
String exceptionHandler = element.getAttribute("exception-handler");
if (StringUtils.hasText(exceptionHandler)) {
builder.addPropertyReference("exceptionHandler", exceptionHandler);
}
//Register bean
parserContext.registerBeanComponent(new BeanComponentDefinition(builder.getBeanDefinition(),
TaskManagementConfigUtils.ASYNC_EXECUTION_ASPECT_BEAN_NAME));
}
}
}
4.2. task:executor
ExecutorBeanDefinitionParser
The main function of is parsing<task:executor/>
Element to configure the task executor
public class ExecutorBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
@Override
protected String getBeanClassName(Element element) {
//Use this class to implement beans
return "org.springframework.scheduling.config.TaskExecutorFactoryBean";
}
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
//Keep alive attribute
String keepAliveSeconds = element.getAttribute("keep-alive");
if (StringUtils.hasText(keepAliveSeconds)) {
builder.addPropertyValue("keepAliveSeconds", keepAliveSeconds);
}
//Queue capacity attribute
String queueCapacity = element.getAttribute("queue-capacity");
if (StringUtils.hasText(queueCapacity)) {
builder.addPropertyValue("queueCapacity", queueCapacity);
}
//Configuration policy
configureRejectionPolicy(element, builder);
//Pool size attribute
String poolSize = element.getAttribute("pool-size");
if (StringUtils.hasText(poolSize)) {
builder.addPropertyValue("poolSize", poolSize);
}
}
//Configuration policy
private void configureRejectionPolicy(Element element, BeanDefinitionBuilder builder) {
//Rejection policy property
String rejectionPolicy = element.getAttribute("rejection-policy");
if (!StringUtils.hasText(rejectionPolicy)) {
return;
}
String prefix = "java.util.concurrent.ThreadPoolExecutor.";
String policyClassName;
if (rejectionPolicy.equals("ABORT")) {
policyClassName = prefix + "AbortPolicy";
}
else if (rejectionPolicy.equals("CALLER_RUNS")) {
policyClassName = prefix + "CallerRunsPolicy";
}
else if (rejectionPolicy.equals("DISCARD")) {
policyClassName = prefix + "DiscardPolicy";
}
else if (rejectionPolicy.equals("DISCARD_OLDEST")) {
policyClassName = prefix + "DiscardOldestPolicy";
}
else {
policyClassName = rejectionPolicy;
}
builder.addPropertyValue("rejectedExecutionHandler", new RootBeanDefinition(policyClassName));
}
}
4.3. task:scheduled-tasks
ScheduledTasksBeanDefinitionParser
The main function of is parsing<task:scheduled-tasks/>
Element to execute timer tasks
public class ScheduledTasksBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
@Override
protected String getBeanClassName(Element element) {
//Use this class to implement beans
return "org.springframework.scheduling.config.ContextLifecycleScheduledTaskRegistrar";
}
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
//Cron task
ManagedList<RuntimeBeanReference> cronTaskList = new ManagedList<>();
//Fixed delay task
ManagedList<RuntimeBeanReference> fixedDelayTaskList = new ManagedList<>();
//Fixed frequency task
ManagedList<RuntimeBeanReference> fixedRateTaskList = new ManagedList<>();
//Trigger task
ManagedList<RuntimeBeanReference> triggerTaskList = new ManagedList<>();
//Traversal of child elements
NodeList childNodes = element.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
Node child = childNodes.item(i);
Element taskElement = (Element) child;
//Ref attribute
String ref = taskElement.getAttribute("ref");
//Method property
String method = taskElement.getAttribute("method");
// ... Code omission
//Cron attribute
String cronAttribute = taskElement.getAttribute("cron");
//Fixed delay attribute
String fixedDelayAttribute = taskElement.getAttribute("fixed-delay");
//Fixed rate attribute
String fixedRateAttribute = taskElement.getAttribute("fixed-rate");
//Trigger attribute
String triggerAttribute = taskElement.getAttribute("trigger");
//Initial delay attribute
String initialDelayAttribute = taskElement.getAttribute("initial-delay");
boolean hasCronAttribute = StringUtils.hasText(cronAttribute);
boolean hasFixedDelayAttribute = StringUtils.hasText(fixedDelayAttribute);
boolean hasFixedRateAttribute = StringUtils.hasText(fixedRateAttribute);
boolean hasTriggerAttribute = StringUtils.hasText(triggerAttribute);
boolean hasInitialDelayAttribute = StringUtils.hasText(initialDelayAttribute);
// ... Code omission
//Use the class "org. Springframework. Scheduling. Support. Scheduledmethodrunnable"
//Instantiate timer bean
String runnableName =
runnableReference(ref, method, taskElement, parserContext).getBeanName();
if (hasFixedDelayAttribute) {
//Use the class "org. Springframework. Scheduling. Config. Intervaltask"
//Instantiate fixed delay executor bean
fixedDelayTaskList.add(intervalTaskReference(runnableName,
initialDelayAttribute, fixedDelayAttribute, taskElement, parserContext));
}
if (hasFixedRateAttribute) {
//Use the class "org. Springframework. Scheduling. Config. Intervaltask"
//Instantiate fixed frequency actuator bean
fixedRateTaskList.add(intervalTaskReference(runnableName,
initialDelayAttribute, fixedRateAttribute, taskElement, parserContext));
}
if (hasCronAttribute) {
//Use the class "org. Springframework. Scheduling. Config. Crontask"
//Instantiate cron executor bean
cronTaskList.add(cronTaskReference(runnableName, cronAttribute,
taskElement, parserContext));
}
if (hasTriggerAttribute) {
//Use the class "org. Springframework. Scheduling. Config. Triggertask"
//Instantiate trigger executor bean
String triggerName = new RuntimeBeanReference(triggerAttribute).getBeanName();
triggerTaskList.add(triggerTaskReference(runnableName, triggerName,
taskElement, parserContext));
}
}
//Scheduler properties
String schedulerRef = element.getAttribute("scheduler");
if (StringUtils.hasText(schedulerRef)) {
builder.addPropertyReference("taskScheduler", schedulerRef);
}
builder.addPropertyValue("cronTasksList", cronTaskList);
builder.addPropertyValue("fixedDelayTasksList", fixedDelayTaskList);
builder.addPropertyValue("fixedRateTasksList", fixedRateTaskList);
builder.addPropertyValue("triggerTasksList", triggerTaskList);
}
}
4.4. task:scheduler
SchedulerBeanDefinitionParser
The main function of is parsing<task:scheduler/>
Element to configure the scheduling thread pool
public class SchedulerBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
@Override
protected String getBeanClassName(Element element) {
//Use this class to implement beans
return "org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler";
}
@Override
protected void doParse(Element element, BeanDefinitionBuilder builder) {
//Pool size attribute
String poolSize = element.getAttribute("pool-size");
if (StringUtils.hasText(poolSize)) {
builder.addPropertyValue("poolSize", poolSize);
}
}
}
5. CacheNamespaceHandler
public class CacheNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenCacheBeanDefinitionParser());
registerBeanDefinitionParser("advice", new CacheAdviceParser());
}
}
5.1. cache:annotation-driven
AnnotationDrivenCacheBeanDefinitionParser
The main function of is parsing<cache:annotation-driven/>
Element, supporting annotation@Cacheable
、@CacheEvict
、@CacheUpdate
class AnnotationDrivenCacheBeanDefinitionParser implements BeanDefinitionParser {
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
//Mode attribute
String mode = element.getAttribute("mode");
//Use AspectJ to execute
if ("aspectj".equals(mode)) {
registerCacheAspect(element, parserContext);
}
//Use built-in functions to perform
else {
registerCacheAdvisor(element, parserContext);
}
return null;
}
//Use AspectJ to execute
private void registerCacheAspect(Element element, ParserContext parserContext) {
SpringCachingConfigurer.registerCacheAspect(element, parserContext);
}
//Use built-in functions to perform
private void registerCacheAdvisor(Element element, ParserContext parserContext) {
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
SpringCachingConfigurer.registerCacheAdvisor(element, parserContext);
}
//Resolve cache resolver attribute
private static void parseCacheResolution(Element element, BeanDefinition def, boolean setBoth) {
String name = element.getAttribute("cache-resolver");
boolean hasText = StringUtils.hasText(name);
if (hasText) {
def.getPropertyValues().add("cacheResolver", new RuntimeBeanReference(name.trim()));
}
if (!hasText || setBoth) {
def.getPropertyValues().add("cacheManager",
new RuntimeBeanReference(CacheNamespaceHandler.extractCacheManager(element)));
}
}
}
Inner classJCacheCachingConfigurer
private static class JCacheCachingConfigurer {
//Use built-in functions to perform
private static void registerCacheAdvisor(Element element, ParserContext parserContext) {
//The bean "org. Springframework. Cache. Config. Internaljcacheadvisor" does not exist
if (!parserContext.getRegistry().containsBeanDefinition(CacheManagementConfigUtils.JCACHE_ADVISOR_BEAN_NAME)) {
Object source = parserContext.extractSource(element);
//Create a bean executed by jcache
BeanDefinition sourceDef = createJCacheOperationSourceBeanDefinition(element, source);
//Get bean name
String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);
//Use "org. Springframework. Cache. Jcache. Interceptor. Jcacheinterceptor"
//Create bean definition of cacheinterceptor
RootBeanDefinition interceptorDef =
new RootBeanDefinition("org.springframework.cache.jcache.interceptor.JCacheInterceptor");
// ... Code omission
//Get bean name
String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);
//Use "org.springframework.cache.jcache.interceptor.beanfactoryjcacheoperationsourceadvisor"
//Create cacheadvisor definition
RootBeanDefinition advisorDef = new RootBeanDefinition(
"org.springframework.cache.jcache.interceptor.BeanFactoryJCacheOperationSourceAdvisor");
// ... Code omission
//Register the bean "org. Springframework. Cache. Config. Internaljcacheadvisor"
parserContext.getRegistry().registerBeanDefinition(CacheManagementConfigUtils.JCACHE_ADVISOR_BEAN_NAME, advisorDef);
//Register composite bean sourcedef + interceptordef + advisordef
CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), source);
compositeDef.addNestedComponent(new BeanComponentDefinition(sourceDef, sourceName));
compositeDef.addNestedComponent(new BeanComponentDefinition(interceptorDef, interceptorName));
compositeDef.addNestedComponent(new BeanComponentDefinition(advisorDef, CacheManagementConfigUtils.JCACHE_ADVISOR_BEAN_NAME));
parserContext.registerComponent(compositeDef);
}
}
//Use AspectJ to execute
private static void registerCacheAspect(Element element, ParserContext parserContext) {
//The bean "org. Springframework. Cache. Config. Internaljcacheaspect" does not exist
if (!parserContext.getRegistry().containsBeanDefinition(CacheManagementConfigUtils.JCACHE_ASPECT_BEAN_NAME)) {
Object eleSource = parserContext.extractSource(element);
RootBeanDefinition def = new RootBeanDefinition();
//Use "org. Springframework. Cache. AspectJ. Jcachecacheaspect"
//To create a bean
def.setBeanClassName(JCACHE_ASPECT_CLASS_NAME);
//Use factorymethod to initialize the bean
def.setFactoryMethodName("aspectOf");
//Create a bean executed by jcache
BeanDefinition sourceDef = createJCacheOperationSourceBeanDefinition(element, eleSource);
String sourceName =
parserContext.getReaderContext().registerWithGeneratedName(sourceDef);
//Register the bean "org. Springframework. Cache. Jcache. Interceptor. Defaultjcacheoperationsource"
parserContext.registerBeanComponent(new BeanComponentDefinition(sourceDef, sourceName));
//Register the bean "org. Springframework. Cache. Config. Internaljcacheaspect"
parserContext.registerBeanComponent(new BeanComponentDefinition(def, CacheManagementConfigUtils.JCACHE_ASPECT_BEAN_NAME));
}
}
//Create a bean executed by jcache
private static RootBeanDefinition createJCacheOperationSourceBeanDefinition(Element element, @Nullable Object eleSource) {
//Use "org. Springframework. Cache. Jcache. Interceptor. Defaultjcacheoperationsource"“
//To create a bean
RootBeanDefinition sourceDef =
new RootBeanDefinition("org.springframework.cache.jcache.interceptor.DefaultJCacheOperationSource");
// ... Code omission
//Resolve cache resolver attribute
CacheNamespaceHandler.parseKeyGenerator(element, sourceDef);
return sourceDef;
}
}
5.2. cache:advice
CacheAdviceParser
The main function of is parsing<cache:advice/>
Element, configuring cache
class CacheAdviceParser extends AbstractSingleBeanDefinitionParser {
@Override
protected Class<?> getBeanClass(Element element) {
//Use this class to implement beans
return CacheInterceptor.class;
}
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
//Cache manager attribute
builder.addPropertyReference("cacheManager", CacheNamespaceHandler.extractCacheManager(element));
//Caching element
List<Element> cacheDefs = DomUtils.getChildElementsByTagName(element, DEFS_ELEMENT);
//There is a caching element
if (!cacheDefs.isEmpty()) {
//Convert caching elements into beans
List<RootBeanDefinition> attributeSourceDefinitions = parseDefinitionsSources(cacheDefs, parserContext);
builder.addPropertyValue("cacheOperationSources", attributeSourceDefinitions);
}
else {
//If there is no caching element, use "org. Springframework. Cache. Annotation. Annotationcacheoperationsource"
//Create a default bean
builder.addPropertyValue("cacheOperationSources",
new RootBeanDefinition("org.springframework.cache.annotation.AnnotationCacheOperationSource"));
}
}
//Convert caching elements into beans
private List<RootBeanDefinition> parseDefinitionsSources(List<Element> definitions, ParserContext parserContext) {
ManagedList<RootBeanDefinition> defs = new ManagedList<>(definitions.size());
//Traversal
for (Element element : definitions) {
defs.add(parseDefinitionSource(element, parserContext));
}
return defs;
}
//Convert caching elements into beans
private RootBeanDefinition parseDefinitionSource(Element definition, ParserContext parserContext) {
// ... Code omission
}
}
6. MvcNamespaceHandler
public class MvcNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
registerBeanDefinitionParser("default-servlet-handler", new DefaultServletHandlerBeanDefinitionParser());
registerBeanDefinitionParser("interceptors", new InterceptorsBeanDefinitionParser());
registerBeanDefinitionParser("resources", new ResourcesBeanDefinitionParser());
registerBeanDefinitionParser("view-controller", new ViewControllerBeanDefinitionParser());
registerBeanDefinitionParser("redirect-view-controller", new ViewControllerBeanDefinitionParser());
registerBeanDefinitionParser("status-controller", new ViewControllerBeanDefinitionParser());
registerBeanDefinitionParser("view-resolvers", new ViewResolversBeanDefinitionParser());
registerBeanDefinitionParser("tiles-configurer", new TilesConfigurerBeanDefinitionParser());
registerBeanDefinitionParser("freemarker-configurer", new FreeMarkerConfigurerBeanDefinitionParser());
registerBeanDefinitionParser("groovy-configurer", new GroovyMarkupConfigurerBeanDefinitionParser());
registerBeanDefinitionParser("script-template-configurer", new ScriptTemplateConfigurerBeanDefinitionParser());
registerBeanDefinitionParser("cors", new CorsBeanDefinitionParser());
}
}
mvc
There are many processors in the namespace. Only the first one is resolved heremvc:annotation-driven
, others who are interested can explore by themselves
AnnotationDrivenBeanDefinitionParser
The main function of is parsing<mvc:annotation-driven/>
Element, enable annotation driven, throughcontext:component-scan
Label configuration, automatic scanning@Component,@Controller,@Service,@Repository
Components marked with annotations are registered in the factory to process the request
class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
@Override
public BeanDefinition parse(Element element, ParserContext context) {
//Meta information
Object source = context.extractSource(element);
XmlReaderContext readerContext = context.getReaderContext();
// ... Code omission
//Request mapping processor bean
RootBeanDefinition handlerMappingDef = new RootBeanDefinition(RequestMappingHandlerMapping.class);
// ... Code omission
//Enable matrix variables property
if (element.hasAttribute("enable-matrix-variables")) {
boolean enableMatrixVariables = Boolean.parseBoolean(element.getAttribute("enable-matrix-variables"));
handlerMappingDef.getPropertyValues().add("removeSemicolonContent", !enableMatrixVariables);
}
//Configure path mapping
configurePathMatchingProperties(handlerMappingDef, element, context);
//Register requestmappinghandlermapping class bean
readerContext.getRegistry().registerBeanDefinition(HANDLER_MAPPING_BEAN_NAME, handlerMappingDef);
// ... Code omission
//Get data conversion service
RuntimeBeanReference conversionService = getConversionService(element, source, context);
//Get validator
RuntimeBeanReference validator = getValidator(element, source, context);
//Get text parser
RuntimeBeanReference messageCodesResolver = getMessageCodesResolver(element);
//Register webinitializebindizer.webinitializer class bean
RootBeanDefinition bindingDef = new RootBeanDefinition(ConfigurableWebBindingInitializer.class);
// ... Code omission
//Load conversionservice, validator, messagecodesresolver
bindingDef.getPropertyValues().add("conversionService", conversionService);
bindingDef.getPropertyValues().add("validator", validator);
bindingDef.getPropertyValues().add("messageCodesResolver", messageCodesResolver);
//Configure message converter
ManagedList<?> messageConverters = getMessageConverters(element, source, context);
//Custom parameter resolver configured by argument resolvers sub element
ManagedList<?> argumentResolvers = getArgumentResolvers(element, context);
//Custom response parser configured by return value handlers sub element
ManagedList<?> returnValueHandlers = getReturnValueHandlers(element, context);
//Asynchronous task timeout configured by async support sub element
String asyncTimeout = getAsyncTimeout(element);
//Asynchronous task executor configured by async support sub element
RuntimeBeanReference asyncExecutor = getAsyncExecutor(element);
//Callable interceptors request interceptor configured by async support sub element
ManagedList<?> callableInterceptors = getInterceptors(element, source, context, "callable-interceptors");
//Deferred result interceptors response interceptor configured by async support sub element
ManagedList<?> deferredResultInterceptors = getInterceptors(element, source, context, "deferred-result-interceptors");
//Register requestmappinghandleradapter class bean
RootBeanDefinition handlerAdapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
//Load contentnegotiationmanager, bindingdef, messageconverters
handlerAdapterDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);
handlerAdapterDef.getPropertyValues().add("webBindingInitializer", bindingDef);
handlerAdapterDef.getPropertyValues().add("messageConverters", messageConverters);
//Load Jackson request processing
addRequestBodyAdvice(handlerAdapterDef);
//Loading Jackson response processing
addResponseBodyAdvice(handlerAdapterDef);
//Ignore default model on redirect attribute
if (element.hasAttribute("ignore-default-model-on-redirect")) {
Boolean ignoreDefaultModel = Boolean.valueOf(element.getAttribute("ignore-default-model-on-redirect"));
handlerAdapterDef.getPropertyValues().add("ignoreDefaultModelOnRedirect", ignoreDefaultModel);
}
if (argumentResolvers != null) {
handlerAdapterDef.getPropertyValues().add("customArgumentResolvers", argumentResolvers);
}
if (returnValueHandlers != null) {
handlerAdapterDef.getPropertyValues().add("customReturnValueHandlers", returnValueHandlers);
}
if (asyncTimeout != null) {
handlerAdapterDef.getPropertyValues().add("asyncRequestTimeout", asyncTimeout);
}
if (asyncExecutor != null) {
handlerAdapterDef.getPropertyValues().add("taskExecutor", asyncExecutor);
}
handlerAdapterDef.getPropertyValues().add("callableInterceptors", callableInterceptors);
handlerAdapterDef.getPropertyValues().add("deferredResultInterceptors", deferredResultInterceptors);
//Register requestmappinghandleradapter class bean
readerContext.getRegistry().registerBeanDefinition(HANDLER_ADAPTER_BEAN_NAME, handlerAdapterDef);
//Register compositeuricomponentscontributorfactorybean class bean
RootBeanDefinition uriContributorDef =
new RootBeanDefinition(CompositeUriComponentsContributorFactoryBean.class);
uriContributorDef.setSource(source);
uriContributorDef.getPropertyValues().addPropertyValue("handlerAdapter", handlerAdapterDef);
uriContributorDef.getPropertyValues().addPropertyValue("conversionService", conversionService);
//Register mvcuricomponentscontributor bean
String uriContributorName = MvcUriComponentsBuilder.MVC_URI_COMPONENTS_CONTRIBUTOR_BEAN_NAME;
readerContext.getRegistry().registerBeanDefinition(uriContributorName, uriContributorDef);
//Register conversionserviceexposinginterceptor class bean
RootBeanDefinition csInterceptorDef = new RootBeanDefinition(ConversionServiceExposingInterceptor.class);
csInterceptorDef.setSource(source);
csInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, conversionService);
//Register mappedinterceptor class bean
RootBeanDefinition mappedInterceptorDef = new RootBeanDefinition(MappedInterceptor.class);
// ... Code omission
//Register exceptionhandlerexceptionresolver class bean
RootBeanDefinition methodExceptionResolver = new RootBeanDefinition(ExceptionHandlerExceptionResolver.class);
// ... Code omission
//Register responsestatusexceptionresolver class bean
RootBeanDefinition statusExceptionResolver = new RootBeanDefinition(ResponseStatusExceptionResolver.class);
// ... Code omission
//Register defaulthandlerexceptionresolver class bean
RootBeanDefinition defaultExceptionResolver = new RootBeanDefinition(DefaultHandlerExceptionResolver.class);
// ... Code omission
//Register a series of beans
context.registerComponent(new BeanComponentDefinition(handlerMappingDef, HANDLER_MAPPING_BEAN_NAME));
context.registerComponent(new BeanComponentDefinition(handlerAdapterDef, HANDLER_ADAPTER_BEAN_NAME));
context.registerComponent(new BeanComponentDefinition(uriContributorDef, uriContributorName));
context.registerComponent(new BeanComponentDefinition(mappedInterceptorDef, mappedInterceptorName));
context.registerComponent(new BeanComponentDefinition(methodExceptionResolver, methodExResolverName));
context.registerComponent(new BeanComponentDefinition(statusExceptionResolver, statusExResolverName));
context.registerComponent(new BeanComponentDefinition(defaultExceptionResolver, defaultExResolverName));
// ... Code omission
context.popAndRegisterContainingComponent();
return null;
}
}
class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
//Configure path mapping
private void configurePathMatchingProperties(
RootBeanDefinition handlerMappingDef, Element element, ParserContext context) {
//Get path matching child element
Element pathMatchingElement = DomUtils.getChildElementByTagName(element, "path-matching");
if (pathMatchingElement != null) {
Object source = context.extractSource(element);
//Suffix pattern attribute
if (pathMatchingElement.hasAttribute("suffix-pattern")) {
Boolean useSuffixPatternMatch = Boolean.valueOf(pathMatchingElement.getAttribute("suffix-pattern"));
handlerMappingDef.getPropertyValues().add("useSuffixPatternMatch", useSuffixPatternMatch);
}
//Trailing slash property
if (pathMatchingElement.hasAttribute("trailing-slash")) {
Boolean useTrailingSlashMatch = Boolean.valueOf(pathMatchingElement.getAttribute("trailing-slash"));
handlerMappingDef.getPropertyValues().add("useTrailingSlashMatch", useTrailingSlashMatch);
}
//Registered suffixes only attribute
if (pathMatchingElement.hasAttribute("registered-suffixes-only")) {
Boolean useRegisteredSuffixPatternMatch = Boolean.valueOf(pathMatchingElement.getAttribute("registered-suffixes-only"));
handlerMappingDef.getPropertyValues().add("useRegisteredSuffixPatternMatch", useRegisteredSuffixPatternMatch);
}
RuntimeBeanReference pathHelperRef = null;
//Path helper attribute
if (pathMatchingElement.hasAttribute("path-helper")) {
pathHelperRef = new RuntimeBeanReference(pathMatchingElement.getAttribute("path-helper"));
}
pathHelperRef = MvcNamespaceUtils.registerUrlPathHelper(pathHelperRef, context, source);
handlerMappingDef.getPropertyValues().add("urlPathHelper", pathHelperRef);
RuntimeBeanReference pathMatcherRef = null;
//Path matcher attribute
if (pathMatchingElement.hasAttribute("path-matcher")) {
pathMatcherRef = new RuntimeBeanReference(pathMatchingElement.getAttribute("path-matcher"));
}
pathMatcherRef = MvcNamespaceUtils.registerPathMatcher(pathMatcherRef, context, source);
handlerMappingDef.getPropertyValues().add("pathMatcher", pathMatcherRef);
}
}
//Get data conversion service
private RuntimeBeanReference getConversionService(Element element, @Nullable Object source, ParserContext context) {
RuntimeBeanReference conversionServiceRef;
//The conversion service attribute is configured
if (element.hasAttribute("conversion-service")) {
conversionServiceRef = new RuntimeBeanReference(element.getAttribute("conversion-service"));
}
else {
//If not, create a default with formattingconversionservicefactorybean
RootBeanDefinition conversionDef = new RootBeanDefinition(FormattingConversionServiceFactoryBean.class);
// ... Code omission
conversionServiceRef = new RuntimeBeanReference(conversionName);
}
return conversionServiceRef;
}
//Get validator
private RuntimeBeanReference getValidator(Element element, @Nullable Object source, ParserContext context) {
//Validator attribute is configured
if (element.hasAttribute("validator")) {
return new RuntimeBeanReference(element.getAttribute("validator"));
}
else if (javaxValidationPresent) {
//If not, create a default with optionalvalidatorfactorybean
RootBeanDefinition validatorDef = new RootBeanDefinition(
"org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean");
// ... Code omission
return new RuntimeBeanReference(validatorName);
}
else {
return null;
}
}
//Get text parser
private RuntimeBeanReference getMessageCodesResolver(Element element) {
//The message codes resolver attribute is configured
if (element.hasAttribute("message-codes-resolver")) {
return new RuntimeBeanReference(element.getAttribute("message-codes-resolver"));
}
else {
return null;
}
}
}
class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
//Configure message converter
private ManagedList<?> getMessageConverters(Element element, @Nullable Object source, ParserContext context) {
//Message converters child element
Element convertersElement = DomUtils.getChildElementByTagName(element, "message-converters");
//Result set
ManagedList<Object> messageConverters = new ManagedList<>();
//There are message converters child elements
if (convertersElement != null) {
//Convert the bean and ref sub elements into beans and add them to the result set
for (Element beanElement : DomUtils.getChildElementsByTagName(convertersElement, "bean", "ref")) {
Object object = context.getDelegate().parsePropertySubElement(beanElement, null);
messageConverters.add(object);
}
}
//There are message converters child elements,但有register-defaults属性
if (convertersElement == null || Boolean.parseBoolean(convertersElement.getAttribute("register-defaults"))) {
//Add bytearrayhttpmessageconverter Class bean to result set
//Byte array converter
messageConverters.add(createConverterDefinition(ByteArrayHttpMessageConverter.class, source));
//Add stringhttpmessageconverter Class bean to result set
//Character converter
RootBeanDefinition stringConverterDef = createConverterDefinition(StringHttpMessageConverter.class, source);
stringConverterDef.getPropertyValues().add("writeAcceptCharset", false);
messageConverters.add(stringConverterDef);
//Add resourcehttpmessageconverter Class bean to result set
//Resource converter
messageConverters.add(createConverterDefinition(ResourceHttpMessageConverter.class, source));
//Add resourceregionhttpmessageconverter Class bean to result set
//Resource area converter
messageConverters.add(createConverterDefinition(ResourceRegionHttpMessageConverter.class, source));
//Add sourcehttpmessageconverter Class bean to result set
// javax. xml. transform. Source converter
messageConverters.add(createConverterDefinition(SourceHttpMessageConverter.class, source));
//Add allencompassingformhttpmessageconverter Class bean to result set
//Form data converter
messageConverters.add(createConverterDefinition(AllEncompassingFormHttpMessageConverter.class, source));
// ... Code omission
if (jackson2XmlPresent) {
//Add jackson2xml converter
}
// ... Code omission
if (jackson2Present) {
//Add jackson2 converter
}
else if (gsonPresent) {
//Add gson converter
}
// ... Code omission
}
return messageConverters;
}
}
follow-up
More blogs, seehttps://github.com/senntyou/blogs
Author:Deep (@ senntyou)
Copyright notice: free reproduction – non commercial – non derivative – keep signature(Creative sharing 3.0 License)