W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
Java 的 AnnotatedElement API 提供的方法通常不提供在不加載注釋本身的情況下內(nèi)省注釋的能力。它們也不提供任何內(nèi)省注釋構(gòu)造型的能力(通常稱為元注釋;注釋構(gòu)造型是用另一個注釋對一個注釋進(jìn)行注釋的地方,本質(zhì)上是繼承它的行為)。
為了解決這個問題,許多框架生成運行時元數(shù)據(jù)或執(zhí)行昂貴的反射來分析類的注釋。
Micronaut 改為在編譯時生成此注解元數(shù)據(jù),從而避免了昂貴的反射并節(jié)省了內(nèi)存。
BeanContext API 可用于獲取對實現(xiàn) AnnotationMetadata 接口的 BeanDefinition 的引用。
例如,以下代碼獲取所有帶有特定構(gòu)造型注釋的 bean 定義:
按構(gòu)造型查找 Bean 定義
BeanContext beanContext = ... // obtain the bean context
Collection<BeanDefinition> definitions =
beanContext.getBeanDefinitions(Qualifiers.byStereotype(Controller.class))
for (BeanDefinition definition : definitions) {
AnnotationValue<Controller> controllerAnn = definition.getAnnotation(Controller.class);
// do something with the annotation
}
上面的示例找到所有用 @Controller 注釋的 BeanDefinition 實例,無論 @Controller 是直接使用還是通過注釋構(gòu)造型繼承。
請注意,getAnnotation 方法和該方法的變體返回 AnnotationValue 類型而不是 Java 注釋。這是設(shè)計使然,您通常應(yīng)該在讀取注釋值時嘗試使用此 API,因為從性能和內(nèi)存消耗的角度來看,合成代理實現(xiàn)更糟糕。
如果您需要對注釋實例的引用,您可以使用 synthesize 方法,它創(chuàng)建一個實現(xiàn)注釋接口的運行時代理:
合成注解實例
Controller controllerAnn = definition.synthesize(Controller.class);
但是,不推薦使用這種方法,因為它需要反射并由于使用運行時生成的代理而增加內(nèi)存消耗,并且應(yīng)該作為最后的手段使用,例如,如果您需要注釋的實例來與第三方集成圖書館。
注解繼承
Micronaut 將遵守 Java 的 AnnotatedElement API 中定義的關(guān)于注解繼承的規(guī)則:
使用 Inherited 進(jìn)行元注釋的注釋將通過 AnnotationMetadata API 的 getAnnotation* 方法提供,而直接聲明的注釋則通過 getDeclaredAnnotation* 方法提供。
未使用 Inherited 進(jìn)行元注釋的注釋將不會包含在元數(shù)據(jù)中
Micronaut 與 AnnotatedElement API 的不同之處在于它將這些規(guī)則擴展到方法和方法參數(shù),以便:
任何用 Inherited 注釋并出現(xiàn)在被子接口或類 B 覆蓋的接口或超類 A 的方法上的注釋都將繼承到可通過 ExecutableMethod API 從 BeanDefinition 或 AOP 攔截器檢索的 AnnotationMetadata 中。
任何用 Inherited 注釋并出現(xiàn)在被子接口或類 B 覆蓋的接口或超類 A 的方法參數(shù)上的注釋都將繼承到可通過 Argument 接口從 ExecutableMethod API 的 getArguments 方法檢索的 AnnotationMetadata 中。
通常,您可能希望覆蓋的一般行為默認(rèn)情況下不會繼承,包括 Bean 范圍、Bean 限定符、Bean 條件、驗證規(guī)則等。
如果您希望在子類化時繼承特定的范圍、限定符或一組要求,那么您可以定義一個用@Inherited 注釋的元注釋。例如:
定義繼承的元注解
Java | Groovy | Kotlin |
|
|
|
注解聲明為@Inherited
Bean Conditions 將被子類繼承
Bean 限定符將由子類繼承
Bean Scopes 將被子類繼承
你也可以給注解起別名,它們會被繼承
使用此元注釋,您可以將注釋添加到超類:
在超類上使用繼承的元注釋
Java | Groovy | Kotlin |
|
|
|
然后子類將繼承所有注釋:
在子類中繼承注解
Java | Groovy | Kotlin |
|
|
|
子類必須至少有一個 bean 定義注釋,例如范圍或限定符。
別名/映射注釋
有時您可能希望將注釋成員的值作為另一個注釋成員的值的別名。為此,請使用@AliasFor 注釋。
例如,一個常見的用例是注釋定義了 value() 成員,但也支持其他成員。例如 @Client 注解:
@Client 注解
public @interface Client {
/**
* @return The URL or service ID of the remote service
*/
@AliasFor(member = "id") (1)
String value() default "";
/**
* @return The ID of the client
*/
@AliasFor(member = "value") (2)
String id() default "";
}
value 成員也設(shè)置了 id 成員
id 成員也設(shè)置了 value 成員
有了這些別名,無論您定義@Client("foo") 還是@Client(id="foo"),value 和 id 成員都將被設(shè)置,從而更容易解析和使用注釋。
如果您無法控制注釋,另一種方法是使用 AnnotationMapper。要創(chuàng)建 AnnotationMapper,請執(zhí)行以下操作:
實現(xiàn) AnnotationMapper 接口
定義一個 META-INF/services/io.micronaut.inject.annotation.AnnotationMapper 文件引用實現(xiàn)類
將包含實現(xiàn)的 JAR 文件添加到 annotationProcessor 類路徑(Kotlin 的 kapt)
因為 AnnotationMapper 實現(xiàn)必須在注釋處理器類路徑上,所以它們通常應(yīng)該在一個包含很少外部依賴項的項目中,以避免污染注釋處理器類路徑。
以下是改進(jìn) JPA 實體的內(nèi)省功能的示例 AnnotationMapper。
EntityIntrospectedAnnotationMapper 映射器示例
public class EntityIntrospectedAnnotationMapper implements NamedAnnotationMapper {
@NonNull
@Override
public String getName() {
return "javax.persistence.Entity";
}
@Override
public List<AnnotationValue<?>> map(AnnotationValue<Annotation> annotation, VisitorContext visitorContext) { (1)
final AnnotationValueBuilder<Introspected> builder = AnnotationValue.builder(Introspected.class)
// don't bother with transients properties
.member("excludedAnnotations", "javax.persistence.Transient"); (2)
return Arrays.asList(
builder.build(),
AnnotationValue.builder(ReflectiveAccess.class).build()
);
}
}
map 方法接收帶有注釋值的 AnnotationValue。
可以返回一個或多個注釋,在本例中為@Transient。
上面的示例實現(xiàn)了 NamedAnnotationMapper 接口,該接口允許將注釋與運行時代碼混合。要針對具體注釋類型進(jìn)行操作,請改用 TypedAnnotationMapper,但請注意,它需要注釋類本身位于注釋處理器類路徑中。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: