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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

idea去掉无用import类_@Import注解的魅力

發(fā)布時間:2024/10/14 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 idea去掉无用import类_@Import注解的魅力 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

? ? 本篇主要介紹Spring注解@Import的魅力所在:它能讓你高度自由的定義配置類裝載規(guī)則與Bean注冊邏輯。@Import是Spring體系中的一個比較重要的注解,下面讓我們一起看看它都有哪些神奇的魅力吧!

注冊Bean

?? @Import第一個功能就是注冊Bean到Spring容器中,用法非常簡單,將需要注冊到Spring的類通過@Import直接導(dǎo)入即可,這時候注冊的Bean對應(yīng)的名稱為類完全限定名。如下所示:

package?com.swj.mj.autoconfig.service;

@Slf4j
public?class?HelloService?{

????public?HelloService()?{
????????log.info("HelloService?Initialization...");
????}

????public?String?sayHello(String?name)?{
????????return?"Hello?"?+?name;
????}

}

? ??首先任意定義一個類,然后我們直接在某個Bean或者配置類上通過@Import(HelloService.class)方法注冊Bean,如下:

package?com.swj.mj.web.hello;

@RestController
@AllArgsConstructor
@RequestMapping("/hello")
@Import(HelloService.class)
public?class?HelloController?implements?ApplicationContextAware?{

????private?static?ApplicationContext?appCtx;
????private?final?HelloService?helloService;

????@GetMapping
????public?Map?hello(String?name)?{
????????String?qualifiedBeanName?=?HelloService.class.getName();
????????assert?appCtx.containsBean(qualifiedBeanName)?:?"Spring容器中找不到名稱為"?+?qualifiedBeanName?+?"的Bean";
????????String[]?beanNames?=?appCtx.getBeanNamesForType(HelloService.class);
????????assert?beanNames.length?==?1?&&?qualifiedBeanName.equals(beanNames[0]);
????????return?ImmutableMap.of("name",?name,?"helloResult",?helloService.sayHello(name));
????}

????@Override
????public?void?setApplicationContext(ApplicationContext?applicationContext)?throws?BeansException?{
????????appCtx?=?applicationContext;
????}

}

? ??創(chuàng)建一個啟動類:

package?com.swj.mj.web;

@SpringBootApplication
public?class?WebApplication?{

????public?static?void?main(String[]?args)?throws?Exception?{
????????SpringApplication.run(WebApplication.class,?args);
????}

}

? ? 添加JVM選項-ea(激活斷言功能)并啟動容器后(啟動類的所在包路徑為com.swj.mj.web,并且沒有額外配置掃描包,所以默認(rèn)掃描的包是com.swj.mj.web),可以看到如下日志打印,說明@Import可以用來注冊Bean。

@Import注冊SpringBean

? ??同時,請求后可以看到兩個斷言都成立,說明通過@Import注冊的SpringBean的beanName為類對應(yīng)的類完全限定名。

@Import注冊的SpringBean對應(yīng)名稱

? ??如果我們?nèi)サ袅?#64;Import(HelloService.class),那么應(yīng)用啟動后將直接失敗并終止:

去掉@Import后將直接找不到類以致于啟動失敗

導(dǎo)入配置類

? ??第二個功能是直接導(dǎo)入配置類。我們在原先的基礎(chǔ)上新增一個配置類HelloServiceConfiguration:

@Configuration
public?class?HelloServiceConfiguration?{

????@Bean
????@ConditionalOnMissingBean
????public?HelloService?helloService()?{
????????return?new?HelloService();
????}

}

? ??該配置類會在容器中沒有helloService這個Bean時自動注冊HelloService。然后修改HelloController:

@RestController
@AllArgsConstructor
@RequestMapping("/hello")
@Import(HelloServiceConfiguration.class)
public?class?HelloController?implements?ApplicationContextAware?{

????private?static?ApplicationContext?appCtx;
????private?final?HelloService?helloService;

????@GetMapping
????public?Map?hello(String?name)?{
????????String?beanName?=?"helloService";
????????assert?appCtx.containsBean(beanName)?:?"Spring容器中找不到名稱為"?+?beanName?+?"的Bean";
????????String[]?beanNames?=?appCtx.getBeanNamesForType(HelloService.class);
????????assert?beanNames.length?==?1?&&?beanName.equals(beanNames[0]);
????????return?ImmutableMap.of("name",?name,?"helloResult",?helloService.sayHello(name));
????}

????@Override
????public?void?setApplicationContext(ApplicationContext?applicationContext)?throws?BeansException?{
????????appCtx?=?applicationContext;
????}

}

? ??這里通過@Import(HelloServiceConfiguration.class)直接導(dǎo)入配置類,由配置類注冊HelloService,這時候的beanName就不是類完全限定名了,而是方法名helloService。

? ??實際上HelloServiceConfiguration同樣會被注冊到Spring容器中,通過appCtx.getBean(HelloServiceConfiguration.class)可以得到配置類。所以可以說第一個功能與第二個功能是重合的,這點在源碼上也可以得到解釋,具體可以參考o(jì)rg.springframework.context.annotation.ConfigurationClassParser#processImports。本篇不講源碼哈,只介紹如何使用。

選擇性裝載配置類

? ??第三個功能是通過實現(xiàn)org.springframework.context.annotation.ImportSelector接口完成動態(tài)開啟配置類。

? ??首先看一下ImportSelector接口的定義:

public?interface?ImportSelector?{

?/**
??*?Select?and?return?the?names?of?which?class(es)?should?be?imported?based?on
??*?the?{@link?AnnotationMetadata}?of?the?importing?@{@link?Configuration}?class.
??*?@return?the?class?names,?or?an?empty?array?if?none
??*/
?String[]?selectImports(AnnotationMetadata?importingClassMetadata);

?/**
??*?Return?a?predicate?for?excluding?classes?from?the?import?candidates,?to?be
??*?transitively?applied?to?all?classes?found?through?this?selector's?imports.
??*?

If?this?predicate?returns?{@code?true}?for?a?given?fully-qualified
??*?class?name,?said?class?will?not?be?considered?as?an?imported?configuration
??*?class,?bypassing?class?file?loading?as?well?as?metadata?introspection.
??*?@return?the?filter?predicate?for?fully-qualified?candidate?class?names
??*?of?transitively?imported?configuration?classes,?or?{@code?null}?if?none
??*?@since?5.2.4
??*/


?@Nullable
?default?Predicate?getExclusionFilter()?{
??return?null;
?}

}

? ??主要關(guān)注String[] selectImports(AnnotationMetadata importingClassMetadata)方法,參數(shù)importingClassMetadata表示使用了@Import(? extends ImportSelector)注解的類的元數(shù)據(jù)。通過該參數(shù)可以實現(xiàn)獲取一些組合注解的自定義屬性等內(nèi)容,從而實現(xiàn)選擇性裝載配置類。

「注意這個方法的返回值不能是null,極端情況請返回空數(shù)組,否則運行將拋出NPE。」

? ??讓我們先創(chuàng)建一個SpringUtil:

package?com.swj.mj.autoconfig.util;

public?class?SpringUtil?implements?BeanFactoryAware,?ApplicationContextAware,?Ordered?{

????private?static?ApplicationContext?appCtx;
????private?static?BeanFactory?beanFactory;

????public?static?ApplicationContext?getAppCtx()?{
????????return?appCtx;
????}

????public?static?BeanFactory?getBeanFactory()?{
????????return?beanFactory;
????}

????@Override
????public?void?setBeanFactory(BeanFactory?beanFactory)?throws?BeansException?{
????????SpringUtil.beanFactory?=?beanFactory;
????}

????@Override
????public?void?setApplicationContext(ApplicationContext?applicationContext)?throws?BeansException?{
????????SpringUtil.appCtx?=?applicationContext;
????}

????@Override
????public?int?getOrder()?{
????????return?HIGHEST_PRECEDENCE?+?1;
????}

}

? ??這個類主要用于通過靜態(tài)持有Spring的ApplicationContext和BeanFactory,后續(xù)可以直接通過該類訪問Spring容器。然后創(chuàng)建我們的ImportSelector配置類裝載選擇器:

package?com.swj.mj.autoconfig.configuration;

public?class?CustomImportSelector?implements?ImportSelector?{

????@Override
????public?String[]?selectImports(AnnotationMetadata?importingClassMetadata)?{
????????//?importingClassMetadata?指使用?@Import(HelloServiceImportSelector)?時?@Import?注解所在類的元數(shù)據(jù)
????????String?enableCustomConfig?=?EnableCustomConfig.class.getName();
????????if?(importingClassMetadata.hasAnnotation(enableCustomConfig))?{
????????????Map?attrs?=?importingClassMetadata.getAnnotationAttributes(enableCustomConfig);if?(MapUtils.isNotEmpty(attrs))?{
????????????????String?registerUtil?=?Optional.ofNullable(attrs.get("registerUtil")).map(Object::toString).orElse("false");if?(Boolean.parseBoolean(registerUtil))?{return?new?String[]{
????????????????????????????HelloServiceConfiguration.class.getName(),
????????????????????????????SpringUtil.class.getName()
????????????????????};
????????????????}
????????????}
????????}return?new?String[]{
????????????????HelloServiceConfiguration.class.getName()
????????};
????}
}

? ??然后創(chuàng)建我們的EnableCustomConfig注解:

package?com.swj.mj.autoconfig.annotation;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(CustomImportSelector.class)
public?@interface?EnableCustomConfig?{

????/**
?????*?是否注冊?{@link?com.swj.mj.autoconfig.util.SpringUtil}?工具類,默認(rèn)為?{@literal?true}
?????*/
????boolean?registerUtil()?default?true;

}

? ??這里簡單解釋一下:首先@EnableCustomConfig注解組合了@Import(CustomImportSelector.class),這樣在CustomImportSelector#selectImports方法中可以通過importingClassMetadata獲取得到@EnableCustomConfig注解的屬性配置。然后通過該配置實現(xiàn)添加裝載配置。這里我們判斷registerUtil是否為true(默認(rèn)為true),為true時將裝載SpringUtil以便后續(xù)可以通過SpringUtil訪問Spring容器。

? ??接著調(diào)整HelloController:

@RestController
@AllArgsConstructor
@RequestMapping("/hello")
@EnableCustomConfig
public?class?HelloController?{

????private?final?HelloService?helloService;

????@GetMapping
????public?Map?hello(String?name)?{
????????ApplicationContext?appCtx?=?SpringUtil.getAppCtx();
????????assert?Objects.nonNull(appCtx)?:?"appCtx?為?null";
????????assert?appCtx.containsBean(SpringUtil.class.getName());
????????assert?appCtx.containsBean(HelloServiceConfiguration.class.getName());
????????assert?appCtx.getBean(HelloService.class)?==?helloService;
????????return?ImmutableMap.of("name",?name,?"helloResult",?helloService.sayHello(name));
????}

}

? ??這里通過添加@EnableCustomConfig激活聯(lián)動激活@Import(CustomImportSelector.class)以注冊SpringUtil和HelloServiceConfiguration,由于默認(rèn)registerUtil為true,所以會注冊SpringUtil。啟動應(yīng)用后能訪問http://localhost:8080/hello?name=Reka表示斷言均成立,容器中確實注冊了對應(yīng)的Bean。

? ??接著我們調(diào)整@EnableCustomConfig為@EnableCustomConfig(registerUtil = false),再次啟動容器訪問http://localhost:8080/hello?name=Reka,這時候會發(fā)現(xiàn)斷言失敗:

通過注解屬性配置選擇性裝載配置類

動態(tài)注冊Bean

? ??這是@Import的第四個功能,通過org.springframework.context.annotation.ImportBeanDefinitionRegistrar自由注冊SpringBean。該接口的定義如下:

public?interface?ImportBeanDefinitionRegistrar?{

?default?void?registerBeanDefinitions(AnnotationMetadata?importingClassMetadata,?BeanDefinitionRegistry?registry,
???BeanNameGenerator?importBeanNameGenerator)?{

??registerBeanDefinitions(importingClassMetadata,?registry);
?}

?default?void?registerBeanDefinitions(AnnotationMetadata?importingClassMetadata,?BeanDefinitionRegistry?registry)?{
?}

}

? ??主要看void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry),其中參數(shù)importingClassMetadata與ImportSelector里的參數(shù)效用一致,registry參數(shù)簡單理解是Bean注冊器,通過它可以往Spring容器中注冊Bean。現(xiàn)在讓我們通過動態(tài)注冊Bean的方式實現(xiàn)CustomImportSelector的功能。

package?com.swj.mj.autoconfig.configuration;

public?class?CustomImportBeanDefinitionRegistrar?implements?ImportBeanDefinitionRegistrar?{

????@Override
????public?void?registerBeanDefinitions(AnnotationMetadata?importingClassMetadata,?BeanDefinitionRegistry?registry,?BeanNameGenerator?importBeanNameGenerator)?{
????????AnnotationAttributes?attrs?=?AnnotatedElementUtils.getMergedAnnotationAttributes(
????????????????ClassUtils.resolveClassName(importingClassMetadata.getClassName(),?null),
????????????????EnableCustomBean.class);
????????if?(MapUtils.isNotEmpty(attrs)?&&?BooleanUtils.isTrue(attrs.getBoolean("registerUtil")))?{
????????????registry.registerBeanDefinition("springUtil",?new?RootBeanDefinition(SpringUtil.class));
????????}
????????registry.registerBeanDefinition("helloService",?new?RootBeanDefinition(HelloService.class));
????}

}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(CustomImportBeanDefinitionRegistrar.class)
public?@interface?EnableCustomBean?{

????/**
?????*?是否注冊?{@link?com.swj.mj.autoconfig.util.SpringUtil}?工具類,默認(rèn)為?{@literal?true}
?????*/
????boolean?registerUtil()?default?true;

}

? ? CustomImportBeanDefinitionRegistrar的邏輯與CustomImportSelector基本一致,只不過最后不是返回配置類,而是直接通過org.springframework.beans.factory.support.BeanDefinitionRegistry#registerBeanDefinition注冊Bean。最后調(diào)整一下HelloController:

@RestController
@AllArgsConstructor
@RequestMapping("/hello")
@EnableCustomBean
public?class?HelloController?{

????private?final?HelloService?helloService;

????@GetMapping
????public?Map?hello(String?name)?{
????????ApplicationContext?appCtx?=?SpringUtil.getAppCtx();
????????assert?Objects.nonNull(appCtx)?:?"appCtx?為?null";
????????assert?appCtx.containsBean("springUtil");
????????assert?appCtx.getBean(HelloService.class)?==?helloService;
????????return?ImmutableMap.of("name",?name,?"helloResult",?helloService.sayHello(name));
????}

}

? ??實際運行效果與CustomImportSelect和@EnableCustomConfig一致,請讀者自行驗證。

? ??如果僅僅是這樣,你是不是認(rèn)為就沒必要有ImportBeanDefinitionRegistrar了。實際上通過該接口我們可以定義自己的容器Bean注解。實現(xiàn)很多特殊的功能:比如在三維家美家技術(shù)中使用到了SpringCloud Stream,但SCS的@org.springframework.cloud.stream.annotation.EnableBinding注解很麻煩,每次引入新的@Input和@Output都要將對應(yīng)接口添加到@EnableBinding中,三維家美家通過ImportBeanDefinitionRegistrar和自定義注解實現(xiàn)新的Input/Ouput Bean掃描注冊流程。后續(xù)會計劃將該功能提PR到SpringCloud項目中。

? ??通過自定義注冊和ImportBeanDefinitionRegistrar可以更靈活地自定義Bean注冊邏輯,限于篇幅原因,我們往后有機會再講。各位,今天關(guān)于@Import的基本用法是否掌握了呢,建議可以自己實踐一次以加深理解,如果對源碼有興趣,可以閱讀org.springframework.context.annotation.ConfigurationClassParser類。

總結(jié)

以上是生活随笔為你收集整理的idea去掉无用import类_@Import注解的魅力的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 99久久久无码国产精品不卡 | 俄罗斯女人裸体性做爰 | 一级特黄aaa大片 | 天天毛片 | 欧美日韩国产高清 | 久久精品视频无码 | 国产精品成人一区二区网站软件 | 日本国产一区 | 欧美黑粗大 | 岛国精品在线 | 国产亚洲综合av | 日一区二区 | 熟女视频一区 | 无码人妻av一区二区三区波多野 | 国产一级视频 | 久久久99精品免费观看 | 精品少妇一区二区三区在线观看 | 伊人亚洲天堂 | 一级片在线观看免费 | 中文资源在线观看 | av一起看香蕉 | 人体av | 国产123| 欧美激情3p | 九九九九九热 | 国产精品视频一区二区三区, | 超碰免费公开 | 中文字幕免费一区二区 | 国产精欧美一区二区三区蓝颜男同 | 91精品国产综合久久福利 | 精品国产自在精品国产精小说 | 亚洲三级黄色 | www.69pao.com| 老汉av在线 | 久久精品性爱视频 | 日韩精品免费电影 | 日韩一区二区三区精 | 欧美欧美欧美 | 国产在线精品一区二区三区 | 99视频99| 中文字幕123区 | 九九精品在线播放 | 久久h| 国产精品久久久久久久久免费软件 | 小明看国产 | 国产精品成人久久久 | 免费的av网址| 五月天狠狠操 | 精品国产99一区二区乱码综合 | 日本一区视频在线观看 | 久久66热这里只有精品 | 国产freexxxx性播放麻豆 | 精品亚洲一区二区三区四区五区 | 夜夜操天天射 | 一级做a爱片久久 | 色噜噜在线观看 | 欧美日韩国产亚洲一区 | 日韩不卡av在线 | 撕开少妇裙子猛然进入 | 香蕉综合网| 精品欧美一区二区三区成人 | www.亚洲免费 | 成人hd| 91午夜在线观看 | 色福利网| 超碰成人av | 日韩一区二区精品 | 欧美在线中文 | 亚洲精品久久久蜜桃网尤妮丝 | 亚洲在线免费视频 | 国产欧美日韩免费 | 无码国产69精品久久久久同性 | 日本a v在线播放 | 精品一区二区免费看 | 毛片福利| 免费裸体美女网站 | 91视频免费看片 | 婷婷综合五月天 | 日韩视频在线观看二区 | 综合久久一区 | 人人爽人人爽人人片 | 91网在线观看 | 成人免费观看网站 | 亚洲av无码乱码国产精品久久 | 国产亚洲成av人在线观看导航 | 国产无码精品一区二区 | 国产午夜精品一区 | 久久久av免费 | 国产精品桃色 | 国产又粗又猛又爽又黄的网站 | 三级做爰在线观看视频 | 欧美黄色a | 九九九热视频 | 97se在线| 亚洲色图第三页 | 日韩欧av| 国产视频一区在线播放 | 日韩国产成人无码av毛片 | 国产精品国产三级国产三级人妇 |