- 使用 Spring Initializr 创建 Spring Boot 应用程序
- 在Spring Boot中配置Cassandra
- 在 Spring Boot 上配置 Tomcat 连接池
- 将Camel消息路由到嵌入WildFly的Artemis上
在 Spring 源码解析五:Bean 的配置、定义、注册 中,有一些 Xml 配置中默认的命名空间处理器还未解析
这里只解析常用的几个
SimpleConstructorNamespaceHandler
SimplePropertyNamespaceHandler
ContextNamespaceHandler
TaskNamespaceHandler
CacheNamespaceHandler
MvcNamespaceHandler
其他的有兴趣可以自行探索
SimpleConstructorNamespaceHandler
的主要功能是在实例化如下配置的 bean
<bean id="author" class="..TestBean" c:name="Enescu" c:work-ref="compositions"/>
将 name="Enescu", work=bean[compositions]
作为构造函数的参数实例化 bean
public class SimpleConstructorNamespaceHandler implements NamespaceHandler {
@Override
public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) {
if (node instanceof Attr) {
Attr attr = (Attr) node;
// 去除两边空白
String argName = StringUtils.trimWhitespace(parserContext.getDelegate().getLocalName(attr));
// 去除两边空白
String argValue = StringUtils.trimWhitespace(attr.getValue());
// 构造函数参数集合
ConstructorArgumentValues cvs = definition.getBeanDefinition().getConstructorArgumentValues();
boolean ref = false;
// 如果字段名以"-ref"结果,则表示在运行时对其他bean的引用
if (argName.endsWith(REF_SUFFIX)) {
ref = true;
argName = argName.substring(0, argName.length() - REF_SUFFIX.length());
}
// 用ValueHolder封装值
ValueHolder valueHolder = new ValueHolder(ref ? new RuntimeBeanReference(argValue) : argValue);
valueHolder.setSource(parserContext.getReaderContext().extractSource(attr));
// 以"_"开头的,表示是没有名字的参数,按照顺序传入就可以了
if (argName.startsWith(DELIMITER_PREFIX)) {
String arg = argName.substring(1).trim();
// 如果没有指定顺序,直接添加
if (!StringUtils.hasText(arg)) {
cvs.addGenericArgumentValue(valueHolder);
}
// 如果有指定顺序,指定顺序添加
else {
int index = -1;
try {
index = Integer.parseInt(arg);
}
catch (NumberFormatException ex) {
// ... 代码省略
}
// ... 代码省略
// 添加进cvs
cvs.addIndexedArgumentValue(index, valueHolder);
}
}
// 有名字的参数
else {
// ... 代码省略
// 添加进cvs
valueHolder.setName(Conventions.attributeNameToPropertyName(argName));
cvs.addGenericArgumentValue(valueHolder);
}
}
return definition;
}
}
SimplePropertyNamespaceHandler
的主要功能是在实例化如下配置的 bean
<bean id="rob" class="..TestBean" p:name="Rob Harrop" p:spouse-ref="sally"/>
将 name="Rob Harrop", spouse=bean[sally]
作为属性注入到 bean 中
public class SimplePropertyNamespaceHandler implements NamespaceHandler {
@Override
public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) {
if (node instanceof Attr) {
Attr attr = (Attr) node;
// 属性名
String propertyName = parserContext.getDelegate().getLocalName(attr);
// 属性值
String propertyValue = attr.getValue();
// 属性集合
MutablePropertyValues pvs = definition.getBeanDefinition().getPropertyValues();
// 如果字段名以"-ref"结果,则表示在运行时对其他bean的引用
if (propertyName.endsWith(REF_SUFFIX)) {
propertyName = propertyName.substring(0, propertyName.length() - REF_SUFFIX.length());
// 把字段名从短横线-或下划线_式的,转化为驼峰式的
pvs.add(Conventions.attributeNameToPropertyName(propertyName), new RuntimeBeanReference(propertyValue));
}
else {
// 把字段名从短横线-或下划线_式的,转化为驼峰式的
pvs.add(Conventions.attributeNameToPropertyName(propertyName), propertyValue);
}
}
return definition;
}
}
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());
}
}
PropertyPlaceholderBeanDefinitionParser
的主要功能是解析<context:property-placeholder/>
元素,在 bean 定义时,使用 ${}
引用外部来源的属性
先看看继承关系
- AbstractBeanDefinitionParser
- AbstractSingleBeanDefinitionParser
- AbstractPropertyLoadingBeanDefinitionParser
- PropertyPlaceholderBeanDefinitionParser
AbstractBeanDefinitionParser
的主要功能是实现了 BeanDefinitionParser
接口的 parse
方法,提供了基本的由配置解析为对象的功能
public abstract class AbstractBeanDefinitionParser implements BeanDefinitionParser {
@Override
public final BeanDefinition parse(Element element, ParserContext parserContext) {
// 解析元素
AbstractBeanDefinition definition = parseInternal(element, parserContext);
try {
// 获取bean的id
String id = resolveId(element, definition, parserContext);
String[] aliases = null;
// 获取name属性,用逗号分隔为多个别名
if (shouldParseNameAsAliases()) {
String name = element.getAttribute(NAME_ATTRIBUTE);
if (StringUtils.hasLength(name)) {
aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name));
}
}
// 封装为BeanDefinitionHolder
BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases);
// 注册到registry中
registerBeanDefinition(holder, parserContext.getRegistry());
// ... 代码省略
}
catch (BeanDefinitionStoreException ex) {
// ... 代码省略
}
return definition;
}
// 解析元素,由子类实现
protected abstract AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext);
// 获取bean的id,先获取id属性,其次name属性,都没有,生成默认的名字
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext)
throws BeanDefinitionStoreException {
// ... 代码省略
}
}
AbstractSingleBeanDefinitionParser
的主要功能是支持解析为单例的 bean
public abstract class AbstractSingleBeanDefinitionParser extends AbstractBeanDefinitionParser {
@Override
protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
// 创建一个构造器
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
// 父元素
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);
}
}
// ... 代码省略
// 解析到构造器
doParse(element, parserContext, builder);
return builder.getBeanDefinition();
}
// 解析到构造器,由子类实现
protected void doParse(Element element, BeanDefinitionBuilder builder) {}
}
AbstractPropertyLoadingBeanDefinitionParser
的主要功能是解析context:property-...
元素
abstract class AbstractPropertyLoadingBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
// location属性
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属性
String propertiesRef = element.getAttribute("properties-ref");
if (StringUtils.hasLength(propertiesRef)) {
builder.addPropertyReference("properties", propertiesRef);
}
// file-encoding属性
String fileEncoding = element.getAttribute("file-encoding");
if (StringUtils.hasLength(fileEncoding)) {
builder.addPropertyValue("fileEncoding", fileEncoding);
}
// order属性
String order = element.getAttribute("order");
if (StringUtils.hasLength(order)) {
builder.addPropertyValue("order", Integer.valueOf(order));
}
// ignore-resource-not-found属性
builder.addPropertyValue("ignoreResourceNotFound",
Boolean.valueOf(element.getAttribute("ignore-resource-not-found")));
// local-override属性
builder.addPropertyValue("localOverride",
Boolean.valueOf(element.getAttribute("local-override")));
}
}
PropertyPlaceholderBeanDefinitionParser
的主要功能是解析context:property-placeholder
元素
class PropertyPlaceholderBeanDefinitionParser extends AbstractPropertyLoadingBeanDefinitionParser {
@Override
protected Class<?> getBeanClass(Element element) {
// 使用这个类来实现bean
return org.springframework.beans.factory.config.PropertyPlaceholderConfigurer.class;
}
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
super.doParse(element, parserContext, builder);
// ignore-unresolvable属性
builder.addPropertyValue("ignoreUnresolvablePlaceholders",
Boolean.valueOf(element.getAttribute("ignore-unresolvable")));
// system-properties-mode属性
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属性
if (element.hasAttribute("value-separator")) {
builder.addPropertyValue("valueSeparator", element.getAttribute("value-separator"));
}
// trim-values属性
if (element.hasAttribute("trim-values")) {
builder.addPropertyValue("trimValues", element.getAttribute("trim-values"));
}
// null-value属性
if (element.hasAttribute("null-value")) {
builder.addPropertyValue("nullValue", element.getAttribute("null-value"));
}
}
}
PropertyOverrideBeanDefinitionParser
的主要功能是解析<context:property-override/>
元素,为 xml 配置文件中的 bean 的属性指定最终结果
class PropertyOverrideBeanDefinitionParser extends AbstractPropertyLoadingBeanDefinitionParser {
@Override
protected Class<?> getBeanClass(Element element) {
// 使用这个类来实现bean
return PropertyOverrideConfigurer.class;
}
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
super.doParse(element, parserContext, builder);
// ignore-unresolvable属性
builder.addPropertyValue("ignoreInvalidKeys",
Boolean.valueOf(element.getAttribute("ignore-unresolvable")));
}
}
AnnotationConfigBeanDefinitionParser
的主要功能是解析<context:annotation-config/>
元素,使用 @Autowired
自动装配 bean
public class AnnotationConfigBeanDefinitionParser implements BeanDefinitionParser {
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
Object source = parserContext.extractSource(element);
// 获取registry所有相关的bean定义
Set<BeanDefinitionHolder> processorDefinitions =
AnnotationConfigUtils.registerAnnotationConfigProcessors(parserContext.getRegistry(), source);
// ... 代码省略
// 注册bean定义
for (BeanDefinitionHolder processorDefinition : processorDefinitions) {
parserContext.registerComponent(new BeanComponentDefinition(processorDefinition));
}
// ... 代码省略
return null;
}
}
ComponentScanBeanDefinitionParser
的主要功能是解析<context:component-scan/>
元素,自动扫描指定包下的注解 bean
public class ComponentScanBeanDefinitionParser implements BeanDefinitionParser {
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
// base-package属性
String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);
basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
// 分隔多个包
String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
// 创建并配置扫描对象
ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
// 扫描包中的组件
Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
// 注册组件到上下文中
registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
return null;
}
}
关于 context:
命令空间的解析就到这里了,其他的有兴趣可以自行探索
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());
}
}
AnnotationDrivenBeanDefinitionParser
的主要功能是解析<task:annotation-driven/>
元素,开启定时器开关,自动扫描程序中带注解的定时器
public class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
Object source = parserContext.extractSource(element);
// ... 代码省略
// 获取registry
BeanDefinitionRegistry registry = parserContext.getRegistry();
// mode属性
String mode = element.getAttribute("mode");
// 使用aspectj来执行异步任务
if ("aspectj".equals(mode)) {
// mode="aspectj"
registerAsyncExecutionAspect(element, parserContext);
}
// 使用内置的功能来执行异步任务
else {
// bean "org.springframework.context.annotation.internalAsyncAnnotationProcessor" 已经存在
if (registry.containsBeanDefinition(TaskManagementConfigUtils.ASYNC_ANNOTATION_PROCESSOR_BEAN_NAME)) {
// ... 代码省略
}
else {
// 使用类 "org.springframework.scheduling.annotation.AsyncAnnotationBeanPostProcessor"
// 来配置bean "org.springframework.context.annotation.internalAsyncAnnotationProcessor"
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(
"org.springframework.scheduling.annotation.AsyncAnnotationBeanPostProcessor");
builder.getRawBeanDefinition().setSource(source);
// executor属性
String executor = element.getAttribute("executor");
if (StringUtils.hasText(executor)) {
builder.addPropertyReference("executor", executor);
}
// exception-handler属性
String exceptionHandler = element.getAttribute("exception-handler");
if (StringUtils.hasText(exceptionHandler)) {
builder.addPropertyReference("exceptionHandler", exceptionHandler);
}
// proxy-target-class属性
if (Boolean.parseBoolean(element.getAttribute(AopNamespaceUtils.PROXY_TARGET_CLASS_ATTRIBUTE))) {
builder.addPropertyValue("proxyTargetClass", true);
}
// 注册组件到registry与上下文
registerPostProcessor(parserContext, builder, TaskManagementConfigUtils.ASYNC_ANNOTATION_PROCESSOR_BEAN_NAME);
}
}
// bean "org.springframework.context.annotation.internalScheduledAnnotationProcessor" 已经存在
if (registry.containsBeanDefinition(TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
// ... 代码省略
}
else {
// 使用类 "org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor"
// 来配置bean "org.springframework.context.annotation.internalScheduledAnnotationProcessor"
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(
"org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor");
builder.getRawBeanDefinition().setSource(source);
// scheduler属性
String scheduler = element.getAttribute("scheduler");
if (StringUtils.hasText(scheduler)) {
builder.addPropertyReference("scheduler", scheduler);
}
// 注册组件到registry与上下文
registerPostProcessor(parserContext, builder, TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME);
}
// ... 代码省略
return null;
}
// 使用aspectj来执行异步任务
private void registerAsyncExecutionAspect(Element element, ParserContext parserContext) {
// bean "org.springframework.scheduling.config.internalAsyncExecutionAspect" 不存在
if (!parserContext.getRegistry().containsBeanDefinition(TaskManagementConfigUtils.ASYNC_EXECUTION_ASPECT_BEAN_NAME)) {
// 使用类 "org.springframework.scheduling.aspectj.AnnotationAsyncExecutionAspect"
// 来配置bean "org.springframework.scheduling.config.internalAsyncExecutionAspect"
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(ASYNC_EXECUTION_ASPECT_CLASS_NAME);
// 使用FactoryMethod来初始化bean
builder.setFactoryMethod("aspectOf");
// executor属性
String executor = element.getAttribute("executor");
if (StringUtils.hasText(executor)) {
builder.addPropertyReference("executor", executor);
}
// exception-handler属性
String exceptionHandler = element.getAttribute("exception-handler");
if (StringUtils.hasText(exceptionHandler)) {
builder.addPropertyReference("exceptionHandler", exceptionHandler);
}
// 注册bean
parserContext.registerBeanComponent(new BeanComponentDefinition(builder.getBeanDefinition(),
TaskManagementConfigUtils.ASYNC_EXECUTION_ASPECT_BEAN_NAME));
}
}
}
ExecutorBeanDefinitionParser
的主要功能是解析<task:executor/>
元素,用于配置任务执行器
public class ExecutorBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
@Override
protected String getBeanClassName(Element element) {
// 使用这个类来实现bean
return "org.springframework.scheduling.config.TaskExecutorFactoryBean";
}
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
// keep-alive属性
String keepAliveSeconds = element.getAttribute("keep-alive");
if (StringUtils.hasText(keepAliveSeconds)) {
builder.addPropertyValue("keepAliveSeconds", keepAliveSeconds);
}
// queue-capacity属性
String queueCapacity = element.getAttribute("queue-capacity");
if (StringUtils.hasText(queueCapacity)) {
builder.addPropertyValue("queueCapacity", queueCapacity);
}
// 配置策略
configureRejectionPolicy(element, builder);
// pool-size属性
String poolSize = element.getAttribute("pool-size");
if (StringUtils.hasText(poolSize)) {
builder.addPropertyValue("poolSize", poolSize);
}
}
// 配置策略
private void configureRejectionPolicy(Element element, BeanDefinitionBuilder builder) {
// rejection-policy属性
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));
}
}
ScheduledTasksBeanDefinitionParser
的主要功能是解析<task:scheduled-tasks/>
元素,执行定时器任务
public class ScheduledTasksBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
@Override
protected String getBeanClassName(Element element) {
// 使用这个类来实现bean
return "org.springframework.scheduling.config.ContextLifecycleScheduledTaskRegistrar";
}
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
// cron任务
ManagedList<RuntimeBeanReference> cronTaskList = new ManagedList<>();
// 固定延迟任务
ManagedList<RuntimeBeanReference> fixedDelayTaskList = new ManagedList<>();
// 固定频率任务
ManagedList<RuntimeBeanReference> fixedRateTaskList = new ManagedList<>();
// 触发任务
ManagedList<RuntimeBeanReference> triggerTaskList = new ManagedList<>();
// 遍历子元素
NodeList childNodes = element.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
Node child = childNodes.item(i);
Element taskElement = (Element) child;
// ref属性
String ref = taskElement.getAttribute("ref");
// method属性
String method = taskElement.getAttribute("method");
// ... 代码省略
// cron属性
String cronAttribute = taskElement.getAttribute("cron");
// fixed-delay属性
String fixedDelayAttribute = taskElement.getAttribute("fixed-delay");
// fixed-rate属性
String fixedRateAttribute = taskElement.getAttribute("fixed-rate");
// trigger属性
String triggerAttribute = taskElement.getAttribute("trigger");
// initial-delay属性
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);
// ... 代码省略
// 使用类 "org.springframework.scheduling.support.ScheduledMethodRunnable"
// 实例化定时器bean
String runnableName =
runnableReference(ref, method, taskElement, parserContext).getBeanName();
if (hasFixedDelayAttribute) {
// 使用类 "org.springframework.scheduling.config.IntervalTask"
// 实例化固定延迟执行器bean
fixedDelayTaskList.add(intervalTaskReference(runnableName,
initialDelayAttribute, fixedDelayAttribute, taskElement, parserContext));
}
if (hasFixedRateAttribute) {
// 使用类 "org.springframework.scheduling.config.IntervalTask"
// 实例化固定频率执行器bean
fixedRateTaskList.add(intervalTaskReference(runnableName,
initialDelayAttribute, fixedRateAttribute, taskElement, parserContext));
}
if (hasCronAttribute) {
// 使用类 "org.springframework.scheduling.config.CronTask"
// 实例化cron执行器bean
cronTaskList.add(cronTaskReference(runnableName, cronAttribute,
taskElement, parserContext));
}
if (hasTriggerAttribute) {
// 使用类 "org.springframework.scheduling.config.TriggerTask"
// 实例化触发执行器bean
String triggerName = new RuntimeBeanReference(triggerAttribute).getBeanName();
triggerTaskList.add(triggerTaskReference(runnableName, triggerName,
taskElement, parserContext));
}
}
// scheduler属性
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);
}
}
SchedulerBeanDefinitionParser
的主要功能是解析<task:scheduler/>
元素,配置调度线程池
public class SchedulerBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
@Override
protected String getBeanClassName(Element element) {
// 使用这个类来实现bean
return "org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler";
}
@Override
protected void doParse(Element element, BeanDefinitionBuilder builder) {
// pool-size属性
String poolSize = element.getAttribute("pool-size");
if (StringUtils.hasText(poolSize)) {
builder.addPropertyValue("poolSize", poolSize);
}
}
}
public class CacheNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenCacheBeanDefinitionParser());
registerBeanDefinitionParser("advice", new CacheAdviceParser());
}
}
AnnotationDrivenCacheBeanDefinitionParser
的主要功能是解析<cache:annotation-driven/>
元素,支持注解注 @Cacheable
、@CacheEvict
、@CacheUpdate
class AnnotationDrivenCacheBeanDefinitionParser implements BeanDefinitionParser {
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
// mode属性
String mode = element.getAttribute("mode");
// 使用aspectj来执行
if ("aspectj".equals(mode)) {
registerCacheAspect(element, parserContext);
}
// 使用内置的功能来执行
else {
registerCacheAdvisor(element, parserContext);
}
return null;
}
// 使用aspectj来执行
private void registerCacheAspect(Element element, ParserContext parserContext) {
SpringCachingConfigurer.registerCacheAspect(element, parserContext);
}
// 使用内置的功能来执行
private void registerCacheAdvisor(Element element, ParserContext parserContext) {
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
SpringCachingConfigurer.registerCacheAdvisor(element, parserContext);
}
// 解析cache-resolver属性
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)));
}
}
}
内部类 JCacheCachingConfigurer
private static class JCacheCachingConfigurer {
// 使用内置的功能来执行
private static void registerCacheAdvisor(Element element, ParserContext parserContext) {
// bean "org.springframework.cache.config.internalJCacheAdvisor" 不存在
if (!parserContext.getRegistry().containsBeanDefinition(CacheManagementConfigUtils.JCACHE_ADVISOR_BEAN_NAME)) {
Object source = parserContext.extractSource(element);
// 创建一个JCache执行的bean
BeanDefinition sourceDef = createJCacheOperationSourceBeanDefinition(element, source);
// 获取bean名字
String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);
// 使用 "org.springframework.cache.jcache.interceptor.JCacheInterceptor"
// 创建CacheInterceptor的bean定义
RootBeanDefinition interceptorDef =
new RootBeanDefinition("org.springframework.cache.jcache.interceptor.JCacheInterceptor");
// ... 代码省略
// 获取bean名字
String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);
// 使用 "org.springframework.cache.jcache.interceptor.BeanFactoryJCacheOperationSourceAdvisor"
// 创建CacheAdvisor定义
RootBeanDefinition advisorDef = new RootBeanDefinition(
"org.springframework.cache.jcache.interceptor.BeanFactoryJCacheOperationSourceAdvisor");
// ... 代码省略
// 注册bean "org.springframework.cache.config.internalJCacheAdvisor"
parserContext.getRegistry().registerBeanDefinition(CacheManagementConfigUtils.JCACHE_ADVISOR_BEAN_NAME, advisorDef);
// 注册复合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);
}
}
// 使用aspectj来执行
private static void registerCacheAspect(Element element, ParserContext parserContext) {
// bean "org.springframework.cache.config.internalJCacheAspect" 不存在
if (!parserContext.getRegistry().containsBeanDefinition(CacheManagementConfigUtils.JCACHE_ASPECT_BEAN_NAME)) {
Object eleSource = parserContext.extractSource(element);
RootBeanDefinition def = new RootBeanDefinition();
// 使用 "org.springframework.cache.aspectj.JCacheCacheAspect"
// 来创建bean
def.setBeanClassName(JCACHE_ASPECT_CLASS_NAME);
// 使用FactoryMethod来初始化bean
def.setFactoryMethodName("aspectOf");
// 创建一个JCache执行的bean
BeanDefinition sourceDef = createJCacheOperationSourceBeanDefinition(element, eleSource);
String sourceName =
parserContext.getReaderContext().registerWithGeneratedName(sourceDef);
// 注册bean "org.springframework.cache.jcache.interceptor.DefaultJCacheOperationSource"
parserContext.registerBeanComponent(new BeanComponentDefinition(sourceDef, sourceName));
// 注册bean "org.springframework.cache.config.internalJCacheAspect"
parserContext.registerBeanComponent(new BeanComponentDefinition(def, CacheManagementConfigUtils.JCACHE_ASPECT_BEAN_NAME));
}
}
// 创建一个JCache执行的bean
private static RootBeanDefinition createJCacheOperationSourceBeanDefinition(Element element, @Nullable Object eleSource) {
// 使用 "org.springframework.cache.jcache.interceptor.DefaultJCacheOperationSource""
// 来创建bean
RootBeanDefinition sourceDef =
new RootBeanDefinition("org.springframework.cache.jcache.interceptor.DefaultJCacheOperationSource");
// ... 代码省略
// 解析cache-resolver属性
CacheNamespaceHandler.parseKeyGenerator(element, sourceDef);
return sourceDef;
}
}
CacheAdviceParser
的主要功能是解析<cache:advice/>
元素,配置缓存
class CacheAdviceParser extends AbstractSingleBeanDefinitionParser {
@Override
protected Class<?> getBeanClass(Element element) {
// 使用这个类来实现bean
return CacheInterceptor.class;
}
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
// cache-manager属性
builder.addPropertyReference("cacheManager", CacheNamespaceHandler.extractCacheManager(element));
// caching元素
List<Element> cacheDefs = DomUtils.getChildElementsByTagName(element, DEFS_ELEMENT);
// 有caching元素
if (!cacheDefs.isEmpty()) {
// 把caching元素转化成bean
List<RootBeanDefinition> attributeSourceDefinitions = parseDefinitionsSources(cacheDefs, parserContext);
builder.addPropertyValue("cacheOperationSources", attributeSourceDefinitions);
}
else {
// 没有caching元素,用 "org.springframework.cache.annotation.AnnotationCacheOperationSource"
// 创建一个默认的bean
builder.addPropertyValue("cacheOperationSources",
new RootBeanDefinition("org.springframework.cache.annotation.AnnotationCacheOperationSource"));
}
}
// 把caching元素转化成bean
private List<RootBeanDefinition> parseDefinitionsSources(List<Element> definitions, ParserContext parserContext) {
ManagedList<RootBeanDefinition> defs = new ManagedList<>(definitions.size());
// 遍历
for (Element element : definitions) {
defs.add(parseDefinitionSource(element, parserContext));
}
return defs;
}
// 把caching元素转化成bean
private RootBeanDefinition parseDefinitionSource(Element definition, ParserContext parserContext) {
// ... 代码省略
}
}
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
命名空间的处理器内容较多,这里只解析第一个 mvc:annotation-driven
,其他的有兴趣可以自行探索
AnnotationDrivenBeanDefinitionParser
的主要功能是解析<mvc:annotation-driven/>
元素,启用注解驱动,通过context:component-scan
标签的配置,自动扫描@Component,@Controller,@Service,@Repository
等注解标记的组件注册到工厂中,来处理请求
class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
@Override
public BeanDefinition parse(Element element, ParserContext context) {
// 元素元信息
Object source = context.extractSource(element);
XmlReaderContext readerContext = context.getReaderContext();
// ... 代码省略
// 请求映射处理器bean
RootBeanDefinition handlerMappingDef = new RootBeanDefinition(RequestMappingHandlerMapping.class);
// ... 代码省略
// enable-matrix-variables属性
if (element.hasAttribute("enable-matrix-variables")) {
boolean enableMatrixVariables = Boolean.parseBoolean(element.getAttribute("enable-matrix-variables"));
handlerMappingDef.getPropertyValues().add("removeSemicolonContent", !enableMatrixVariables);
}
// 配置路径映射
configurePathMatchingProperties(handlerMappingDef, element, context);
// 注册RequestMappingHandlerMapping.class bean
readerContext.getRegistry().registerBeanDefinition(HANDLER_MAPPING_BEAN_NAME, handlerMappingDef);
// ... 代码省略
// 获取数据转换服务
RuntimeBeanReference conversionService = getConversionService(element, source, context);
// 获取验证器
RuntimeBeanReference validator = getValidator(element, source, context);
// 获取文本解析器
RuntimeBeanReference messageCodesResolver = getMessageCodesResolver(element);
// 注册ConfigurableWebBindingInitializer.class bean
RootBeanDefinition bindingDef = new RootBeanDefinition(ConfigurableWebBindingInitializer.class);
// ... 代码省略
// 载入conversionService、validator、messageCodesResolver
bindingDef.getPropertyValues().add("conversionService", conversionService);
bindingDef.getPropertyValues().add("validator", validator);
bindingDef.getPropertyValues().add("messageCodesResolver", messageCodesResolver);
// 配置消息转换器
ManagedList<?> messageConverters = getMessageConverters(element, source, context);
// argument-resolvers子元素配置的自定义参数解析器
ManagedList<?> argumentResolvers = getArgumentResolvers(element, context);
// return-value-handlers子元素配置的自定义响应解析器
ManagedList<?> returnValueHandlers = getReturnValueHandlers(element, context);
// async-support子元素配置的异步任务超时时间
String asyncTimeout = getAsyncTimeout(element);
// async-support子元素配置的异步任务执行器
RuntimeBeanReference asyncExecutor = getAsyncExecutor(element);
// async-support子元素配置的callable-interceptors请求拦截器
ManagedList<?> callableInterceptors = getInterceptors(element, source, context, "callable-interceptors");
// async-support子元素配置的deferred-result-interceptors响应拦截器
ManagedList<?> deferredResultInterceptors = getInterceptors(element, source, context, "deferred-result-interceptors");
// 注册RequestMappingHandlerAdapter.class bean
RootBeanDefinition handlerAdapterDef = new RootBeanDefinition(RequestMappingHandlerAdapter.class);
// 载入contentNegotiationManager、bindingDef、messageConverters
handlerAdapterDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);
handlerAdapterDef.getPropertyValues().add("webBindingInitializer", bindingDef);
handlerAdapterDef.getPropertyValues().add("messageConverters", messageConverters);
// 载入jackson请求处理
addRequestBodyAdvice(handlerAdapterDef);
// 载入jackson响应处理
addResponseBodyAdvice(handlerAdapterDef);
// ignore-default-model-on-redirect属性
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);
// 注册RequestMappingHandlerAdapter.class bean
readerContext.getRegistry().registerBeanDefinition(HANDLER_ADAPTER_BEAN_NAME, handlerAdapterDef);
// 注册CompositeUriComponentsContributorFactoryBean.class bean
RootBeanDefinition uriContributorDef =
new RootBeanDefinition(CompositeUriComponentsContributorFactoryBean.class);
uriContributorDef.setSource(source);
uriContributorDef.getPropertyValues().addPropertyValue("handlerAdapter", handlerAdapterDef);
uriContributorDef.getPropertyValues().addPropertyValue("conversionService", conversionService);
// 注册mvcUriComponentsContributor bean
String uriContributorName = MvcUriComponentsBuilder.MVC_URI_COMPONENTS_CONTRIBUTOR_BEAN_NAME;
readerContext.getRegistry().registerBeanDefinition(uriContributorName, uriContributorDef);
// 注册ConversionServiceExposingInterceptor.class bean
RootBeanDefinition csInterceptorDef = new RootBeanDefinition(ConversionServiceExposingInterceptor.class);
csInterceptorDef.setSource(source);
csInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(0, conversionService);
// 注册MappedInterceptor.class bean
RootBeanDefinition mappedInterceptorDef = new RootBeanDefinition(MappedInterceptor.class);
// ... 代码省略
// 注册ExceptionHandlerExceptionResolver.class bean
RootBeanDefinition methodExceptionResolver = new RootBeanDefinition(ExceptionHandlerExceptionResolver.class);
// ... 代码省略
// 注册ResponseStatusExceptionResolver.class bean
RootBeanDefinition statusExceptionResolver = new RootBeanDefinition(ResponseStatusExceptionResolver.class);
// ... 代码省略
// 注册DefaultHandlerExceptionResolver.class bean
RootBeanDefinition defaultExceptionResolver = new RootBeanDefinition(DefaultHandlerExceptionResolver.class);
// ... 代码省略
// 注册一系列bean
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));
// ... 代码省略
context.popAndRegisterContainingComponent();
return null;
}
}
class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
// 配置路径映射
private void configurePathMatchingProperties(
RootBeanDefinition handlerMappingDef, Element element, ParserContext context) {
// 获取path-matching子元素
Element pathMatchingElement = DomUtils.getChildElementByTagName(element, "path-matching");
if (pathMatchingElement != null) {
Object source = context.extractSource(element);
// suffix-pattern属性
if (pathMatchingElement.hasAttribute("suffix-pattern")) {
Boolean useSuffixPatternMatch = Boolean.valueOf(pathMatchingElement.getAttribute("suffix-pattern"));
handlerMappingDef.getPropertyValues().add("useSuffixPatternMatch", useSuffixPatternMatch);
}
// trailing-slash属性
if (pathMatchingElement.hasAttribute("trailing-slash")) {
Boolean useTrailingSlashMatch = Boolean.valueOf(pathMatchingElement.getAttribute("trailing-slash"));
handlerMappingDef.getPropertyValues().add("useTrailingSlashMatch", useTrailingSlashMatch);
}
// registered-suffixes-only属性
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属性
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属性
if (pathMatchingElement.hasAttribute("path-matcher")) {
pathMatcherRef = new RuntimeBeanReference(pathMatchingElement.getAttribute("path-matcher"));
}
pathMatcherRef = MvcNamespaceUtils.registerPathMatcher(pathMatcherRef, context, source);
handlerMappingDef.getPropertyValues().add("pathMatcher", pathMatcherRef);
}
}
// 获取数据转换服务
private RuntimeBeanReference getConversionService(Element element, @Nullable Object source, ParserContext context) {
RuntimeBeanReference conversionServiceRef;
// 有配置conversion-service属性
if (element.hasAttribute("conversion-service")) {
conversionServiceRef = new RuntimeBeanReference(element.getAttribute("conversion-service"));
}
else {
// 没有就用FormattingConversionServiceFactoryBean创建一个默认的
RootBeanDefinition conversionDef = new RootBeanDefinition(FormattingConversionServiceFactoryBean.class);
// ... 代码省略
conversionServiceRef = new RuntimeBeanReference(conversionName);
}
return conversionServiceRef;
}
// 获取验证器
private RuntimeBeanReference getValidator(Element element, @Nullable Object source, ParserContext context) {
// 有配置validator属性
if (element.hasAttribute("validator")) {
return new RuntimeBeanReference(element.getAttribute("validator"));
}
else if (javaxValidationPresent) {
// 没有就用OptionalValidatorFactoryBean创建一个默认的
RootBeanDefinition validatorDef = new RootBeanDefinition(
"org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean");
// ... 代码省略
return new RuntimeBeanReference(validatorName);
}
else {
return null;
}
}
// 获取文本解析器
private RuntimeBeanReference getMessageCodesResolver(Element element) {
// 有配置message-codes-resolver属性
if (element.hasAttribute("message-codes-resolver")) {
return new RuntimeBeanReference(element.getAttribute("message-codes-resolver"));
}
else {
return null;
}
}
}
class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
// 配置消息转换器
private ManagedList<?> getMessageConverters(Element element, @Nullable Object source, ParserContext context) {
// message-converters子元素
Element convertersElement = DomUtils.getChildElementByTagName(element, "message-converters");
// 结果集
ManagedList<Object> messageConverters = new ManagedList<>();
// 有message-converters子元素
if (convertersElement != null) {
// 把bean、ref子元素转换为bean,加入结果集
for (Element beanElement : DomUtils.getChildElementsByTagName(convertersElement, "bean", "ref")) {
Object object = context.getDelegate().parsePropertySubElement(beanElement, null);
messageConverters.add(object);
}
}
// 有message-converters子元素,但有register-defaults属性
if (convertersElement == null || Boolean.parseBoolean(convertersElement.getAttribute("register-defaults"))) {
// 添加ByteArrayHttpMessageConverter.class bean到结果集
// 字节数组转换器
messageConverters.add(createConverterDefinition(ByteArrayHttpMessageConverter.class, source));
// 添加StringHttpMessageConverter.class bean到结果集
// 字符转换器
RootBeanDefinition stringConverterDef = createConverterDefinition(StringHttpMessageConverter.class, source);
stringConverterDef.getPropertyValues().add("writeAcceptCharset", false);
messageConverters.add(stringConverterDef);
// 添加ResourceHttpMessageConverter.class bean到结果集
// 资源转换器
messageConverters.add(createConverterDefinition(ResourceHttpMessageConverter.class, source));
// 添加ResourceRegionHttpMessageConverter.class bean到结果集
// 资源区域转换器
messageConverters.add(createConverterDefinition(ResourceRegionHttpMessageConverter.class, source));
// 添加SourceHttpMessageConverter.class bean到结果集
// javax.xml.transform.Source转换器
messageConverters.add(createConverterDefinition(SourceHttpMessageConverter.class, source));
// 添加AllEncompassingFormHttpMessageConverter.class bean到结果集
// form-data转换器
messageConverters.add(createConverterDefinition(AllEncompassingFormHttpMessageConverter.class, source));
// ... 代码省略
if (jackson2XmlPresent) {
// 添加jackson2Xml转换器
}
// ... 代码省略
if (jackson2Present) {
// 添加jackson2转换器
}
else if (gsonPresent) {
// 添加gson转换器
}
// ... 代码省略
}
return messageConverters;
}
}
更多博客,查看 https://github.com/senntyou/blogs
版权声明:自由转载-非商用-非衍生-保持署名(创意共享 3.0 许可证)
我需要将文本放在 中在一个 Div 中,在另一个 Div 中,在另一个 Div 中。所以这是它的样子: #document Change PIN
奇怪的事情发生了。 我有一个基本的 html 代码。 html,头部, body 。(因为我收到了一些反对票,这里是完整的代码) 这是我的CSS: html { backgroun
我正在尝试将 Assets 中的一组图像加载到 UICollectionview 中存在的 ImageView 中,但每当我运行应用程序时它都会显示错误。而且也没有显示图像。 我在ViewDidLoa
我需要根据带参数的 perl 脚本的输出更改一些环境变量。在 tcsh 中,我可以使用别名命令来评估 perl 脚本的输出。 tcsh: alias setsdk 'eval `/localhome/
我使用 Windows 身份验证创建了一个新的 Blazor(服务器端)应用程序,并使用 IIS Express 运行它。它将显示一条消息“Hello Domain\User!”来自右上方的以下 Ra
这是我的方法 void login(Event event);我想知道 Kotlin 中应该如何 最佳答案 在 Kotlin 中通配符运算符是 * 。它指示编译器它是未知的,但一旦知道,就不会有其他类
看下面的代码 for story in book if story.title.length < 140 - var story
我正在尝试用 C 语言学习字符串处理。我写了一个程序,它存储了一些音乐轨道,并帮助用户检查他/她想到的歌曲是否存在于存储的轨道中。这是通过要求用户输入一串字符来完成的。然后程序使用 strstr()
我正在学习 sscanf 并遇到如下格式字符串: sscanf("%[^:]:%[^*=]%*[*=]%n",a,b,&c); 我理解 %[^:] 部分意味着扫描直到遇到 ':' 并将其分配给 a。:
def char_check(x,y): if (str(x) in y or x.find(y) > -1) or (str(y) in x or y.find(x) > -1):
我有一种情况,我想将文本文件中的现有行包含到一个新 block 中。 line 1 line 2 line in block line 3 line 4 应该变成 line 1 line 2 line
我有一个新项目,我正在尝试设置 Django 调试工具栏。首先,我尝试了快速设置,它只涉及将 'debug_toolbar' 添加到我的已安装应用程序列表中。有了这个,当我转到我的根 URL 时,调试
在 Matlab 中,如果我有一个函数 f,例如签名是 f(a,b,c),我可以创建一个只有一个变量 b 的函数,它将使用固定的 a=a1 和 c=c1 调用 f: g = @(b) f(a1, b,
我不明白为什么 ForEach 中的元素之间有多余的垂直间距在 VStack 里面在 ScrollView 里面使用 GeometryReader 时渲染自定义水平分隔线。 Scrol
我想知道,是否有关于何时使用 session 和 cookie 的指南或最佳实践? 什么应该和什么不应该存储在其中?谢谢! 最佳答案 这些文档很好地了解了 session cookie 的安全问题以及
我在 scipy/numpy 中有一个 Nx3 矩阵,我想用它制作一个 3 维条形图,其中 X 轴和 Y 轴由矩阵的第一列和第二列的值、高度确定每个条形的 是矩阵中的第三列,条形的数量由 N 确定。
假设我用两种不同的方式初始化信号量 sem_init(&randomsem,0,1) sem_init(&randomsem,0,0) 现在, sem_wait(&randomsem) 在这两种情况下
我怀疑该值如何存储在“WORD”中,因为 PStr 包含实际输出。? 既然Pstr中存储的是小写到大写的字母,那么在printf中如何将其给出为“WORD”。有人可以吗?解释一下? #include
我有一个 3x3 数组: var my_array = [[0,1,2], [3,4,5], [6,7,8]]; 并想获得它的第一个 2
我意识到您可以使用如下方式轻松检查焦点: var hasFocus = true; $(window).blur(function(){ hasFocus = false; }); $(win
我是一名优秀的程序员,十分优秀!