目录
自定义标签解析相关的类
Spring scan
Spring AnnotationUtils
Spring-SimpleAliasRegistry
org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser
org.springframework.beans.factory.xml.NamespaceHandlerSupport
示例,首先创建对象类
public class UserXtd {private String userName;private String emailAddress;public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}public String getEmailAddress() {return emailAddress;}public void setEmailAddress(String emailAddress) {this.emailAddress = emailAddress;}
}
创建xsd文件
创建namespaceHandler
public class UserNamespaceHandler extends NamespaceHandlerSupport {@Overridepublic void init() {registerBeanDefinitionParser("myUser", new UserBeanDefinitionParser());}
}
创建beanDefinitionParser
public class UserBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {/*** 标签对应class* @param element the {@code Element} that is being parsed* @return*/@Overrideprotected Class> getBeanClass(Element element) {return UserXtd.class;}@Overrideprotected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {// 获取 userName 标签属性值String name = element.getAttribute("userName");// 获取 emailAddress 标签属性值String address = element.getAttribute("emailAddress");if (StringUtils.hasText(name)) {builder.addPropertyValue("userName", name);}if (StringUtils.hasText(address)) {builder.addPropertyValue("emailAddress", address);}}
}
创建resource/META-INF/spring.handlers
http\://www.huifer.com/schema/user=com.huifer.source.spring.parser.UserNamespaceHandler
创建resource/META-INF/spring.schemas
http\://www.huifer.com/schema/user.xsd=META-INF/spring-test.xsd
创建测试用例xml
创建Java运行方法
/*** 自定义标签测试用例*/
public class XSDDemo {public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("XTD-xml.xml");UserXtd user = (UserXtd) applicationContext.getBean("testUserBean");System.out.println(user.getEmailAddress());}
}
这里我们希望输出结果是huifer97@163.com,运行后结果也确实是huifer97@163.com
解析DefaultNamespaceHandlerResolver
入口方法org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {if (delegate.isDefaultNamespace(root)) {NodeList nl = root.getChildNodes();for (int i = 0; i < nl.getLength(); i++) {Node node = nl.item(i);if (node instanceof Element) {Element ele = (Element) node;if (delegate.isDefaultNamespace(ele)) {// 不同标签的解析parseDefaultElement(ele, delegate);}else {// 非spring 默认标签解析delegate.parseCustomElement(ele);}}}}else {delegate.parseCustomElement(root);}}
org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(org.w3c.dom.Element)
org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(org.w3c.dom.Element, org.springframework.beans.factory.config.BeanDefinition)
/*** Parse a custom element (outside of the default namespace).* * 自定义标签解析** @param ele the element to parse* @param containingBd the containing bean definition (if any)* @return the resulting bean definition*/@Nullablepublic BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {// 自定义标签解析String namespaceUri = getNamespaceURI(ele);if (namespaceUri == null) {return null;}// 根据命名空间获取处理类NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);if (handler == null) {error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);return null;}// 自定义处理器return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));}
http://www.huifer.com/schema/user和我们定义的 xsd 文件中的 url 相同,如何找到对应的 NamespaceHandler,在META-INF/spring.handlers中有定义,
http\://www.huifer.com/schema/user=com.huifer.source.spring.parser.UserNamespaceHandler
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);这行代码就是获取spring.handlers中的定义
处理方法org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver.resolve
/*** Locate the {@link NamespaceHandler} for the supplied namespace URI* from the configured mappings.** 根据 namespaceUri 获取对应的 {@link NamespaceHandler}* @param namespaceUri the relevant namespace URI* @return the located {@link NamespaceHandler}, or {@code null} if none found*/@Override@Nullablepublic NamespaceHandler resolve(String namespaceUri) {// 获取handlerMappingMap handlerMappings = getHandlerMappings();// 从 handlerMapping 中获取类名Object handlerOrClassName = handlerMappings.get(namespaceUri);if (handlerOrClassName == null) {return null;}// 判断是否处理过,处理过直接返回else if (handlerOrClassName instanceof NamespaceHandler) {return (NamespaceHandler) handlerOrClassName;}else {// 没有处理,进行反射还原类String className = (String) handlerOrClassName;try {// 通过反射还原类Class> handlerClass = ClassUtils.forName(className, this.classLoader);if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +"] does not implement the [" + NamespaceHandler.class.getName() + "] interface");}// 初始化类NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);// 调用init()方法,自定义类中实现namespaceHandler.init();// 放入缓存handlerMappings.put(namespaceUri, namespaceHandler);// 返回自定义的 namespaceHandlerreturn namespaceHandler;}catch (ClassNotFoundException ex) {throw new FatalBeanException("Could not find NamespaceHandler class [" + className +"] for namespace [" + namespaceUri + "]", ex);}catch (LinkageError err) {throw new FatalBeanException("Unresolvable class definition for NamespaceHandler class [" +className + "] for namespace [" + namespaceUri + "]", err);}}}
org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver#getHandlerMappings跟踪这个方法 /*** Load the specified NamespaceHandler mappings lazily.** 获取handlerMappings*/private Map getHandlerMappings() {Map handlerMappings = this.handlerMappings;}
org.springframework.beans.factory.xml.XmlBeanDefinitionReader#registerBeanDefinitions
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();int countBefore = getRegistry().getBeanDefinitionCount();// 注册方法// createReaderContext 初始化HandlerMappingdocumentReader.registerBeanDefinitions(doc, createReaderContext(resource));return getRegistry().getBeanDefinitionCount() - countBefore;}
继续跟踪createReaderContext
org.springframework.beans.factory.xml.XmlBeanDefinitionReader#createReaderContext
public XmlReaderContext createReaderContext(Resource resource) {return new XmlReaderContext(resource, this.problemReporter, this.eventListener,this.sourceExtractor, this, getNamespaceHandlerResolver());}
继续跟踪getNamespaceHandlerResolver
org.springframework.beans.factory.xml.XmlBeanDefinitionReader#getNamespaceHandlerResolver
public NamespaceHandlerResolver getNamespaceHandlerResolver() {if (this.namespaceHandlerResolver == null) {this.namespaceHandlerResolver = createDefaultNamespaceHandlerResolver();}return this.namespaceHandlerResolver;}
继续跟踪createDefaultNamespaceHandlerResolver
org.springframework.beans.factory.xml.XmlBeanDefinitionReader#createDefaultNamespaceHandlerResolver
protected NamespaceHandlerResolver createDefaultNamespaceHandlerResolver() {ClassLoader cl = (getResourceLoader() != null ? getResourceLoader().getClassLoader() : getBeanClassLoader());return new DefaultNamespaceHandlerResolver(cl);}
继续跟踪DefaultNamespaceHandlerResolver
org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolverpublic DefaultNamespaceHandlerResolver(@Nullable ClassLoader classLoader) {this(classLoader, DEFAULT_HANDLER_MAPPINGS_LOCATION);}
handlerMappings 如何出现的
public DefaultNamespaceHandlerResolver(@Nullable ClassLoader classLoader) {this(classLoader, DEFAULT_HANDLER_MAPPINGS_LOCATION);}
public static final String DEFAULT_HANDLER_MAPPINGS_LOCATION = "META-INF/spring.handlers";
@Overridepublic String toString() {return "NamespaceHandlerResolver using mappings " + getHandlerMappings();}
/*** Load the specified NamespaceHandler mappings lazily.** 获取handlerMappings*/private Map getHandlerMappings() {Map handlerMappings = this.handlerMappings;// 缓存不存在if (handlerMappings == null) {synchronized (this) {handlerMappings = this.handlerMappings;if (handlerMappings == null) {if (logger.isTraceEnabled()) {logger.trace("Loading NamespaceHandler mappings from [" + this.handlerMappingsLocation + "]");}try {// 将本地文件读出Properties mappings =PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);if (logger.isTraceEnabled()) {logger.trace("Loaded NamespaceHandler mappings: " + mappings);}handlerMappings = new ConcurrentHashMap<>(mappings.size());// 转换成map结构CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);this.handlerMappings = handlerMappings;}catch (IOException ex) {throw new IllegalStateException("Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex);}}}}return handlerMappings;}
org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver#resolve
@Override@Nullablepublic NamespaceHandler resolve(String namespaceUri) {// 获取handlerMappingMap handlerMappings = getHandlerMappings();// 从 handlerMapping 中获取类名Object handlerOrClassName = handlerMappings.get(namespaceUri);if (handlerOrClassName == null) {return null;}// 判断是否处理过,处理过直接返回else if (handlerOrClassName instanceof NamespaceHandler) {return (NamespaceHandler) handlerOrClassName;}else {// 没有处理,进行反射还原类String className = (String) handlerOrClassName;try {// 通过反射还原类Class> handlerClass = ClassUtils.forName(className, this.classLoader);if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +"] does not implement the [" + NamespaceHandler.class.getName() + "] interface");}// 初始化类NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);// 调用init()方法,自定义类中实现namespaceHandler.init();// 放入缓存handlerMappings.put(namespaceUri, namespaceHandler);// 返回自定义的 namespaceHandlerreturn namespaceHandler;}catch (ClassNotFoundException ex) {throw new FatalBeanException("Could not find NamespaceHandler class [" + className +"] for namespace [" + namespaceUri + "]", ex);}catch (LinkageError err) {throw new FatalBeanException("Unresolvable class definition for NamespaceHandler class [" +className + "] for namespace [" + namespaceUri + "]", err);}}}
执行init方法
public class UserNamespaceHandler extends NamespaceHandlerSupport {@Overridepublic void init() {registerBeanDefinitionParser("myUser", new UserBeanDefinitionParser());}
}/*** Subclasses can call this to register the supplied {@link BeanDefinitionParser} to* handle the specified element. The element name is the local (non-namespace qualified)* name.** 将标签名称,标签解析类放入*/protected final void registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser) {this.parsers.put(elementName, parser);}
方法走完,回到开始的方法
/*** Parse a custom element (outside of the default namespace).* * 自定义标签解析** @param ele the element to parse* @param containingBd the containing bean definition (if any)* @return the resulting bean definition*/@Nullablepublic BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {// 自定义标签解析String namespaceUri = getNamespaceURI(ele);if (namespaceUri == null) {return null;}// 根据命名空间获取处理类// org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver.resolveNamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);if (handler == null) {error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);return null;}// 自定义处理器return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));}
org.springframework.beans.factory.xml.NamespaceHandler#parse
org.springframework.beans.factory.xml.NamespaceHandlerSupport.parse
@Override@Nullablepublic BeanDefinition parse(Element element, ParserContext parserContext) {BeanDefinitionParser parser = findParserForElement(element, parserContext);return (parser != null ? parser.parse(element, parserContext) : null);}
org.springframework.beans.factory.xml.NamespaceHandlerSupport#findParserForElement
@Nullableprivate BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {// 获取标签名称String localName = parserContext.getDelegate().getLocalName(element);// 在map中获取对应的标签解析类BeanDefinitionParser parser = this.parsers.get(localName);// 空报错if (parser == null) {parserContext.getReaderContext().fatal("Cannot locate BeanDefinitionParser for element [" + localName + "]", element);}// 不为空返回return parser;}
org.springframework.beans.factory.xml.BeanDefinitionParser#parse
org.springframework.beans.factory.xml.AbstractBeanDefinitionParser#parsepublic final BeanDefinition parse(Element element, ParserContext parserContext) {/*** {@link AbstractSingleBeanDefinitionParser#parseInternal(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext)}*/AbstractBeanDefinition definition = parseInternal(element, parserContext);}
org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser#parseInternal
@Overrideprotected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();String parentName = getParentName(element);if (parentName != null) {builder.getRawBeanDefinition().setParentName(parentName);}// 调用自己实现的方法 com.huifer.source.spring.parser.UserBeanDefinitionParser.getBeanClassClass> beanClass = getBeanClass(element);if (beanClass != null) {builder.getRawBeanDefinition().setBeanClass(beanClass);}else {// getBeanClassName 同样也是可以在自定义的解析类中实现String beanClassName = getBeanClassName(element);if (beanClassName != null) {builder.getRawBeanDefinition().setBeanClassName(beanClassName);}}builder.getRawBeanDefinition().setSource(parserContext.extractSource(element));BeanDefinition containingBd = parserContext.getContainingBeanDefinition();if (containingBd != null) {// Inner bean definition must receive same scope as containing bean.// 设置scopebuilder.setScope(containingBd.getScope());}if (parserContext.isDefaultLazyInit()) {// Default-lazy-init applies to custom bean definitions as well.// 设置 lazy-initbuilder.setLazyInit(true);}// 执行解析方法,在自定义解析类中存在com.huifer.source.spring.parser.UserBeanDefinitionParser.doParsedoParse(element, parserContext, builder);return builder.getBeanDefinition();}
执行com.huifer.source.spring.parser.UserBeanDefinitionParser#doParse
@Overrideprotected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {// 获取 userName 标签属性值String name = element.getAttribute("userName");// 获取 emailAddress 标签属性值String address = element.getAttribute("emailAddress");if (StringUtils.hasText(name)) {builder.addPropertyValue("userName", name);}if (StringUtils.hasText(address)) {builder.addPropertyValue("emailAddress", address);}}
Spring注解形式使用有下面两种方式
通过AnnotationConfigApplicationContext参数:扫描包
通过 xml 配置context:component-scan属性base-package
AnnotationConfigApplicationContext aac =new AnnotationConfigApplicationContext("com.huifer.source.spring.ann");
AnnotationConfigApplicationContext直接点进去
public AnnotationConfigApplicationContext(String... basePackages) {this();// 扫描包scan(basePackages);refresh();}
context:component-scan 全文搜索component-scan,最终找到org.springframework.context.config.ContextNamespaceHandler
public class ContextNamespaceHandler extends NamespaceHandlerSupport {@Overridepublic 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());}}
org.springframework.context.annotation.ComponentScanBeanDefinitionParser
实现BeanDefinitionParser直接看parse方法
@Override@Nullablepublic BeanDefinition parse(Element element, ParserContext parserContext) {// 获取 base-package 属性值String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);// 处理 ${}basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);// 分隔符`,;\t\n`切分String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);// Actually scan for bean definitions and register them.// 扫描对象创建ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);// 执行扫描方法Set beanDefinitions = scanner.doScan(basePackages);// 注册组件,触发监听registerComponents(parserContext.getReaderContext(), beanDefinitions, element);return null;}
回过头看AnnotationConfigApplicationContext
org.springframework.context.annotation.AnnotationConfigApplicationContext
public AnnotationConfigApplicationContext(String... basePackages) {this();// 扫描包scan(basePackages);refresh();}private final ClassPathBeanDefinitionScanner scanner;@Overridepublic void scan(String... basePackages) {Assert.notEmpty(basePackages, "At least one base package must be specified");this.scanner.scan(basePackages);}
org.springframework.context.annotation.ClassPathBeanDefinitionScanner.scan
public int scan(String... basePackages) {// 获取bean数量int beanCountAtScanStart = this.registry.getBeanDefinitionCount();// 执行扫描doScan(basePackages);// Register annotation config processors, if necessary.if (this.includeAnnotationConfig) {AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);}return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);}
org.springframework.context.annotation.ClassPathBeanDefinitionScanner.doScan
protected Set doScan(String... basePackages) {Assert.notEmpty(basePackages, "At least one base package must be specified");Set beanDefinitions = new LinkedHashSet<>();for (String basePackage : basePackages) {// 寻找组件Set candidates = findCandidateComponents(basePackage);for (BeanDefinition candidate : candidates) {// bean 作用域设置ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);// 设置生命周期candidate.setScope(scopeMetadata.getScopeName());// 创建beanNameString beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);if (candidate instanceof AbstractBeanDefinition) {// 设置默认属性 具体方法:org.springframework.beans.factory.support.AbstractBeanDefinition.applyDefaultspostProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);}if (candidate instanceof AnnotatedBeanDefinition) {// 读取Lazy,Primary 等注解AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);}// bean的重复检查if (checkCandidate(beanName, candidate)) {// 创建 BeanDefinitionHolderBeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);// 代理对象的处理definitionHolder =AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);// 放入list中,最后返回用beanDefinitions.add(definitionHolder);// 注册beanregisterBeanDefinition(definitionHolder, this.registry);}}}return beanDefinitions;}
org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#findCandidateComponents
public Set findCandidateComponents(String basePackage) {// 扫描if (this.componentsIndex != null && indexSupportsIncludeFilters()) {return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);}else {return scanCandidateComponents(basePackage);}}
/*** 扫描当前包路径下的资源* @param basePackage* @return*/private Set scanCandidateComponents(String basePackage) {Set candidates = new LinkedHashSet<>();try {// 字符串拼接出一个编译后的路径 classpath://// 这里替换了通配符String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +resolveBasePackage(basePackage) + '/' + this.resourcePattern;// 获取资源Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);// 日志级别boolean traceEnabled = logger.isTraceEnabled();boolean debugEnabled = logger.isDebugEnabled();for (Resource resource : resources) {if (traceEnabled) {logger.trace("Scanning " + resource);}if (resource.isReadable()) {try {// 获取 MetadataReaderMetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);// 判断是否是 Componentif (isCandidateComponent(metadataReader)) {ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);sbd.setResource(resource);sbd.setSource(resource);if (isCandidateComponent(sbd)) {if (debugEnabled) {logger.debug("Identified candidate component class: " + resource);}candidates.add(sbd);}else {if (debugEnabled) {logger.debug("Ignored because not a concrete top-level class: " + resource);}}}else {if (traceEnabled) {logger.trace("Ignored because not matching any filter: " + resource);}}}catch (Throwable ex) {throw new BeanDefinitionStoreException("Failed to read candidate component class: " + resource, ex);}}else {if (traceEnabled) {logger.trace("Ignored because not readable: " + resource);}}}}catch (IOException ex) {throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);}return candidates;}
org.springframework.context.annotation.ScopeMetadataResolver#resolveScopeMetadata
/*** 生命周期设置** @param definition the target bean definition* @return*/@Overridepublic ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {ScopeMetadata metadata = new ScopeMetadata();// 判断是否属于 AnnotatedBeanDefinitionif (definition instanceof AnnotatedBeanDefinition) {AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition;AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(annDef.getMetadata(), this.scopeAnnotationType);if (attributes != null) {// 获取 value 属性值并且设置metadata.setScopeName(attributes.getString("value"));// 获取 proxyMode 属性值并且设置ScopedProxyMode proxyMode = attributes.getEnum("proxyMode");if (proxyMode == ScopedProxyMode.DEFAULT) {proxyMode = this.defaultProxyMode;}metadata.setScopedProxyMode(proxyMode);}}return metadata;}
org.springframework.context.annotation.AnnotationScopeMetadataResolverTests#resolveScopeMetadataShouldReadScopedProxyModeFromAnnotation测试用例
@Testpublic void resolveScopeMetadataShouldReadScopedProxyModeFromAnnotation() {AnnotatedBeanDefinition bd = new AnnotatedGenericBeanDefinition(AnnotatedWithScopedProxy.class);ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(bd);assertNotNull("resolveScopeMetadata(..) must *never* return null.", scopeMetadata);assertEquals("request", scopeMetadata.getScopeName());assertEquals(TARGET_CLASS, scopeMetadata.getScopedProxyMode());}
org.springframework.beans.factory.support.BeanNameGenerator#generateBeanName
创建beanName org.springframework.context.annotation.AnnotationBeanNameGenerator#generateBeanName
@Overridepublic String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {if (definition instanceof AnnotatedBeanDefinition) {// 如果存在bean(value="") value存在String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);if (StringUtils.hasText(beanName)) {// Explicit bean name found.return beanName;}}// Fallback: generate a unique default bean name.// 创建beanNamereturn buildDefaultBeanName(definition, registry);}@Nullableprotected String determineBeanNameFromAnnotation(AnnotatedBeanDefinition annotatedDef) {AnnotationMetadata amd = annotatedDef.getMetadata();Set types = amd.getAnnotationTypes();String beanName = null;for (String type : types) {AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(amd, type);if (attributes != null && isStereotypeWithNameValue(type, amd.getMetaAnnotationTypes(type), attributes)) {// 获取注解的value 属性值Object value = attributes.get("value");if (value instanceof String) {String strVal = (String) value;// 判断是否存在值if (StringUtils.hasLength(strVal)) {if (beanName != null && !strVal.equals(beanName)) {throw new IllegalStateException("Stereotype annotations suggest inconsistent " +"component names: '" + beanName + "' versus '" + strVal + "'");}// beanName = value属性值beanName = strVal;}}}}return beanName;}
@Service(value = "dhc")
public class DemoService {}
org.springframework.context.annotation.AnnotationBeanNameGenerator#buildDefaultBeanName(org.springframework.beans.factory.config.BeanDefinition, org.springframework.beans.factory.support.BeanDefinitionRegistry) org.springframework.context.annotation.AnnotationBeanNameGenerator#buildDefaultBeanName(org.springframework.beans.factory.config.BeanDefinition) protected String buildDefaultBeanName(BeanDefinition definition) {// 获取bean class nameString beanClassName = definition.getBeanClassName();Assert.state(beanClassName != null, "No bean class name set");// 获取短类名,String shortClassName = ClassUtils.getShortName(beanClassName);// 第一个字母小写return Introspector.decapitalize(shortClassName);}
@Configuration
public class BeanConfig {@Scope(value =ConfigurableBeanFactory.SCOPE_PROTOTYPE)@Bean(value = "hc")public Ubean f() {return new Ubean();}
}
org.springframework.context.annotation.ClassPathBeanDefinitionScanner#postProcessBeanDefinition
protected void postProcessBeanDefinition(AbstractBeanDefinition beanDefinition, String beanName) {beanDefinition.applyDefaults(this.beanDefinitionDefaults);if (this.autowireCandidatePatterns != null) {beanDefinition.setAutowireCandidate(PatternMatchUtils.simpleMatch(this.autowireCandidatePatterns, beanName));}}public void applyDefaults(BeanDefinitionDefaults defaults) {setLazyInit(defaults.isLazyInit());setAutowireMode(defaults.getAutowireMode());setDependencyCheck(defaults.getDependencyCheck());setInitMethodName(defaults.getInitMethodName());setEnforceInitMethod(false);setDestroyMethodName(defaults.getDestroyMethodName());setEnforceDestroyMethod(false);}
org.springframework.context.annotation.AnnotationConfigUtils#processCommonDefinitionAnnotations(org.springframework.beans.factory.annotation.AnnotatedBeanDefinition)
public static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd) {processCommonDefinitionAnnotations(abd, abd.getMetadata());}
static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {// 获取 lazy 注解AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);if (lazy != null) {abd.setLazyInit(lazy.getBoolean("value"));} else if (abd.getMetadata() != metadata) {lazy = attributesFor(abd.getMetadata(), Lazy.class);if (lazy != null) {abd.setLazyInit(lazy.getBoolean("value"));}}if (metadata.isAnnotated(Primary.class.getName())) {abd.setPrimary(true);}AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);if (dependsOn != null) {abd.setDependsOn(dependsOn.getStringArray("value"));}AnnotationAttributes role = attributesFor(metadata, Role.class);if (role != null) {abd.setRole(role.getNumber("value").intValue());}AnnotationAttributes description = attributesFor(metadata, Description.class);if (description != null) {abd.setDescription(description.getString("value"));}}
获取注解的属性值设置注解属性
org.springframework.context.annotation.ClassPathBeanDefinitionScanner#checkCandidate
protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) throws IllegalStateException {// 判断当前 beanName 是否在注册表中if (!this.registry.containsBeanDefinition(beanName)) {return true;}// 从注册表中获取BeanDefinition existingDef = this.registry.getBeanDefinition(beanName);// 当前的beanBeanDefinition originatingDef = existingDef.getOriginatingBeanDefinition();if (originatingDef != null) {existingDef = originatingDef;}if (isCompatible(beanDefinition, existingDef)) {return false;}throw new ConflictingBeanDefinitionException("Annotation-specified bean name '" + beanName +"' for bean class [" + beanDefinition.getBeanClassName() + "] conflicts with existing, " +"non-compatible bean definition of same name and class [" + existingDef.getBeanClassName() + "]");}
org.springframework.context.annotation.AnnotationConfigUtils#applyScopedProxyMode
static BeanDefinitionHolder applyScopedProxyMode(ScopeMetadata metadata, BeanDefinitionHolder definition, BeanDefinitionRegistry registry) {ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();if (scopedProxyMode.equals(ScopedProxyMode.NO)) {return definition;}boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);// 创建代理对象return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);}
org.springframework.core.annotation.AnnotationUtils提供了注解相关的方法 getAnnotation
@Test
public void findMethodAnnotationOnLeaf() throws Exception {Method m = Leaf.class.getMethod("annotatedOnLeaf");assertNotNull(m.getAnnotation(Order.class));assertNotNull(getAnnotation(m, Order.class));assertNotNull(findAnnotation(m, Order.class));
}
org.springframework.core.annotation.AnnotationUtils.getAnnotation(java.lang.reflect.Method, java.lang.Class)
/*** Get a single {@link Annotation} of {@code annotationType} from the* supplied {@link Method}, where the annotation is either present* or meta-present on the method.* Correctly handles bridge {@link Method Methods} generated by the compiler.*
Note that this method supports only a single level of meta-annotations.* For support for arbitrary levels of meta-annotations, use* {@link #findAnnotation(Method, Class)} instead.** @param method the method to look for annotations on* 被检查的函数* @param annotationType the annotation type to look for* 需要检测的注解类型* @return the first matching annotation, or {@code null} if not found* @see org.springframework.core.BridgeMethodResolver#findBridgedMethod(Method)* @see #getAnnotation(AnnotatedElement, Class)*/
@Nullable
public static A getAnnotation(Method method, Class annotationType) {// 函数Method resolvedMethod = BridgeMethodResolver.findBridgedMethod(method);// 强制转换return getAnnotation((AnnotatedElement) resolvedMethod, annotationType);
}
@Nullable
public static A getAnnotation(AnnotatedElement annotatedElement, Class annotationType) {try {// 获取注解A annotation = annotatedElement.getAnnotation(annotationType);if (annotation == null) {for (Annotation metaAnn : annotatedElement.getAnnotations()) {annotation = metaAnn.annotationType().getAnnotation(annotationType);if (annotation != null) {break;}}}return (annotation != null ? synthesizeAnnotation(annotation, annotatedElement) : null);} catch (Throwable ex) {handleIntrospectionFailure(annotatedElement, ex);return null;}
}
org.springframework.core.annotation.AnnotationUtils.synthesizeAnnotation(A, java.lang.reflect.AnnotatedElement)
public static A synthesizeAnnotation(A annotation, @Nullable AnnotatedElement annotatedElement) {return synthesizeAnnotation(annotation, (Object) annotatedElement);
}
/*** 注解是否存在别名,没有直接返回** @param annotation 注解* @param annotatedElement 函数* @param * @return*/
@SuppressWarnings("unchecked")
static A synthesizeAnnotation(A annotation, @Nullable Object annotatedElement) {if (annotation instanceof SynthesizedAnnotation || hasPlainJavaAnnotationsOnly(annotatedElement)) {return annotation;}// 具体的注解Class extends Annotation> annotationType = annotation.annotationType();if (!isSynthesizable(annotationType)) {return annotation;}DefaultAnnotationAttributeExtractor attributeExtractor =new DefaultAnnotationAttributeExtractor(annotation, annotatedElement);InvocationHandler handler = new SynthesizedAnnotationInvocationHandler(attributeExtractor);// Can always expose Spring's SynthesizedAnnotation marker since we explicitly check for a// synthesizable annotation before (which needs to declare @AliasFor from the same package)Class>[] exposedInterfaces = new Class>[]{annotationType, SynthesizedAnnotation.class};return (A) Proxy.newProxyInstance(annotation.getClass().getClassLoader(), exposedInterfaces, handler);
}
org.springframework.core.annotation.AnnotationUtils.isSynthesizable
@SuppressWarnings("unchecked")
private static boolean isSynthesizable(Class extends Annotation> annotationType) {if (hasPlainJavaAnnotationsOnly(annotationType)) {return false;}// 从缓存中获取当前注解,不存在nullBoolean synthesizable = synthesizableCache.get(annotationType);if (synthesizable != null) {return synthesizable;}synthesizable = Boolean.FALSE;for (Method attribute : getAttributeMethods(annotationType)) {if (!getAttributeAliasNames(attribute).isEmpty()) {synthesizable = Boolean.TRUE;break;}// 获取返回值类型Class> returnType = attribute.getReturnType();// 根据返回值做不同处理if (Annotation[].class.isAssignableFrom(returnType)) {Class extends Annotation> nestedAnnotationType =(Class extends Annotation>) returnType.getComponentType();if (isSynthesizable(nestedAnnotationType)) {synthesizable = Boolean.TRUE;break;}} else if (Annotation.class.isAssignableFrom(returnType)) {Class extends Annotation> nestedAnnotationType = (Class extends Annotation>) returnType;if (isSynthesizable(nestedAnnotationType)) {synthesizable = Boolean.TRUE;break;}}}synthesizableCache.put(annotationType, synthesizable);return synthesizable;
}
org.springframework.core.annotation.AnnotationUtils#getAttributeMethods
static List getAttributeMethods(Class extends Annotation> annotationType) {List methods = attributeMethodsCache.get(annotationType);if (methods != null) {return methods;}methods = new ArrayList<>();// annotationType.getDeclaredMethods() 获取注解中的方法for (Method method : annotationType.getDeclaredMethods()) {if (isAttributeMethod(method)) {ReflectionUtils.makeAccessible(method);methods.add(method);}}// 缓存 key:注解,value:函数列表attributeMethodsCache.put(annotationType, methods);// 函数列表return methods;
}
org.springframework.core.annotation.AnnotationUtils#isAttributeMethod
/*** Determine if the supplied {@code method} is an annotation attribute method.* * 做3个判断*
* - 函数不为空(method != null)
* - 参数列表是不是空(method.getParameterCount() == 0)
* - 返回类型不是void(method.getReturnType() != void.class)
*
** @param method the method to check* @return {@code true} if the method is an attribute method* @since 4.2*/
static boolean isAttributeMethod(@Nullable Method method) {return (method != null && method.getParameterCount() == 0 && method.getReturnType() !=void.class);
}
org.springframework.util.ReflectionUtils#makeAccessible(java.lang.reflect.Method)
@SuppressWarnings("deprecation") // on JDK 9
public static void makeAccessible(Method method) {// 1. 方法修饰符是不是public// 2. 注解是不是public// 3. 是否重写if ((!Modifier.isPublic(method.getModifiers()) ||!Modifier.isPublic(method.getDeclaringClass().getModifiers())) && !method.isAccessible()) {method.setAccessible(true);}
}
处理结果和 Order 定义相同
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@Documented
public @interface Order {/*** The order value.* Default is {@link Ordered#LOWEST_PRECEDENCE}.** 启动顺序,默认integer最大值* @see Ordered#getOrder()*/int value() default Ordered.LOWEST_PRECEDENCE;}
findAnnotation
org.springframework.core.annotation.AnnotationUtils#findAnnotation(java.lang.reflect.Method, java.lang.Class)
@SuppressWarnings("unchecked")
@Nullable
public static A findAnnotation(Method method, @Nullable Class annotationType) {Assert.notNull(method, "Method must not be null");if (annotationType == null) {return null;}// 创建注解缓存,key:被扫描的函数,value:注解AnnotationCacheKey cacheKey = new AnnotationCacheKey(method, annotationType);// 从findAnnotationCache获取缓存A result = (A) findAnnotationCache.get(cacheKey);if (result == null) {Method resolvedMethod = BridgeMethodResolver.findBridgedMethod(method);// 寻找注解result = findAnnotation((AnnotatedElement) resolvedMethod, annotationType);if (result == null) {result = searchOnInterfaces(method, annotationType, method.getDeclaringClass().getInterfaces());}Class> clazz = method.getDeclaringClass();while (result == null) {clazz = clazz.getSuperclass();if (clazz == null || clazz == Object.class) {break;}Set annotatedMethods = getAnnotatedMethodsInBaseType(clazz);if (!annotatedMethods.isEmpty()) {for (Method annotatedMethod : annotatedMethods) {if (isOverride(method, annotatedMethod)) {Method resolvedSuperMethod = BridgeMethodResolver.findBridgedMethod(annotatedMethod);result = findAnnotation((AnnotatedElement) resolvedSuperMethod, annotationType);if (result != null) {break;}}}}if (result == null) {result = searchOnInterfaces(method, annotationType, clazz.getInterfaces());}}if (result != null) {// 处理注解result = synthesizeAnnotation(result, method);// 添加缓存findAnnotationCache.put(cacheKey, result);}}// 返回return result;
}
org.springframework.core.annotation.AnnotationUtils.AnnotationCacheKey
private static final class AnnotationCacheKey implements Comparable {/*** 带有注解的函数或者类*/private final AnnotatedElement element;/*** 注解*/private final Class extends Annotation> annotationType;public AnnotationCacheKey(AnnotatedElement element, Class extends Annotation> annotationType) {this.element = element;this.annotationType = annotationType;}}
org.springframework.core.annotation.AnnotationUtils#findAnnotation(java.lang.reflect.AnnotatedElement, java.lang.Class)
@Nullable
public static A findAnnotation(AnnotatedElement annotatedElement, @Nullable Class annotationType) {// 注解类型不为空if (annotationType == null) {return null;}// Do NOT store result in the findAnnotationCache since doing so could break// findAnnotation(Class, Class) and findAnnotation(Method, Class).// 寻找注解A ann = findAnnotation(annotatedElement, annotationType, new HashSet<>());return (ann != null ? synthesizeAnnotation(ann, annotatedElement) : null);
}
org.springframework.core.annotation.AnnotationUtils#findAnnotation(java.lang.reflect.AnnotatedElement, java.lang.Class, java.util.Set
@Nullable
private static A findAnnotation(AnnotatedElement annotatedElement, Class annotationType, Set visited) {try {// 直接获取注解A annotation = annotatedElement.getDeclaredAnnotation(annotationType);if (annotation != null) {return annotation;}// 多级注解for (Annotation declaredAnn : getDeclaredAnnotations(annotatedElement)) {Class extends Annotation> declaredType = declaredAnn.annotationType();// 注解是否 由java.lang.annotation提供if (!isInJavaLangAnnotationPackage(declaredType) && visited.add(declaredAnn)) {annotation = findAnnotation((AnnotatedElement) declaredType, annotationType, visited);if (annotation != null) {return annotation;}}}} catch (Throwable ex) {handleIntrospectionFailure(annotatedElement, ex);}return null;
}
getValue
@Test
public void getValueFromAnnotation() throws Exception {Method method = SimpleFoo.class.getMethod("something", Object.class);Order order = findAnnotation(method, Order.class);assertEquals(1, getValue(order, VALUE));assertEquals(1, getValue(order));
}
org.springframework.core.annotation.AnnotationUtils#getValue(java.lang.annotation.Annotation, java.lang.String)
@Nullable
public static Object getValue(@Nullable Annotation annotation, @Nullable String attributeName) {if (annotation == null || !StringUtils.hasText(attributeName)) {return null;}try {// 根据attributeName获取注解对应函数Method method = annotation.annotationType().getDeclaredMethod(attributeName);ReflectionUtils.makeAccessible(method);// 反射执行方法return method.invoke(annotation);} catch (NoSuchMethodException ex) {return null;} catch (InvocationTargetException ex) {rethrowAnnotationConfigurationException(ex.getTargetException());throw new IllegalStateException("Could not obtain value for annotation attribute '" +attributeName + "' in " + annotation, ex);} catch (Throwable ex) {handleIntrospectionFailure(annotation.getClass(), ex);return null;}
}
@Nullable
public static Object getValue(Annotation annotation) {return getValue(annotation, VALUE);
}
getDefaultValue
org.springframework.core.annotation.AnnotationUtils#getDefaultValue(java.lang.annotation.Annotation)
@Nullable
public static Object getDefaultValue(Annotation annotation) {return getDefaultValue(annotation, VALUE);
}
@Nullable
public static Object getDefaultValue(@Nullable Class extends Annotation> annotationType, @Nullable String attributeName) {if (annotationType == null || !StringUtils.hasText(attributeName)) {return null;}try {// 直接获取defaultValuereturn annotationType.getDeclaredMethod(attributeName).getDefaultValue();} catch (Throwable ex) {handleIntrospectionFailure(annotationType, ex);return null;}
}
AliasRegistry
别名注册SimpleAliasRegistry继承org.springframework.core.AliasRegistry
public interface AliasRegistry {/*** Given a name, register an alias for it.* 别名注册** @param name the canonical name* @param alias the alias to be registered* @throws IllegalStateException if the alias is already in use* and may not be overridden* @see SimpleAliasRegistry* @see org.springframework.context.support.GenericApplicationContext*/void registerAlias(String name, String alias);/*** Remove the specified alias from this registry.* 别名移除** @param alias the alias to remove* @throws IllegalStateException if no such alias was found*/void removeAlias(String alias);/*** Determine whether this given name is defines as an alias* (as opposed to the name of an actually registered component).* 是不是别名** @param name the name to check* @return whether the given name is an alias*/boolean isAlias(String name);/*** Return the aliases for the given name, if defined.* 从别名注册map中获取别名信息** @param name the name to check for aliases* @return the aliases, or an empty array if none*/String[] getAliases(String name);}
SimpleAliasRegistry
/*** Simple implementation of the {@link AliasRegistry} interface.* Serves as base class for* {@link org.springframework.beans.factory.support.BeanDefinitionRegistry}* implementations.** @author Juergen Hoeller* @since 2.5.2*/
public class SimpleAliasRegistry implements AliasRegistry {/*** Logger available to subclasses.*/protected final Log logger = LogFactory.getLog(getClass());/*** Map from alias to canonical name.* 存放别名的map(线程安全的),* 结构: alias-> name*/private final Map aliasMap = new ConcurrentHashMap<>(16);/*** {@code }** @param name the canonical name* alias 标签的name属性* @param alias the alias to be registered* alias 标签的alias属性*/@Overridepublic void registerAlias(String name, String alias) {Assert.hasText(name, "'name' must not be empty");Assert.hasText(alias, "'alias' must not be empty");synchronized (this.aliasMap) {// 判断: 别名和名字是否相同if (alias.equals(name)) {//相同在别名map中移除this.aliasMap.remove(alias);if (logger.isDebugEnabled()) {logger.debug("Alias definition '" + alias + "' ignored since it points to same name");}}else {// 不相同// 从map对象中获取别名为alias的valueString registeredName = this.aliasMap.get(alias);if (registeredName != null) {// 判断map中是否有有一个别名和传入的name相同的内容if (registeredName.equals(name)) {// An existing alias - no need to re-registerreturn;}if (!allowAliasOverriding()) {throw new IllegalStateException("Cannot define alias '" + alias + "' for name '" +name + "': It is already registered for name '" + registeredName + "'.");}if (logger.isDebugEnabled()) {logger.debug("Overriding alias '" + alias + "' definition for registered name '" +registeredName + "' with new target name '" + name + "'");}}// 别名环检查checkForAliasCircle(name, alias);// 放入 map 对象中 alias-> namethis.aliasMap.put(alias, name);if (logger.isTraceEnabled()) {logger.trace("Alias definition '" + alias + "' registered for name '" + name + "'");}}}}/*** Return whether alias overriding is allowed.* Default is {@code true}.* 是否允许重写别名*/protected boolean allowAliasOverriding() {return true;}/*** Determine whether the given name has the given alias registered.* * 递归判断是否已经存在别名** @param name the name to check* @param alias the alias to look for* @since 4.2.1*/public boolean hasAlias(String name, String alias) {for (Map.Entry entry : this.aliasMap.entrySet()) {// 获取key值String registeredName = entry.getValue();if (registeredName.equals(name)) {String registeredAlias = entry.getKey();// 循环引用判断if (registeredAlias.equals(alias) || hasAlias(registeredAlias, alias)) {return true;}}}return false;}/*** 别名移除** @param alias the alias to remove*/@Overridepublic void removeAlias(String alias) {synchronized (this.aliasMap) {// 判断是否移除成功String name = this.aliasMap.remove(alias);if (name == null) {throw new IllegalStateException("No alias '" + alias + "' registered");}}}/*** 判断是否是一个别名,校验方式{@link org.springframework.core.SimpleAliasRegistry#aliasMap} 的key是否包含** @param name the name to check* @return*/@Overridepublic boolean isAlias(String name) {return this.aliasMap.containsKey(name);}/*** 获取别名列表** @param name the name to check for aliases* @return*/@Overridepublic String[] getAliases(String name) {List result = new ArrayList<>();synchronized (this.aliasMap) {retrieveAliases(name, result);}return StringUtils.toStringArray(result);}/*** Transitively retrieve all aliases for the given name.* 根据 name 获取别名** @param name the target name to find aliases for* @param result the resulting aliases list*/private void retrieveAliases(String name, List result) {// 循环获取this.aliasMap.forEach((alias, registeredName) -> {if (registeredName.equals(name)) {result.add(alias);// 递归查询循环引用的别名retrieveAliases(alias, result);}});}/*** Resolve all alias target names and aliases registered in this* factory, applying the given StringValueResolver to them.* The value resolver may for example resolve placeholders* in target bean names and even in alias names.** @param valueResolver the StringValueResolver to apply*/public void resolveAliases(StringValueResolver valueResolver) {Assert.notNull(valueResolver, "StringValueResolver must not be null");synchronized (this.aliasMap) {Map aliasCopy = new HashMap<>(this.aliasMap);aliasCopy.forEach((alias, registeredName) -> {String resolvedAlias = valueResolver.resolveStringValue(alias);String resolvedName = valueResolver.resolveStringValue(registeredName);if (resolvedAlias == null || resolvedName == null || resolvedAlias.equals(resolvedName)) {this.aliasMap.remove(alias);}else if (!resolvedAlias.equals(alias)) {String existingName = this.aliasMap.get(resolvedAlias);if (existingName != null) {if (existingName.equals(resolvedName)) {// Pointing to existing alias - just remove placeholderthis.aliasMap.remove(alias);return;}throw new IllegalStateException("Cannot register resolved alias '" + resolvedAlias + "' (original: '" + alias +"') for name '" + resolvedName + "': It is already registered for name '" +registeredName + "'.");}checkForAliasCircle(resolvedName, resolvedAlias);this.aliasMap.remove(alias);this.aliasMap.put(resolvedAlias, resolvedName);}else if (!registeredName.equals(resolvedName)) {this.aliasMap.put(alias, resolvedName);}});}}/*** Check whether the given name points back to the given alias as an alias* in the other direction already, catching a circular reference upfront* and throwing a corresponding IllegalStateException.* * 判断是否循环别名** @param name the candidate name* @param alias the candidate alias* @see #registerAlias* @see #hasAlias*/protected void checkForAliasCircle(String name, String alias) {if (hasAlias(alias, name)) {throw new IllegalStateException("Cannot register alias '" + alias +"' for name '" + name + "': Circular reference - '" +name + "' is a direct or indirect alias for '" + alias + "' already");}}/*** Determine the raw name, resolving aliases to canonical names.** @param name the user-specified name* @return the transformed name*/public String canonicalName(String name) {String canonicalName = name;// Handle aliasing...String resolvedName;do {resolvedName = this.aliasMap.get(canonicalName);if (resolvedName != null) {canonicalName = resolvedName;}}while (resolvedName != null);return canonicalName;}}
下一篇:openGauss 安装 极简版