文章目錄
-
- 元件掃描
- @Component
- 元注解群組合注解
- 元件内部定義Bean中繼資料
- 為自動檢測元件命名
- 為自動檢測的元件提供作用域
- 生成候選元件的索引
上一篇文章我們講到了annotation-config配置,它主要用于bean内部的屬性注入。而bean本身則需要通過配置的方式來定義。如果想使用配置的方式來定義bean,則可以使用component-scan,如下:
<context:component-scan base-package="com.flydean"/>
component-scan會掃描類路徑裡面的注解注解,包括(@Component, @Repository, @Service,
@Controller, @RestController, @ControllerAdvice, 和@Configuration ), 當然component-scan預設包含了annotation-config,我們可以直接在這些配置bean中使用上篇文章講到的注解。
@Component表示該bean是一個元件,@Component是任何Spring管理的元件的通用原型。@Repository、@Service和@Controller是@Component針對更具體的用例(分别在持久性、服務和表示層中)的特殊注解。是以,您可以用@Component注解元件類,但是,通過用@Repository、@Service或@Controller注解它們,您的類更具有語義性。通常更适合在AOP中做進一步的業務邏輯處理。
所謂元注解就是可以用在其他注解中的注解。 像之前提到的@Component就是@Service的元注解。如下:
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Component public @interface Service {// ....}
@Component會導緻@Service和@Component一樣被對待。
當然你也可以組合使用元注解,或者自定義元注解。例如,Spring的@SessionScope注解将作用域名稱寫死為session,但仍允許自定義proxyMode。以下清單顯示了sessionScope注解的定義:
@Target({ElementType.TYPE, ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@Documented@Scope(WebApplicationContext.SCOPE_SESSION)public @Interface SessionScope {/**
* Alias for {@link Scope#proxyMode}.
* <p>Defaults to {@link ScopedProxyMode#TARGET_CLASS}.
*/@AliasFor(annotation = Scope.class)ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;}
你可以不定義@SessionScope裡面的proxyMode, 如下:
@Service@SessionScopepublic class SessionScopedService {// ...}
你也可以重寫proxyMode,如下:
@Service@SessionScope(proxyMode = ScopedProxyMode.INTERFACES)public class SessionScopedUserService implements UserService {// ...}
#@ComponentScan和filters
上面我們講到,要是要使用元件掃描,需要在XML配置context:component-scan, 其實也可以使用注解的形式,如下所示:
@Configuration@ComponentScan(basePackages = "com.flydean.beans")public class AppConfig {}
@ComponentScan可以配置一些filters用來過濾不需要的元件。如下所示:
@Configuration@ComponentScan(basePackages = "com.flydean.beans",includeFilters = @ComponentScan.Filter(type = FilterType.REGEX, pattern = ".*Stub.*Repository"),excludeFilters = @ComponentScan.Filter(BeanA.class))public class BeanAConfig {}
下表是支援的filter類型和例子:
Filter type | 表達式例子 | 描述 |
---|---|---|
annotation(預設) | org.example.SomeAnnotation | type基本的目标元件 |
assignable | org.example.SomeClass | 目标元件可配置設定給(擴充或實作)的類(或接口)。 |
aspectj | org.example…*Service+ | 比對目标元件的AspectJ類型 |
regex | org\.example\.Default.* | 比對目标主鍵内名的正規表達式 |
custom | org.example.MyTypeFilter | org.springframework.core.type .TypeFilter的自定義實作 |
Spring元件還可以為容器提供bean定義中繼資料。您可以使用用于在@Configuration annotated類中定義bean中繼資料的相同@Bean注解來實作這一點。以下示例顯示了如何執行此操作:
@Componentpublic class FactoryMethodComponent {@Bean@Qualifier("public")public BeanA publicInstance() {return new BeanA();}public void doWork() {// Component method implementation omitted}}
InjectionPoint
從SpringFramework4.3開始,還可以聲明InjectionPoint類型的工廠方法參數,來建立Bean。
注意,這隻适用于bean執行個體的實際建立,而不适用于現有執行個體的注入。是以,這個特性對于原型範圍的bean最有意義。
@Componentpublic class InjectPointFactoryMethodComponent {@Bean@Scope("prototype")public BeanA prototypeInstance(InjectionPoint injectionPoint) {return new BeanA("prototypeInstance for " + injectionPoint.getMember());}}
正常Spring元件中的@Bean方法的處理方式與Spring@Configuration類中的對應方法不同。不同的是,@Component類沒有用cglib來增強以截獲方法和字段的調用。cglib代理是調用@Configuration classes中通過@Bean methods内的方法或字段建立對協作對象的bean中繼資料引用的方法。
你可以将@Bean方法聲明為靜态方法,允許在不将其包含的配置類建立為執行個體的情況下調用它們。在定義post-processor bean(例如,BeanFactoryPostProcessor或BeanPostProcessor類型)時,這是特别有意義的,因為這樣的bean在容器生命周期的早期就被初始化,應該避免在此時觸發配置的其他部分。
由于技術限制,對static @Bean方法的調用永遠不會被容器截獲,即使是在@Configuration類(如本節前面所述)中也是如此:cglib子類隻能重寫非靜态方法。是以,直接調用另一個@Bean方法相當于标準Java的new方法,導緻從工廠方法本身直接傳回一個獨立的執行個體。
要注意: @Configuration類中的正常@Bean方法必須是可重寫的,也就是說,它們不能聲明為私有或最終的。
預設情況下,可以提供value屬性給@Component、@Repository、@Service和@Controller),進而為Bean命名。
如果這樣的注解不包含value,則預設bean名稱生成器将傳回小寫的非限定類名。例如,如果檢測到以下元件類,則名稱為myMovieLister和movieFinderImpl:
@Service("myMovieLister")public class SimpleMovieLister {// ...}
@Repositorypublic class MovieFinderImpl implements MovieFinder {// ...}
如果您不想依賴預設的bean命名政策,可以提供一個自定義的bean命名政策。首先,實作BeanNameGenerator接口,并確定包含一個預設的無參數構造函數。然後,在配置掃描器時提供完全限定的類名,如下面的示例注解和bean定義所示:
public class MyNameGenerator implements BeanNameGenerator {@Overridepublic String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {return null;}}
@Configuration@ComponentScan(basePackages = "com.flydean", nameGenerator = MyNameGenerator.class)public class BeanNameConfig {}
與一般的Spring管理元件一樣,自動檢測元件的預設和最常見的作用域是singleton。但是,有時您需要一個可以由@Scope注解指定的不同範圍。可以在注解中提供作用域的名稱,如下示例所示:
@Scope("prototype")@Component("beanA")public class BeanA {public BeanA(){}public BeanA(String name){}}
自定義範圍解析
要為範圍解析提供自定義政策,而不是依賴基于注解的方法,可以實作ScopeMetadataResolver接口。如下所示:
public class MyScopeResolver implements ScopeMetadataResolver {@Overridepublic ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {return null;}}
@Configuration@ComponentScan(basePackages = "com.flydean", scopeResolver = MyScopeResolver.class)public class BeanScopeResolverConfig {}
scoped-proxy
當使用某些非單例作用域時,可能需要為作用域對象生成代理。為此,元件掃描元素上可以有一個scoped-proxy 屬性。三個可能的值是:no、interfaces和targetClass。例如,以下配置将生成标準JDK動态代理:
@Configuration@ComponentScan(basePackages = "com.flydean", scopedProxy = ScopedProxyMode.INTERFACES)public class ScopedProxyConfig {}
雖然類路徑掃描速度非常快,但是可以通過在編譯時建立一個靜态候選清單來提高大型應用程式的啟動性能。
要生成索引,需要每個子產品添加一個附加依賴項,該子產品包含作為元件掃描指令目标的元件。下面的示例說明如何使用Maven:
<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context-indexer</artifactId><version>5.1.8.RELEASE</version><optional>true</optional></dependency></dependencies>
- 區塊鍊從入門到放棄系列教程-涵蓋密碼學,超級賬本,以太坊,Libra,比特币等持續更新
- Spring Boot 2.X系列教程:七天從無到有掌握Spring Boot-持續更新
- Spring 5.X系列教程:滿足你對Spring5的一切想象-持續更新
- java程式員從小工到專家成神之路(2020版)-持續更新中,附詳細文章教程