亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

Spring4.3.x 淺析xml配置的解析過程(8)——解析context命名空間之component-scan標簽

2019-11-10 17:31:38
字體:
來源:轉載
供稿:網友

概述


SPRing context命名空間有property-placeholder、property-override、annotation-config、component-scan、load-time-weaver、spring-configured、mbean-export和mbean-server 8個標簽。

property-placeholder和property-override標簽的解析見property-placeholder和property-override標簽的解析,annotation-config標簽的解析見解析context命名空間之annotation-config標簽。這一節來探討component-scan標簽的解析與用途。

解析component-scan標簽


component-scan標簽擁有同annotation-config標簽一樣的作用,但它比annotation-config標簽更強大。annotation-config標簽主要作用是注冊后處理來對已創建的BeanDefintion對象和實例化的bean做加工,component-scan標簽作用不僅于此,還可以把特定包下被指定注解類標注的類對象封裝成BeanDefinition對象并注冊到BeanDefinitionRegistry對象中,這樣大大簡化了xml文件的內容。

component-scan標簽的解析器類為ComponentScanBeanDefinitionParser類,它直接實現了BeanDefinitionParser接口,下面是它實現的parse方法的源代碼。

@Override public BeanDefinition parse(Element element, ParserContext parserContext) { String basePackage = element.getAttribute("base-package"); // 處理base-package屬性值中被“${”、“}”包圍的變量 // 比如,base-package="${package}",如果上下文環境對象中有一個Properties對象的key為package // ->那么,base-package的值就為這個key對應的value值 basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage); // 如果有多個根包需要掃描,那么以“,; /t/n”中的一個隔開 String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,",; /t/n"); // Actually scan for bean definitions and register them. // 創建ClassPathBeanDefinitionScanner對象,這個對象用于掃描base-package指定的包下面的類對象 // ->并把匹配的類對象使用BeanDefinition對象封裝,然后注冊到BeanDefinitionRegistry中 ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element); Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages); // 注冊ComponentDefinition和注解配置處理器(和annotation-config標簽的一樣) registerComponents(parserContext.getReaderContext(), beanDefinitions, element); return null; }

ComponentScanBeanDefinitionParser的parser方法,首先創建并初始化ClassPathBeanDefinitionScanner對象;然后使用前面scanner對象掃描指定包下匹配的類對象并注冊相應BeanDefinition對象;最后調用registerComponents方法,如果屬性annotation-config的值為true,則同annotation-config標簽一樣會注冊處理注解配置的各種后處理器。我們先看看最后一步中的registerComponents方法,后面我們在來詳細探討spring如何掃描和匹配包下的類對象。

protected void registerComponents( XmlReaderContext readerContext, Set<BeanDefinitionHolder> beanDefinitions, Element element) { Object source = readerContext.extractSource(element); CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), source); for (BeanDefinitionHolder beanDefHolder : beanDefinitions) { compositeDef.addNestedComponent(new BeanComponentDefinition(beanDefHolder)); } // Register annotation config processors, if necessary. boolean annotationConfig = true; if (element.hasAttribute("annotation-config")) { annotationConfig = Boolean.valueOf(element.getAttribute("annotation-config")); } if (annotationConfig) { Set<BeanDefinitionHolder> processorDefinitions = AnnotationConfigUtils.registerAnnotationConfigProcessors(readerContext.getRegistry(), source); for (BeanDefinitionHolder processorDefinition : processorDefinitions) { compositeDef.addNestedComponent(new BeanComponentDefinition(processorDefinition)); } } readerContext.fireComponentRegistered(compositeDef); }

registerComponents方法代碼很簡單,它主要是拿去component-scan標簽的annotation-config屬性值,這個屬性值默認為true的,如果annotation-config值為true,則注冊注解配置的各個處理器,這個注冊過程在上一節——“解析annotation-config標簽”中已經探討了,這里就不用再說了。

這一節我們詳細討論spring如何使用component-scan標簽來掃描和匹配包下的類對象。

(1)創建并初始化ClassPathBeanDefinitionScanner對象 ComponentScanBeanDefinitionParser的parser方法調用configureScanner(ParserContext parserContext, Element element)方法來創建初始化并返回一個ClassPathBeanDefinitionScanner對象,這個方法的源碼如下。

protected ClassPathBeanDefinitionScanner configureScanner(ParserContext parserContext, Element element) { // 設置是否自動檢測被@Component、@Repository、@Service或者@Controller注解標注的類 // 默認為true。如果為false,那么上面4個注解將沒有作用,因此一般都不會設置這個屬性 boolean useDefaultFilters = true; if (element.hasAttribute("use-default-filters")) { useDefaultFilters = Boolean.valueOf(element.getAttribute("use-default-filters")); } // 把注冊BeanDefinition的任務委托給scanner ClassPathBeanDefinitionScanner scanner = createScanner(parserContext.getReaderContext(), useDefaultFilters); scanner.setResourceLoader(parserContext.getReaderContext().getResourceLoader()); scanner.setEnvironment(parserContext.getReaderContext().getEnvironment()); // 讓scanner持有component-scan標簽的父節點<beans>的屬性默認值 scanner.setBeanDefinitionDefaults(parserContext.getDelegate().getBeanDefinitionDefaults()); scanner.setAutowireCandidatePatterns(parserContext.getDelegate().getAutowireCandidatePatterns()); // 設置資源匹配模式,默認為**/*.class if (element.hasAttribute("resource-pattern")) { scanner.setResourcePattern(element.getAttribute("resource-pattern")); } try { // 設置Bean名稱生成器 parseBeanNameGenerator(element, scanner); } catch (Exception ex) { parserContext.getReaderContext().error(ex.getMessage(), parserContext.extractSource(element), ex.getCause()); } try { // 設置作用域 parseScope(element, scanner); } catch (Exception ex) { parserContext.getReaderContext().error(ex.getMessage(), parserContext.extractSource(element), ex.getCause()); } // 設置過濾器,即用于指定哪些類需要被處理,哪些類需要被忽略 parseTypeFilters(element, scanner, parserContext); return scanner; }

configureScanner方法有4步,第一步是調用createScanner方法來創建一個ClassPathBeanDefinitionScanner 對象,并使用ParserContext對象來初始化它;第二步是調用parseBeanNameGenerator方法;第三步是調用parseScope方法,第四步是調用parseTypeFilters方法。下面我們分別介紹這4個方法。

1)調用createScanner方法創建ClassPathBeanDefinitionScanner 對象,代碼如下。

/** * 創建并返回ClassPathBeanDefinitionScanner對象 **/ protected ClassPathBeanDefinitionScanner createScanner(XmlReaderContext readerContext, boolean useDefaultFilters) { return new ClassPathBeanDefinitionScanner(readerContext.getRegistry(), useDefaultFilters); }

2)調用parseBeanNameGenerator方法設置Bean名稱生成器

protected void parseBeanNameGenerator(Element element, ClassPathBeanDefinitionScanner scanner) { if (element.hasAttribute("name-generator")) { // 生成一個BeanNameGenerator對象 BeanNameGenerator beanNameGenerator = (BeanNameGenerator) instantiateUserDefinedStrategy( element.getAttribute("name-generator"), BeanNameGenerator.class, scanner.getResourceLoader().getClassLoader()); scanner.setBeanNameGenerator(beanNameGenerator); } }

parseBeanNameGenerator為scanner對象設置一個BeanNameGenerator接口對象。spring提供了兩個這樣的對象,其一是AnnotationBeanNameGenerator,它被用于獲取被@Component等注解的類對象的bean名稱。其二是DefaultBeanNameGenerator,它被用于獲取一般bean的名稱。

生成BeanNameGenerator對象調用了ClassPathBeanDefinitionScanner類的私有方法instantiateUserDefinedStrategy,這個方法用于實例化一個指定類型的對象,源碼如下。

/** * 根據指定的class名稱實例化一個對象,這個對象必須為指定的strategyType類型。 **/ private Object instantiateUserDefinedStrategy(String className, Class<?> strategyType, ClassLoader classLoader) { Object result; try { result = classLoader.loadClass(className).newInstance(); } catch (ClassNotFoundException ex) { throw new IllegalArgumentException("Class [" + className + "] for strategy [" + strategyType.getName() + "] not found", ex); } catch (Exception ex) { throw new IllegalArgumentException("Unable to instantiate class [" + className + "] for strategy [" + strategyType.getName() + "]: a zero-argument constructor is required", ex); } if (!strategyType.isAssignableFrom(result.getClass())) { throw new IllegalArgumentException("Provided class name must be an implementation of " + strategyType); } return result; }

3)調用parseScope方法設置作用域解析器或者作用域的默認代理模式

protected void parseScope(Element element, ClassPathBeanDefinitionScanner scanner) { // 如果scope-resolver有值,則注冊ScopeMetadataResolver if (element.hasAttribute("scope-resolver")) { if (element.hasAttribute("scoped-proxy")) { throw new IllegalArgumentException( "Cannot define both 'scope-resolver' and 'scoped-proxy' on <component-scan> tag"); } ScopeMetadataResolver scopeMetadataResolver = (ScopeMetadataResolver) instantiateUserDefinedStrategy( element.getAttribute("scope-resolver"), ScopeMetadataResolver.class, scanner.getResourceLoader().getClassLoader()); scanner.setScopeMetadataResolver(scopeMetadataResolver); } // 設置作用域的默認代理模式ScopedProxyMode if (element.hasAttribute("scoped-proxy")) { String mode = element.getAttribute("scoped-proxy"); if ("targetClass".equals(mode)) { scanner.setScopedProxyMode(ScopedProxyMode.TARGET_CLASS); } else if ("interfaces".equals(mode)) { scanner.setScopedProxyMode(ScopedProxyMode.INTERFACES); } else if ("no".equals(mode)) { scanner.setScopedProxyMode(ScopedProxyMode.NO); } else { throw new IllegalArgumentException("scoped-proxy only supports 'no', 'interfaces' and 'targetClass'"); } } }

注:scope-resolver和scoped-proxy不能同時定義。

4)調用parseTypeFilters方法設置類型過濾器 parseTypeFilters方法主要是用來component-scan標簽的include-filter和exclude-filter子節點。include-filter標簽用來表示必須包含的類,不管這個類是否被默認的注解類標注。exclude-filter標簽用來表示掃描時必須忽略的類,即使這個類被默認的注解標注了。但include-filter和exclude-filter兩個元素不能共存。

protected void parseTypeFilters(Element element, ClassPathBeanDefinitionScanner scanner, ParserContext parserContext) { // 解析exclude和include過濾器元素 ClassLoader classLoader = scanner.getResourceLoader().getClassLoader(); NodeList nodeList = element.getChildNodes(); // 遍歷component-scan標簽下的子節點 for (int i = 0; i < nodeList.getLength(); i++) { Node node = nodeList.item(i); if (node.getNodeType() == Node.ELEMENT_NODE) { String localName = parserContext.getDelegate().getLocalName(node); try { if ("include-filter".equals(localName)) { // 解析include元素 TypeFilter typeFilter = createTypeFilter((Element) node, classLoader, parserContext); scanner.addIncludeFilter(typeFilter); } else if ("exclude-filter".equals(localName)) { 解析exclude元素 TypeFilter typeFilter = createTypeFilter((Element) node, classLoader, parserContext); scanner.addExcludeFilter(typeFilter); } } catch (Exception ex) { parserContext.getReaderContext().error( ex.getMessage(), parserContext.extractSource(element), ex.getCause()); } } } }

parseTypeFilters方法首先判斷區分出include-filter和exclude-filter標簽,然后調用createTypeFilter方法來解析他們并返回TypeFilter,scanner把他們的指代的TypeFilter對象保存到它的includeFilters和excludeFilters列表中。

/** * 解析component-scan標簽的include-filter和exclude-filter子節點,并返回TypeFilter對象 **/ protected TypeFilter createTypeFilter(Element element, ClassLoader classLoader, ParserContext parserContext) { String filterType = element.getAttribute("type"); String expression = element.getAttribute("expression"); expression = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(expression); try { if ("annotation".equals(filterType)) { // 指定過濾的注解。expression=類全名稱 return new AnnotationTypeFilter((Class<Annotation>) classLoader.loadClass(expression)); } else if ("assignable".equals(filterType)) { // 指定過濾的類,它的子類或者實現類也包括。expression=類全名稱 return new AssignableTypeFilter(classLoader.loadClass(expression)); } else if ("aspectj".equals(filterType)) { // 指定aspectj表達式來過濾類。expression=aspectj表達式字符串 return new AspectJTypeFilter(expression, classLoader); } else if ("regex".equals(filterType)) { // 通過指定的正則表達式來過濾類。expression=正則表達式字符串 return new RegexPatternTypeFilter(Pattern.compile(expression)); } else if ("custom".equals(filterType)) { // 用戶自定義過濾器類型 Class<?> filterClass = classLoader.loadClass(expression); if (!TypeFilter.class.isAssignableFrom(filterClass)) { throw new IllegalArgumentException( "Class is not assignable to [" + TypeFilter.class.getName() + "]: " + expression); } return (TypeFilter) BeanUtils.instantiateClass(filterClass); } else { throw new IllegalArgumentException("Unsupported filter type: " + filterType); } } catch (ClassNotFoundException ex) { throw new FatalBeanException("Type filter class not found: " + expression, ex); } }

(2)使用ClassPathBeanDefinitionScanner對象的doScan(String… basePackages)方法開始掃描包,這個方法的源碼如下。

protected Set<BeanDefinitionHolder> doScan(String... basePackages) { Assert.notEmpty(basePackages, "At least one base package must be specified"); Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<BeanDefinitionHolder>(); // 遍歷指定的包 for (String basePackage : basePackages) { // 獲取包下的所有候選BeanDefinition對象 Set<BeanDefinition> candidates = findCandidateComponents(basePackage); // 遍歷所有候選BeanDefinition對象 for (BeanDefinition candidate : candidates) { // 獲取一個ScopeMetadata對象,默認為AnnotationScopeMetadataResolver // 如果目標類未被@Scope注解,則返回一個默認的ScopeMetadata ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate); candidate.setScope(scopeMetadata.getScopeName()); // 使用bean名稱生成器生成bean名稱,默認生成器為AnnotationBeanNameGenerator // 首先是以注解的value為bean名稱,如果注解的value沒有值,則使用默認的名稱 String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry); if (candidate instanceof AbstractBeanDefinition) { // 進一步處理BeanDefinition對象,比如,bean是否可以被用于自動注入的備選bean postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName); } if (candidate instanceof AnnotatedBeanDefinition) { // 處理定義在目標類上的注解,包括@Lazy, @Primary, @DependsOn, @Role, @Description AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate); } // 檢查beanName是否已經存在BeanDefinitionRegistry中存在 if (checkCandidate(beanName, candidate)) { // beanName還沒被使用過 BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName); // 如果有必要,則創建作用域代理 // 如果創建了代理,則返回表示代理對象的BeanDefinitionHolder definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); beanDefinitions.add(definitionHolder); // 注冊BeanDefinitionHolder對象 registerBeanDefinition(definitionHolder, this.registry); } } } return beanDefinitions; }

關于doScan方法所調用的方法,我只探討其中的三個,其一是ClassPathBeanDefinitionScanner的findCandidateComponents方法;其二是AnnotationConfigUtils的processCommonDefinitionAnnotations靜態方法;其三是AnnotationConfigUtils的applyScopedProxyMode靜態方法。

1) findCandidateComponents方法繼承自ClassPathScanningCandidateComponentProvider類,是用于查找指定包及其子包下所有匹配的類,并返回這些類對應的BeanDefinition對象。它的源碼如下。

public Set<BeanDefinition> findCandidateComponents(String basePackage) { Set<BeanDefinition> candidates = new LinkedHashSet<BeanDefinition>(); try { // 聲明有CLASSPATH_ALL_URL_PREFIX="classpath*:" // resourcePattern默認為"**/*.class" String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + resolveBasePackage(basePackage) + "/" + this.resourcePattern; // 根據模式匹配來搜索包下面匹配的所有類 // 默認的ResourcePatternResolver實現類為PathMatchingResourcePatternResolver類 Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath); boolean traceEnabled = logger.isTraceEnabled(); boolean debugEnabled = logger.isDebugEnabled(); // 遍歷所有匹配的類 for (Resource resource : resources) { if (traceEnabled) { logger.trace("Scanning " + resource); } if (resource.isReadable()) { try { // 默認的MetadataReaderFactory實現類為CachingMetadataReaderFactory // 默認返回的是SimpleMetadataReader對象 MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource); // 通過過濾器來判斷類對象是否為候選類 if (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; }

findCandidateComponents方法首先獲取指定包及其子包下所有類的資源對象,然后使用CachingMetadataReaderFactory對象獲取一個SimpleMetadataReader的MetadataReader對象,SimpleMetadataReader使用ClassReader對象從Resource對象持有的類文件輸入流中讀取類信息,ClassReader允許通過ClassVisitor對象來訪問它持有的類信息。而SimpleMetadataReader使用AnnotationMetadataReadingVisitor訪問器把ClassReader存有的類信息分解成類元數據ClassMetadata對象和注解元數據AnnotationMetadata對象。 因此findCandidateComponents方法才可以調用isCandidateComponent(MetadataReader metadataReader)方法來通過過濾器判斷當前類是否會被排除在候選類之外,下面是isCandidateComponent方法的源碼。

protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException { // 首先使用excludeFilters中的過濾器檢查當前類是否應該排除 // 通過exclude-filter標簽配置 for (TypeFilter tf : this.excludeFilters) { if (tf.match(metadataReader, this.metadataReaderFactory)) { return false; } } // 最后使用includeFilters來查看當前類是否候選類 // 通過include-filter標簽配置。 // 默認為注解類型的過濾器,注解類為spring定義的@Component for (TypeFilter tf : this.includeFilters) { if (tf.match(metadataReader, this.metadataReaderFactory)) { return isConditionMatch(metadataReader); } } return false; }

如果當前類是候選類,那么為當前類生成一個ScannedGenericBeanDefinition對象,ScannedGenericBeanDefinition繼承自GenericBeanDefinition并實現了AnnotatedBeanDefinition接口。 如果類不是一個具體且獨立的類,比如抽象類、接口或者非靜態內部類,通過反射實例化一個對象的時候是會拋出異常的。因此spring還會判斷一次,在findCandidateComponents方法中調用isCandidateComponent(AnnotatedBeanDefinition beanDefinition)方法,它的源碼如下。

/** * 判斷類是否是一個具體類,并且是一個可以獨立實例化的類。 **/ protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) { return (beanDefinition.getMetadata().isConcrete() && beanDefinition.getMetadata().isIndependent()); }

通過以上判斷排除,最終獲得一個ScannedGenericBeanDefinition對象?,F在我們第2點ClassPathBeanDefinitionScanner類的 doScan(String… basePackages)方法拿到這個對象后通過調用AnnotationConfigUtils工具類processCommonDefinitionAnnotations靜態方法還做了些什么。

2) AnnotationConfigUtils的processCommonDefinitionAnnotations靜態方法的源碼如下。

public static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd) { processCommonDefinitionAnnotations(abd, abd.getMetadata()); }

processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd)方法把解析類上的注解任務轉交給它的另一個重載方法processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata),這是一個只有包訪問權限的靜態方法,源碼如下。

static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) { // 解析@Lazy注解,設置是否延遲加載 if (metadata.isAnnotated(Lazy.class.getName())) { abd.setLazyInit(attributesFor(metadata, Lazy.class).getBoolean("value")); } else if (abd.getMetadata() != metadata && abd.getMetadata().isAnnotated(Lazy.class.getName())) { abd.setLazyInit(attributesFor(abd.getMetadata(), Lazy.class).getBoolean("value")); } // 解析@Primary注解 if (metadata.isAnnotated(Primary.class.getName())) { abd.setPrimary(true); } // 解析@DependOn注解 if (metadata.isAnnotated(DependsOn.class.getName())) { abd.setDependsOn(attributesFor(metadata, DependsOn.class).getStringArray("value")); } if (abd instanceof AbstractBeanDefinition) { AbstractBeanDefinition absBd = (AbstractBeanDefinition) abd; // 解析@Role注解 if (metadata.isAnnotated(Role.class.getName())) { absBd.setRole(attributesFor(metadata, Role.class).getNumber("value").intValue()); } // 解析@Description注解 if (metadata.isAnnotated(Description.class.getName())) { absBd.setDescription(attributesFor(metadata, Description.class).getString("value")); } } }

3) doScan(String… basePackages)方法還調用AnnotationConfigUtils工具類的applyScopedProxyMode靜態方法,這也是一個只有包訪問權限的方法,它主要是處理標注在類上的@Scope注解,源碼如下。

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); // 創建一個scope代理 return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass); }

ScopedProxyCreator類的createScopedProxy靜態方法源碼如下

public static BeanDefinitionHolder createScopedProxy( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry, boolean proxyTargetClass) { // 調用ScopedProxyUtils工具類的createScopedProxy方法 return ScopedProxyUtils.createScopedProxy(definitionHolder, registry, proxyTargetClass); }

工具類ScopedProxyUtils的createScopedProxy靜態方法源碼如下。

public static BeanDefinitionHolder createScopedProxy(BeanDefinitionHolder definition, BeanDefinitionRegistry registry, boolean proxyTargetClass) { String originalBeanName = definition.getBeanName(); BeanDefinition targetDefinition = definition.getBeanDefinition(); // targetBeanName格式為scopedTarget. + originalBeanName String targetBeanName = getTargetBeanName(originalBeanName); // Create a scoped proxy definition for the original bean name, // "hiding" the target bean in an internal target definition. // 創建一個ScopedProxyFactoryBean類對應BeanDefinition對象 RootBeanDefinition proxyDefinition = new RootBeanDefinition(ScopedProxyFactoryBean.class); proxyDefinition.setDecoratedDefinition(new BeanDefinitionHolder(targetDefinition, targetBeanName)); proxyDefinition.setOriginatingBeanDefinition(targetDefinition); proxyDefinition.setSource(definition.getSource()); proxyDefinition.setRole(targetDefinition.getRole()); proxyDefinition.getPropertyValues().add("targetBeanName", targetBeanName); if (proxyTargetClass) { targetDefinition.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE); } else { // 設置為根據接口做做代理 proxyDefinition.getPropertyValues().add("proxyTargetClass", Boolean.FALSE); } // 根據代理目標BeanDefinition設置是否可以為自動注入的候選bean proxyDefinition.setAutowireCandidate(targetDefinition.isAutowireCandidate()); proxyDefinition.setPrimary(targetDefinition.isPrimary()); if (targetDefinition instanceof AbstractBeanDefinition) { proxyDefinition.copyQualifiersFrom((AbstractBeanDefinition) targetDefinition); } // 隱藏被代理的bean targetDefinition.setAutowireCandidate(false); targetDefinition.setPrimary(false); // 注冊被代理的bean的BeanDefinition對象 registry.registerBeanDefinition(targetBeanName, targetDefinition); // 返回代理bean的BeanDefinitionHolder對象 return new BeanDefinitionHolder(proxyDefinition, originalBeanName, definition.getAliases()); }

總結


(1)component-scan不只是擁有annotation-config的作用,它還用于掃描注冊指定包下特定的bean。因此,在xml配置文件中定義了component-scan就不需要再定義annotation-config。

(2)component-scan大大簡化了我們的xml配置。如果我們需要把一個對象托管給Spring容器,只需要在類上添加@Component注解或者被@Component標注的注解(比如,@Controller、@Service、@Repository)

(3)component-scan的兩個子標簽include-filter和exclude-filter不能共存。這個并不是從spring的java源碼中體現的,而是在schema文件中體現的。(spring為什么這樣設計,我實在是不懂的了)


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
97成人在线视频| 中文字幕久精品免费视频| 日韩精品免费综合视频在线播放| 亚洲欧美在线第一页| 国产精彩精品视频| 亚洲午夜久久久影院| 精品视频久久久| 亚洲欧美制服综合另类| 久久久久久久91| 国产成人精品a视频一区www| 日韩av免费在线看| 亚洲无线码在线一区观看| 国产精品久久久久久久久久免费| 91老司机在线| 久久久久久久亚洲精品| 国产福利精品在线| 精品美女永久免费视频| 欧美极品欧美精品欧美视频| 国产精品视频播放| 欧美电影在线观看网站| 永久免费毛片在线播放不卡| 日日骚久久av| 超碰日本道色综合久久综合| 亚洲区免费影片| 欧美激情视频一区二区| 成人精品视频99在线观看免费| 成人激情在线播放| www.欧美精品一二三区| 日韩视频永久免费观看| 美女撒尿一区二区三区| 92福利视频午夜1000合集在线观看| 日韩欧美aⅴ综合网站发布| 日韩av网址在线观看| 亚洲成人黄色在线| 亚洲精品自拍视频| 亚洲国产天堂久久国产91| 亚洲国产精品美女| 日本久久91av| 国产精品亚洲网站| 亚洲毛片一区二区| 国产剧情久久久久久| 粉嫩av一区二区三区免费野| 国产精品高清在线| 精品国产91久久久久久老师| 78m国产成人精品视频| 亚洲国产精品久久| 国产一区二区丝袜| 大量国产精品视频| 在线观看国产欧美| 亚洲欧美制服第一页| 日韩综合视频在线观看| 97色在线播放视频| 成人高清视频观看www| 国产精品久久久久久av福利| 日韩精品亚洲元码| 琪琪亚洲精品午夜在线| 久久久久国产视频| 91精品国产91久久久久久最新| 成人激情视频小说免费下载| 免费不卡欧美自拍视频| 亚洲欧美在线一区二区| 欧美成人免费在线视频| 亚洲精品黄网在线观看| 欧美日韩免费区域视频在线观看| 91在线观看免费高清完整版在线观看| 欧美一区第一页| 成人做爽爽免费视频| 国产精品天天狠天天看| 欧美性精品220| 国产精品成熟老女人| 亚洲高清一二三区| 亚洲欧美第一页| 日本不卡高字幕在线2019| 91高清视频在线免费观看| 久久久人成影片一区二区三区观看| 亚洲人成网在线播放| 久久韩国免费视频| 国产成人97精品免费看片| 亚洲精品电影在线| 亚洲精品久久久久中文字幕二区| 伊人久久免费视频| 狠狠爱在线视频一区| 91在线视频精品| 日韩视频在线观看免费| 日韩av免费网站| 午夜精品久久久久久久久久久久久| 久久久视频在线| 欧美国产日韩一区二区| 欧美在线视频网| 亚洲xxxxx电影| 亚洲丝袜av一区| 欧美孕妇与黑人孕交| 全色精品综合影院| 国产精品wwww| 亚洲已满18点击进入在线看片| 国产精品网红福利| 国产主播喷水一区二区| 国内精品模特av私拍在线观看| 在线免费看av不卡| 欧美视频免费在线| 国产精品久在线观看| 色七七影院综合| 精品激情国产视频| 精品亚洲一区二区三区在线观看| 成人黄色免费网站在线观看| 91精品视频在线免费观看| 亚洲综合精品伊人久久| 日韩国产精品一区| 欧美在线视频免费播放| 久久精品国产亚洲一区二区| 久久久久久有精品国产| 国产成人免费av电影| 国产精品成人在线| 91九色蝌蚪国产| 国产精品老女人精品视频| 日韩视频永久免费观看| 91亚洲一区精品| 日韩最新av在线| 国产精品专区h在线观看| 成人美女av在线直播| 国产精品永久在线| 日韩在线视频导航| 日韩女优在线播放| 亚洲最大成人网色| 91精品国产成人| 国内精品小视频在线观看| 欧美在线精品免播放器视频| 日韩高清免费观看| 欧美美最猛性xxxxxx| 中文字幕自拍vr一区二区三区| 国产黑人绿帽在线第一区| 成人xxxxx| 欧美成人高清视频| 精品少妇v888av| 欧美尺度大的性做爰视频| 91av网站在线播放| 丝袜亚洲欧美日韩综合| 国产美女扒开尿口久久久| 精品国产一区二区三区四区在线观看| 亚洲男人7777| 亚洲日本欧美日韩高观看| 性色av香蕉一区二区| www.欧美免费| 亚洲自拍偷拍色片视频| 日韩中文第一页| 2020国产精品视频| 播播国产欧美激情| 久久精品精品电影网| 黄色91在线观看| 国产精品福利在线观看| 国产a∨精品一区二区三区不卡| 国产精品a久久久久久| 日韩精品在线观看视频| 色伦专区97中文字幕| 国产精品久久久久久久久久久久| 91国产高清在线| 成人性生交大片免费看视频直播| 中文字幕日韩欧美在线| 国产精品免费视频久久久| 亲爱的老师9免费观看全集电视剧| 国产日韩欧美日韩大片| 日韩精品一区二区三区第95| 亚洲精品电影网站| 国产69精品久久久久9999|