99re热这里只有精品视频,7777色鬼xxxx欧美色妇,国产成人精品一区二三区在线观看,内射爽无广熟女亚洲,精品人妻av一区二区三区

Micronaut Bean 注釋元數(shù)據(jù)

2023-03-07 13:39 更新

Java 的 AnnotatedElement API 提供的方法通常不提供在不加載注釋本身的情況下內(nèi)省注釋的能力。它們也不提供任何內(nèi)省注釋構(gòu)造型的能力(通常稱(chēng)為元注釋?zhuān)蛔⑨寴?gòu)造型是用另一個(gè)注釋對(duì)一個(gè)注釋進(jìn)行注釋的地方,本質(zhì)上是繼承它的行為)。

為了解決這個(gè)問(wèn)題,許多框架生成運(yùn)行時(shí)元數(shù)據(jù)或執(zhí)行昂貴的反射來(lái)分析類(lèi)的注釋。

Micronaut 改為在編譯時(shí)生成此注解元數(shù)據(jù),從而避免了昂貴的反射并節(jié)省了內(nèi)存。

BeanContext API 可用于獲取對(duì)實(shí)現(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 實(shí)例,無(wú)論 @Controller 是直接使用還是通過(guò)注釋構(gòu)造型繼承。

請(qǐng)注意,getAnnotation 方法和該方法的變體返回 AnnotationValue 類(lèi)型而不是 Java 注釋。這是設(shè)計(jì)使然,您通常應(yīng)該在讀取注釋值時(shí)嘗試使用此 API,因?yàn)閺男阅芎蛢?nèi)存消耗的角度來(lái)看,合成代理實(shí)現(xiàn)更糟糕。

如果您需要對(duì)注釋實(shí)例的引用,您可以使用 synthesize 方法,它創(chuàng)建一個(gè)實(shí)現(xiàn)注釋接口的運(yùn)行時(shí)代理:

合成注解實(shí)例

Controller controllerAnn = definition.synthesize(Controller.class);

但是,不推薦使用這種方法,因?yàn)樗枰瓷洳⒂捎谑褂眠\(yùn)行時(shí)生成的代理而增加內(nèi)存消耗,并且應(yīng)該作為最后的手段使用,例如,如果您需要注釋的實(shí)例來(lái)與第三方集成圖書(shū)館。

注解繼承

Micronaut 將遵守 Java 的 AnnotatedElement API 中定義的關(guān)于注解繼承的規(guī)則:

  • 使用 Inherited 進(jìn)行元注釋的注釋將通過(guò) AnnotationMetadata API 的 getAnnotation* 方法提供,而直接聲明的注釋則通過(guò) getDeclaredAnnotation* 方法提供。

  • 未使用 Inherited 進(jìn)行元注釋的注釋將不會(huì)包含在元數(shù)據(jù)中

Micronaut 與 AnnotatedElement API 的不同之處在于它將這些規(guī)則擴(kuò)展到方法和方法參數(shù),以便:

  • 任何用 Inherited 注釋并出現(xiàn)在被子接口或類(lèi) B 覆蓋的接口或超類(lèi) A 的方法上的注釋都將繼承到可通過(guò) ExecutableMethod API 從 BeanDefinition 或 AOP 攔截器檢索的 AnnotationMetadata 中。

  • 任何用 Inherited 注釋并出現(xiàn)在被子接口或類(lèi) B 覆蓋的接口或超類(lèi) A 的方法參數(shù)上的注釋都將繼承到可通過(guò) Argument 接口從 ExecutableMethod API 的 getArguments 方法檢索的 AnnotationMetadata 中。

通常,您可能希望覆蓋的一般行為默認(rèn)情況下不會(huì)繼承,包括 Bean 范圍、Bean 限定符、Bean 條件、驗(yàn)證規(guī)則等。

如果您希望在子類(lèi)化時(shí)繼承特定的范圍、限定符或一組要求,那么您可以定義一個(gè)用@Inherited 注釋的元注釋。例如:

定義繼承的元注解

 Java Groovy  Kotlin 
import io.micronaut.context.annotation.AliasFor;
import io.micronaut.context.annotation.Requires;
import io.micronaut.core.annotation.AnnotationMetadata;
import jakarta.inject.Named;
import jakarta.inject.Singleton;

import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Inherited // (1)
@Retention(RetentionPolicy.RUNTIME)
@Requires(property = "datasource.url") // (2)
@Named // (3)
@Singleton // (4)
public @interface SqlRepository {
    @AliasFor(annotation = Named.class, member = AnnotationMetadata.VALUE_MEMBER) // (5)
    String value() default "";
}
import io.micronaut.context.annotation.AliasFor
import io.micronaut.context.annotation.Requires
import io.micronaut.core.annotation.AnnotationMetadata
import jakarta.inject.Named
import jakarta.inject.Singleton

import java.lang.annotation.Inherited
import java.lang.annotation.Retention
import java.lang.annotation.RetentionPolicy

@Inherited // (1)
@Retention(RetentionPolicy.RUNTIME)
@Requires(property = "datasource.url") // (2)
@Named // (3)
@Singleton // (4)
@interface SqlRepository {
    @AliasFor(annotation = Named.class, member = AnnotationMetadata.VALUE_MEMBER) // (5)
    String value() default "";
}
import io.micronaut.context.annotation.Requires
import jakarta.inject.Named
import jakarta.inject.Singleton
import java.lang.annotation.Inherited

@Inherited // (1)
@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
@Requires(property = "datasource.url") // (2)
@Named // (3)
@Singleton // (4)
annotation class SqlRepository(
    val value: String = ""
)
  1. 注解聲明為@Inherited

  2. Bean Conditions 將被子類(lèi)繼承

  3. Bean 限定符將由子類(lèi)繼承

  4. Bean Scopes 將被子類(lèi)繼承

  5. 你也可以給注解起別名,它們會(huì)被繼承

使用此元注釋?zhuān)梢詫⒆⑨屘砑拥匠?lèi):

在超類(lèi)上使用繼承的元注釋

 Java Groovy  Kotlin 
@SqlRepository
public abstract class BaseSqlRepository {
}
@SqlRepository
abstract class BaseSqlRepository {
}
@SqlRepository
abstract class BaseSqlRepository

然后子類(lèi)將繼承所有注釋?zhuān)?

在子類(lèi)中繼承注解

 Java Groovy  Kotlin 
import jakarta.inject.Named;
import javax.sql.DataSource;

@Named("bookRepository")
public class BookRepository extends BaseSqlRepository {
    private final DataSource dataSource;

    public BookRepository(DataSource dataSource) {
        this.dataSource = dataSource;
    }
}
import jakarta.inject.Named
import javax.sql.DataSource

@Named("bookRepository")
class BookRepository extends BaseSqlRepository {
    private final DataSource dataSource

    BookRepository(DataSource dataSource) {
        this.dataSource = dataSource
    }
}
import jakarta.inject.Named
import javax.sql.DataSource

@Named("bookRepository")
class BookRepository(private val dataSource: DataSource) : BaseSqlRepository()

子類(lèi)必須至少有一個(gè) bean 定義注釋?zhuān)绶秶蛳薅ǚ?/p>

別名/映射注釋

有時(shí)您可能希望將注釋成員的值作為另一個(gè)注釋成員的值的別名。為此,請(qǐng)使用@AliasFor 注釋。

例如,一個(gè)常見(jiàn)的用例是注釋定義了 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 "";
}
  1. value 成員也設(shè)置了 id 成員

  2. id 成員也設(shè)置了 value 成員

有了這些別名,無(wú)論您定義@Client("foo") 還是@Client(id="foo"),value 和 id 成員都將被設(shè)置,從而更容易解析和使用注釋。

如果您無(wú)法控制注釋?zhuān)硪环N方法是使用 AnnotationMapper。要?jiǎng)?chuàng)建 AnnotationMapper,請(qǐng)執(zhí)行以下操作:

  • 實(shí)現(xiàn) AnnotationMapper 接口

  • 定義一個(gè) META-INF/services/io.micronaut.inject.annotation.AnnotationMapper 文件引用實(shí)現(xiàn)類(lèi)

  • 將包含實(shí)現(xiàn)的 JAR 文件添加到 annotationProcessor 類(lèi)路徑(Kotlin 的 kapt)

因?yàn)?nbsp;AnnotationMapper 實(shí)現(xiàn)必須在注釋處理器類(lèi)路徑上,所以它們通常應(yīng)該在一個(gè)包含很少外部依賴項(xiàng)的項(xiàng)目中,以避免污染注釋處理器類(lèi)路徑。

以下是改進(jìn) JPA 實(shí)體的內(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()
        );
    }
}
  1. map 方法接收帶有注釋值的 AnnotationValue。

  2. 可以返回一個(gè)或多個(gè)注釋?zhuān)诒纠袨锧Transient。

上面的示例實(shí)現(xiàn)了 NamedAnnotationMapper 接口,該接口允許將注釋與運(yùn)行時(shí)代碼混合。要針對(duì)具體注釋類(lèi)型進(jìn)行操作,請(qǐng)改用 TypedAnnotationMapper,但請(qǐng)注意,它需要注釋類(lèi)本身位于注釋處理器類(lèi)路徑中。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)