日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

java 外部覆盖内部配置,Spring 与自定义注解、外部配置化的结合使用

發布時間:2025/4/5 javascript 51 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java 外部覆盖内部配置,Spring 与自定义注解、外部配置化的结合使用 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Spring 與自定義注解、外部配置化的結合使用

一、Java注解的簡單介紹

注解,也叫Annotation、標注,是 Java 5 帶來的新特性。

可使用范圍

類、字段、方法、參數、構造函數、包等,具體可參閱枚舉類 java.lang.annotation.ElementType

生命周期(摘自 劉大飛的博客 )

RetentionPolicy.SOURCE 注解只保留在源文件,當Java文件編譯成class文件的時候,注解被遺棄

RetentionPolicy.CLASS 注解被保留到class文件,但 jvm 加載class文件時候被遺棄,這是默認的生命周期

RetentionPolicy.RUNTIME 注解不僅被保存到class文件中,jvm 加載class文件之后,仍然存在

使用方式

可以使用反射獲取注解的內容,具體如何使用請自己百度,可參考這篇Java注解完全解析,這里不是重點,不多做介紹

二、Spring的 @Import注解

@Import 注解是Spring用來注入 Spring Bean 的一種方式,可以用來修飾別的注解,也可以直接在Springboot配置類上使用。

它只有一個value屬性需要設置,來看一下源碼

public @interface Import {

Class>[] value();

}

這里的 value屬性只接受三種類型的Class:

被@Configuration 修飾的配置類

接口org.springframework.context.annotation.ImportBeanDefinitionRegistrar的實現類

接口org.springframework.context.annotation.ImportSelector的實現類

下面針對三種類型的Class分別做簡單介紹,中間穿插自定義注解與外部配置的結合使用方式。

三、被@Configuration 修飾的配置類

像 Springboot 中的配置類一樣正常使用,需要注意的是,如果該類的包路徑已在Springboot啟動類上配置的掃描路徑下,則不需要再重新使用@Import導入了,因為@Import的目的是注入bean,但是Springboot啟動類自動掃描已經可以注入你想通過@Import導入的bean了。

這種Class可以進行如下拓展

繼承各種Aware接口, 獲取對應的信息(如果不清楚Aware接口在Spring當中的作用,請自行百度),如,繼承EnviromentAware,可以拿到Spring的環境配置信息,進而從中拿到 @Value所需要的值,如 environment.getProperty("user.username")

使用@Autowire、@Resource、@Value注入各種所需Spring 資源

像普通Spring Bean 一樣使用該類

更多使用方式,請自行百度。

四、接口org.springframework.context.annotation.ImportBeanDefinitionRegistrar的實現類

當@Import修飾自定義注解時候,通常會導入這種類。

來看一下接口定義

public interface ImportBeanDefinitionRegistrar {

default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry,

BeanNameGenerator importBeanNameGenerator) {

registerBeanDefinitions(importingClassMetadata, registry);

}

/**

* importingClassMetadata 被@Import修飾的自定義注解的元信息,可以獲得屬性集合

* registry Spring bean注冊中心

**/

default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

}

通過這種方式,我們可以根據自定義注解配置的屬性值來注入Spring Bean 信息。

來看如下案例,我們通過一個注解,啟動RocketMq的消息發送器:

@SpringBootApplication

@EnableMqProducer(group="xxx")

public class App {

public static void main(String[] args) {

SpringApplication.run(App.class);

}

}

這是一個服務項目的啟動類,這個服務開啟了RocketMq的一個發送器,并且分到xxx組里。

來下一下@EnableMqProducer注解

@Retention(RetentionPolicy.RUNTIME)

@Target({ElementType.TYPE})

@Documented

@Import({XXXRegistrar.class,XXXConfig.class})

public @interface EnableMqProducer {

String group() default "DEFAULT_PRODUCER_GROUP";

String instanceName() default "defaultProducer";

boolean retryAnotherBrokerWhenNotStoreOK() default true;

}

這里使用@Import導入了兩個配置類,第一個是接口org.springframework.context.annotation.ImportBeanDefinitionRegistrar的實現類,第二個是被@Configuration 修飾的配置類

我們看第一個類,這個類注入了一個DefaultMQProducer到Spring 容器中,使業務方可以直接通過@Autowired注入使用

public class XXXRegistrar implements ImportBeanDefinitionRegistrar {

@Override

public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

AnnotationAttributes attributes = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(EnableMqProducer.class.getName()));

registerBeanDefinitions(attributes, registry);

}

private void registerBeanDefinitions(AnnotationAttributes attributes, BeanDefinitionRegistry registry) {

//獲取配置

String group = attributes.getString("group");

//省略部分代碼...

//添加要注入的類的字段值

Map values = new HashMap<>();

//這里有的同學可能不清楚為什么key是這個

//這里的key就是DefaultMQProducer的字段名

values.put("producerGroup", group);

//省略部分代碼

//注冊到Spring中

BeanRegistrationUtil.registerBeanDefinitionIfNotExists(registry, DefaultMQProducer.class.getName(), DefaultMQProducer.class, values);

}

到這里,我們已經注入了一個DefaultMQProducer的實例到Spring容器中,但是這個實例,還不完整,比如,還沒有啟動,nameServer地址還沒有配置,可外部配置的屬性還沒有覆蓋實例已有的值(nameServer地址建議外部配置)。好消息是,我們已經可以通過注入來使用這個實例了。

上面遺留的問題,就是第二個類接下來要做的事。

來看第二個配置類

@Configuration

@Role(BeanDefinition.ROLE_INFRASTRUCTURE)

@EnableConfigurationProperties(XxxProperties.class) //Spring提供的配置自動映射功能,配置后可直接注入

public class XXXConfig {

@Resource //直接注入

private XxxProperties XxxProperties;

@Autowired //注入上一步生成的實例

private DefaultMQProducer producer;

@PostConstruct

public void init() {

//省略部分代碼

//獲取外部配置的值

String nameServer = XxxProperties.getNameServer();

//修改實例

producer.setNamesrvAddr(nameServer);

//啟動實例

try {

this.producer.start();

} catch (MQClientException e) {

throw new RocketMqException("mq消息發送實例啟動失敗", e);

}

}

@PreDestroy

public void destroy() {

producer.shutdown();

}

到這里,通過自定義注解和外部配置的結合,一個完整的消息發送器就可以使用了,但方式有取巧之嫌,因為在消息發送器啟動之前,不知道還有沒有別的類使用了這個實例,這是不安全的。

五、接口org.springframework.context.annotation.ImportSelector的實現類

首先看一下接口

public interface ImportSelector {

/**

* importingClassMetadata 注解元信息,可獲取自定義注解的屬性集合

* 根據自定義注解的屬性,或者沒有屬性,返回要注入Spring的Class全限定類名集合

如:XXX.class.getName(),Spring會自動注入XXX的一個實例

*/

String[] selectImports(AnnotationMetadata importingClassMetadata);

@Nullable

default Predicate getExclusionFilter() {

return null;

}

}

這個接口的實現類如果沒有進行@Aware拓展,功能比較單一,因為我們無法參與Spring Bean 的構建過程,只是告訴Spring 要注入的Bean的名字。不再詳述。

六、總結

通過接口和配置類的靈活結合,可以實現自定義注解的配置化設計,歸根到底是Spring Bean的靈活構建,如果你有更好更優雅的方式,歡迎留言指教。

總結

以上是生活随笔為你收集整理的java 外部覆盖内部配置,Spring 与自定义注解、外部配置化的结合使用的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。