成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

我100%確定,你對(duì)@ComponentScan注解的了解僅限于皮毛

開(kāi)發(fā) 前端
@ComponentScan注解,用于自動(dòng)檢測(cè)并注冊(cè)帶有@Component、@Service、@Repository和@Controller等注解的類(lèi)為Spring Bean。雖然許多開(kāi)發(fā)者都熟悉它的基本用法,但其背后的復(fù)雜性和靈活性卻往往被忽視。

環(huán)境:Spring Boot3.2.5

1. 簡(jiǎn)介

在Spring中,@ComponentScan注解是一個(gè)強(qiáng)大且常用的工具,但很多人對(duì)其功能和使用方法可能只是一知半解。本文將深入探討@ComponentScan注解的各個(gè)方面,揭示其隱藏的功能和最佳實(shí)踐,幫助讀者徹底掌握這一重要注解。

@ComponentScan注解,用于自動(dòng)檢測(cè)并注冊(cè)帶有@Component、@Service、@Repository和@Controller等注解的類(lèi)為Spring Bean。雖然許多開(kāi)發(fā)者都熟悉它的基本用法,但其背后的復(fù)雜性和靈活性卻往往被忽視。

本篇文章中我將詳細(xì)的介紹@ComponentScan的各種配置選項(xiàng),包括如何指定基礎(chǔ)包、排除特定組件、自定義過(guò)濾器以及處理代理和作用域等配置項(xiàng)的使用。

首先,我們先準(zhǔn)備以下要使用到的類(lèi)

package com.pack.ioc.scan_component
@Component
public class A {}


package com.pack.ioc.scan_component.child
@Component
public class B {}


// 配置類(lèi)
package com.pack.ioc.scan_component
@Configuration
@ComponentScan
public class AppConfig {
}

接下來(lái),準(zhǔn)備一個(gè)運(yùn)行的Main類(lèi)

public class ComponentScanTest {


  public static void main(String[] args) {
    try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationCo
      context.registerBean(AppConfig.class) ;
      context.refresh() ;
      // 打印當(dāng)前容器中注冊(cè)的所有bean集合
      System.out.println(Arrays.toString(context.getBeanDefinitionNames())) ;
    }
  }
}

在后續(xù)的每一個(gè)示例演示中都會(huì)基于上面定義的類(lèi)進(jìn)行,這過(guò)程中我們還會(huì)創(chuàng)建更多的類(lèi)。

2. 實(shí)戰(zhàn)案例

2.1 基本使用

在上面準(zhǔn)備的基本環(huán)境中,在AppConfig類(lèi)是僅僅是添加了@ComponentScan注解,沒(méi)有配置任何的選項(xiàng),運(yùn)行程序輸出如下:

[..., com.pack.ioc.scan_component.AppConfig, a, b]

這里將我們自定義的類(lèi)都打印了(這里省去Spring容器自動(dòng)注冊(cè)bean)。根據(jù)運(yùn)行結(jié)果看出,雖然A,B不再同一個(gè)包中,但是B所在的包是AppConfig所在的包的子包中,所以@ComponentScan會(huì)處理當(dāng)前包及其子包中的類(lèi)。

2.2 指定basePackages

@ComponentScan(basePackages = {"com.pack.ioc.scan_component.child"})
public class AppConfig {}

這里只是指定了一個(gè)子包,運(yùn)行結(jié)果:

[..., com.pack.ioc.scan_component.AppConfig, b]

此時(shí),A類(lèi)不會(huì)包含在內(nèi)。

2.3 指定basePackageClasses

@ComponentScan(basePackageClasses = {B.class})
public class AppConfig {}

這里可以通過(guò)指定Class對(duì)象,這樣會(huì)根據(jù)該Class對(duì)象所在的包進(jìn)行掃描,運(yùn)行結(jié)果

[..., com.pack.ioc.scan_component.AppConfig, b]

Spring內(nèi)部會(huì)自動(dòng)將你配置的所有Class對(duì)象所在的包,作為掃描路徑。

2.4 指定includeFilters

注:@ComponentScan注解還包括excludeFilters排除過(guò)濾屬性,這里我們只介紹includeFilters屬性。

由于includeFilters中配置的是@Filter,而該注解中定義了type屬性,該type屬性是FilterType枚舉類(lèi),其中包括以下值:

public enum FilterType {


  ANNOTATION,


  ASSIGNABLE_TYPE,


  ASPECTJ,


  REGEX,


  CUSTOM
}

接下來(lái),我們將依次介紹這些枚舉值。

  • 過(guò)濾類(lèi)型FilterType.ANNOTATION

在目標(biāo)類(lèi)上存在指定的注解。

首先,我們自定義一個(gè)注解,然后通過(guò)該注解標(biāo)準(zhǔn)類(lèi)。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Pack {
}
// 使用該注解標(biāo)注下面的類(lèi)
@Pack
public class C {
}

在默認(rèn)情況下,Spring容器是不會(huì)識(shí)別到C這個(gè)類(lèi)的,通過(guò)如下配置后就不一樣了

@ComponentScan(includeFilters = {
  @Filter(type = FilterType.ANNOTATION, classes = {Pack.class})
})
public class AppConfig {}

運(yùn)行結(jié)果

[..., com.pack.ioc.scan_component.AppConfig, a, c, b]

Spring默認(rèn)的@Component注解及我們自定義的@Pack注解都生效了。

  • 過(guò)濾類(lèi)型FilterType.ASPECTJ

與目標(biāo)類(lèi)匹配的AspectJ類(lèi)型表達(dá)式。

首先,自定義如下類(lèi)。

public class PackClass {
}

修改配置類(lèi)

@ComponentScan(includeFilters = {
  @Filter(
    type = FilterType.ASPECTJ, 
    pattern = {"com.pack..Pack*"}
  )
})
public class AppConfig {}

com.pack..Pack*:com.pack包及子包下的以Pack開(kāi)頭的類(lèi)都將匹配。

運(yùn)行結(jié)果

[..., com.pack.ioc.scan_component.AppConfig, a, b, packClass]

注:在本例中@ComponentScan掃描的包還是當(dāng)前AppConfig所在的包及其子包。

  • 過(guò)濾類(lèi)型FilterType.ASSIGNABLE_TYPE

目標(biāo)類(lèi)可以是這里給定的類(lèi)或接口。

首先,自定義DAO接口。

public interface DAO {
}
public class Person implements DAO {
}

修改配置類(lèi)

@ComponentScan(includeFilters = {
  @Filter(
    type = FilterType.ASSIGNABLE_TYPE, classes = {DAO.class}
  )
})
public class AppConfig {}

只要我們定義的類(lèi)實(shí)現(xiàn)了DAO接口都將匹配。

運(yùn)行結(jié)果

[..., com.pack.ioc.scan_component.AppConfig, a, b, person]

通過(guò)classes你可以指定多個(gè)接口或者是父類(lèi)。

  • 過(guò)濾類(lèi)型FilterType.REGEX

與目標(biāo)組件的類(lèi)名匹配的正則表達(dá)式。

@ComponentScan(includeFilters = {
  @Filter(
    type = FilterType.REGEX, 
    pattern = {"com\\.pack\\..*.Pack.*"}
  )
})
public class AppConfig {}

運(yùn)行結(jié)果

[..., com.pack.ioc.scan_component.AppConfig, a, b, packClass]

注意:在寫(xiě)正則表達(dá)式時(shí) "." 需要進(jìn)行轉(zhuǎn)義。

  • 過(guò)濾類(lèi)型FilterType.CUSTOM

org.springframework.core.type.TypeFilter接口的自定義實(shí)現(xiàn)。

public class PackTypeFilter implements TypeFilter {


  @Override
  public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
    AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata() ;
    return annotationMetadata.hasAnnotation(Pack.class.getName()) ;
  }
}

在自定義的類(lèi)型過(guò)濾中,我們判斷類(lèi)上是否存在@Pack。

修改配置類(lèi)

@ComponentScan(includeFilters = {
  @Filter(
    type = FilterType.CUSTOM, 
    classes = {PackTypeFilter.class}
  )
})
public class AppConfig {}

這不僅包括了內(nèi)置的過(guò)濾器會(huì)生效(過(guò)濾@Component注解),同時(shí)我們自定義的過(guò)濾器也會(huì)起到作用。

以上針對(duì)每一種過(guò)濾類(lèi)型講解完了,你是否有點(diǎn)暈,這里指定了type后,接下來(lái)是配置pattern還是classes屬性呢?大家記住如下組合即可。

類(lèi)型

配置的屬性

ANNOTATION、ASSIGNABLE_TYPE、CUSTOM

classes

ASPECTJ、REGEX

pattern

只有這兩種組合沒(méi)有其它組合。

2.5 指定lazyInit

指定掃描到的類(lèi)是否進(jìn)行延遲初始化。

@Component
public class A implements InitializingBean {


  @PostConstruct
  public void init() {
    System.err.println("A init...") ;
  }


  @Override
  public void afterPropertiesSet() throws Exception {
    System.err.println("A afterPropertiesSet...") ;
  }
}

修改配置類(lèi)

@ComponentScan(lazyInit = true)
public class AppConfig {}

運(yùn)行結(jié)果

圖片圖片

并沒(méi)有打印在A類(lèi)中定義的初始化回調(diào)。

2.6 指定useDefaultFilters

指示是否應(yīng)啟用對(duì)帶有@Component、@Repository、@Service或@Controller注解的類(lèi)的自動(dòng)檢測(cè)。

修改配置類(lèi)

@ComponentScan(
  useDefaultFilters = false, 
  includeFilters = {
    @Filter(
      type = FilterType.CUSTOM, 
      classes = {PackTypeFilter.class}
    )
})
public class AppConfig {}

運(yùn)行結(jié)果

[..., com.pack.ioc.scan_component.AppConfig, c]

我們定義的A,B兩個(gè)類(lèi)都沒(méi)有打印(這2個(gè)類(lèi)是有@Component注解的)。這說(shuō)明我們就關(guān)閉了默認(rèn)的過(guò)濾器功能。

2.7 指定nameGenerator

通過(guò)指定該屬性,掃描到的組件將通過(guò)該值來(lái)生成對(duì)應(yīng)的beanName。

自定義BeanNameGenerator

public class PackBeanNameGenerator extends AnnotationBeanNameGenerator {


  @Override
  public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
    String beanName = super.generateBeanName(definition, registry) ;
    beanName = beanName.replaceFirst("^.", beanName.substring(0, 1).toUpperCase()) ;
    return "pack" + beanName ;
  }
}

在這里我們將所有的beanName都添加一個(gè) pack 前綴。

修改配置類(lèi)

@ComponentScan(nameGenerator = PackBeanNameGenerator.class)
public class AppConfig {}

運(yùn)行結(jié)果

[..., com.pack.ioc.scan_component.AppConfig, packA, packB]

除配置類(lèi)外,其它beanName都以pack開(kāi)頭。

2.8 指定scopedProxy

指示是否應(yīng)為檢測(cè)到的組件生成代理。

首先,修改A類(lèi)如下:

@Scope
@Component
public class A implements InitializingBean {}

在類(lèi)A上添加了@Scope作用域注解。注:要使得scopedProxy生效你必須對(duì)bean定義作用域(只要有該注解即可,而至于什么作用域無(wú)所謂)。

修改配置類(lèi)

@ComponentScan(scopedProxy = ScopedProxyMode.TARGET_CLASS)
public class AppConfig {}

這里設(shè)置為代理目標(biāo)類(lèi)。

接下來(lái),我們做如下的測(cè)試

try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext()) {
  context.registerBean(AppConfig.class) ;
  context.refresh() ;
  System.out.println(Arrays.toString(context.getBeanDefinitionNames())) ;
  System.err.println(context.getBean(A.class).getClass().getName()) ;
}

運(yùn)行結(jié)果

圖片圖片

Bean A生成的是通過(guò)cglib代理后的對(duì)象。

2.9 指定scopeResolver

用于解析檢測(cè)到的組件的作用域。在默認(rèn)情況下檢測(cè)的是@Scope定義的作用域。

特別說(shuō)明:只有當(dāng)@ComponentScan中的scopedProxy屬性設(shè)置為ScopedProxyMode.DEFAULT時(shí),該屬性才會(huì)生效。

接下來(lái),通過(guò)實(shí)例講解。

首先,我們自定義作用域注解(為了體現(xiàn)自定義自定義ScopeMetadataResolver的意義)。

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PackScope {


  @AliasFor("scopeName")
  String value() default "";


  @AliasFor("value")
  String scopeName() default "";
  
  ScopedProxyMode proxyMode() default ScopedProxyMode.DEFAULT;
}

該自定義作用域注解與@Scope中定義的屬性一致。

自定義作用域解析器。

public class PackAnnotationScopeMetadataResolver extends AnnotationScopeMetadataResolver {


  public PackAnnotationScopeMetadataResolver() {
    setScopeAnnotationType(PackScope.class) ;
  }
}

解析器中設(shè)置我們自定義的作用域注解。

修改的類(lèi)A。

@PackScope(proxyMode = ScopedProxyMode.TARGET_CLASS)
@Component
public class A implements InitializingBean {}

運(yùn)行結(jié)果

圖片

自定義的作用域注解及自定義解析器生效了。

責(zé)任編輯:武曉燕 來(lái)源: Spring全家桶實(shí)戰(zhàn)案例源碼
相關(guān)推薦

2009-12-09 09:30:21

PHP foreach

2009-07-09 09:48:35

Google Chro微軟競(jìng)爭(zhēng)

2015-07-16 11:31:53

虛擬化SDN

2022-01-18 16:50:07

人工智能教育雙減

2025-01-14 10:39:49

2022-12-19 08:14:30

注解開(kāi)發(fā)配置

2021-03-19 17:37:04

數(shù)據(jù)庫(kù)

2012-12-27 10:58:24

KVMKVM概念

2022-02-20 07:28:13

Spring注解用法

2022-02-14 16:53:57

Spring項(xiàng)目數(shù)據(jù)庫(kù)

2023-08-08 09:49:01

2012-10-31 09:30:19

2022-05-10 14:08:56

云計(jì)算IT運(yùn)營(yíng)

2017-08-16 20:26:19

OTT網(wǎng)絡(luò)效應(yīng)監(jiān)管

2024-01-29 10:09:59

數(shù)據(jù)庫(kù)INT(3)INT(11)

2021-11-05 08:29:13

數(shù)據(jù)校驗(yàn)Spring

2024-03-25 00:20:00

AI短視頻

2012-08-15 10:50:51

IE6

2012-04-10 10:11:41

回顧Windows 8

2019-11-27 12:04:00

物聯(lián)網(wǎng)IIoT安全
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 国产精品一区二区久久精品爱微奶 | 国产黄色大片在线免费观看 | 乱码av午夜噜噜噜噜动漫 | 午夜在线精品偷拍 | 精品国产18久久久久久二百 | 中文字幕 在线观看 | 国产成人精品综合 | 日韩在线免费视频 | 久久在线 | 亚州国产| a免费视频 | 国产二区视频 | 欧美一级α片 | 91精品国产乱码久久久 | 一区二区日韩 | 中国免费黄色片 | 日韩欧美在线一区二区 | 欧美精品在线一区 | 色偷偷人人澡人人爽人人模 | 在线播放中文字幕 | 午夜欧美 | 日韩成人在线播放 | 天天干精品| 91九色婷婷 | 日本高清中文字幕 | 欧美一级电影免费观看 | 91玖玖| 亚洲一区二区三区在线视频 | 中文字幕一区二区三区在线观看 | 久久精品a级毛片 | 欧美一区二区三区在线视频 | 国产精品毛片一区二区在线看 | 国产精品片 | av色站 | 色就是色欧美 | 亚洲一区二区视频 | 午夜影院在线视频 | 日韩欧美国产精品一区二区 | 精品久久久久久一区二区 | 搞黄网站在线观看 | 午夜免费网站 |