应用办公生活信息教育商业
投稿投诉
商业财经
汽车智能
教育国际
房产环球
信息数码
热点科技
生活手机
晨报新闻
办公软件
科学动态
应用生物
体育时事

SpringBoot中Import三种使用方式

  转载于:公众号:后端元宇宙
  需要注意的是:ImportSelector、ImportBeanDefinitionRegistrar这两个接口都必须依赖于Im
  port一起使用,而Import可以单独使用。
  Import是一个非常有用的注解,它的长处在于你可以通过配置来控制是否注入该Bean,也可以通过条件来控制注入哪些Bean到Spring容器中。
  比如我们熟悉的:EnableAsync、EnableCaching、EnableScheduling等等统一采用的都是借助Import注解来实现的。
  下面我们就通过示例来了解Import三种用法!一、引入普通类
  有个用户类如下DatapublicclassUserConfig{用户名privateStringusername;手机号privateStringphone;}
  那么如何通过Import注入容器呢?Import(UserConfig。class)ConfigurationpublicclassUserConfiguration{}
  当在Configuration标注的类上使用Import引入了一个类后,就会把该类注入容器中。
  当然除了Configuration比如Component、Service等一样也可以。
  测试SpringBootTestRunWith(SpringRunner。class)publicclassUserServiceTest{AutowiredprivateUserConfiguserConfig;TestpublicvoidgetUser(){StringnameuserConfig。getClass()。getName();System。out。println(namename);}}
  控制台输出namecom。jincou。importselector。model。UserConfig
  如果Import的功能仅仅是这样,那其实它并没什么特别的价值,我们可以通过其它方式实现?ConfigurationpublicclassUserConfiguration{BeanpublicUserConfiguserConfig(){returnnewUserConfig();}}
  再比如直接添加Configuration注解ConfigurationpublicclassUserConfig{。。。。。。}
  确实如果注入静态的Bean到容器中,那完全可以用上面的方式代替,但如果需要动态的带有逻辑性的注入Bean,那才更能体现Import的价值。
  二、引入ImportSelector的实现类
  说到ImportSelector这个接口就不得不说这里面最重要的一个方法:selectImports()。publicinterfaceImportSelector{String〔〕selectImports(AnnotationMetadataimportingClassMetadata);}
  这个方法的返回值是一个字符串数组,只要在配置类被引用了,这里返回的字符串数组中的类名就会被Spring容器new出来,然后再把这些对象注入IOC容器中。
  所以这有啥用呢?我们还是用一个例子演示一下。1、静态import场景(注入已知的类)
  我们先将上面的示例改造下:
  自定义MyImportSelector实现ImportSelector接口,重写selectImports方法publicclassMyImportSelectorimplementsImportSelector{OverridepublicString〔〕selectImports(AnnotationMetadataimportingClassMetadata){这里目的是将UserConfig注入容器中returnnewString〔〕{com。jincou。importselector。model。UserConfig};}}
  然后在配置类引用Import(MyImportSelector。class)ConfigurationpublicclassUserConfiguration{}
  这样一来同样可以通过成功将UserConfig注入容器中。
  如果看到这,你肯定会有疑问。我这又是新建MyImportSelector类,又是实现ImportSelector重写selectImports方法,然后我这么做有个卵用呢?
  直接把类上加个Component注入进去不香吗?这个ImportSelector把简单的功能搞这么复杂。
  接下来就要说说如何动态注入Bean了。2、动态import场景(注入指定条件的类)
  我们来思考一种场景,就是你想通过开关来控制是否注入该Bean,或者说通过配置来控制注入哪些Bean,这个时候就有了ImportSelector的用武之地了。
  我们来举个例子,通过ImportSelector的使用实现条件选择是注入本地缓存还是Redis缓存。
  1)、定义缓存接口和实现类
  顶层接口publicinterfaceCacheService{voidsetData(Stringkey);}
  本地缓存实现类publicclassLocalServicemplimplementsCacheService{OverridepublicvoidsetData(Stringkey){System。out。println(本地存储存储数据成功keykey);}}
  redis缓存实现类publicclassRedisServicemplimplementsCacheService{OverridepublicvoidsetData(Stringkey){System。out。println(redis存储数据成功keykey);}}
  2)、定义ImportSelector实现类
  以下代码中根据EnableMyCache注解中的不同值来切换缓存的实现类再spring中的注册。publicclassMyCacheSelectorimplementsImportSelector{OverridepublicString〔〕selectImports(AnnotationMetadataimportingClassMetadata){MapString,ObjectannotationAttributesimportingClassMetadata。getAnnotationAttributes(EnableMyCache。class。getName());通过不同type注入不同的缓存到容器中CacheTypetype(CacheType)annotationAttributes。get(type);switch(type){caseLOCAL:{returnnewString〔〕{LocalServicempl。class。getName()};}caseREDIS:{returnnewString〔〕{RedisServicempl。class。getName()};}default:{thrownewRuntimeException(MessageFormat。format(unsupportcachetype{0},type。toString()));}}}}
  3)、定义注解
  EnableMyCache注解就像一个开关,通过这个开关来是否将特定的Bean注入容器。
  定义一个枚举Target(ElementType。TYPE)Retention(RetentionPolicy。RUNTIME)DocumentedImport(MyCacheSelector。class)publicinterfaceEnableMyCache{CacheTypetype()defaultCacheType。REDIS;}publicenumCacheType{LOCAL,REDIS;}
  4)、测试
  这里选择本地缓存。EnableMyCache(typeCacheType。LOCAL)SpringBootTestRunWith(SpringRunner。class)publicclassUserServiceTest{AutowiredprivateCacheServicecacheService;Testpublicvoidtest(){cacheService。setData(key);}}
  控制台输出本地存储存储数据成功keykey
  切换成redis缓存EnableMyCache(typeCacheType。REDIS)SpringBootTestRunWith(SpringRunner。class)publicclassUserServiceTest{AutowiredprivateCacheServicecacheService;Testpublicvoidtest(){cacheService。setData(key);}}
  控制台输出redis存储数据成功keykey
  这个示例不是就是Bean的动态注入了吗?3、Spring如何使用ImportSelector的场景
  SpringBoot有两个常用注解EnableAsyncEnableCaching其实就是通过ImportSelector来动态注入Bean
  看下EnableAsync注解,它有通过Import({AsyncConfigurationSelector。class})Target({ElementType。TYPE})Retention(RetentionPolicy。RUNTIME)DocumentedImport({AsyncConfigurationSelector。class})publicinterfaceEnableAsync{Classlt;?extendsAnnotationannotation()defaultAnnotation。class;booleanproxyTargetClass()defaultfalse;AdviceModemode()defaultAdviceMode。PROXY;intorder()default2147483647;}
  AsyncConfigurationSelector。classpublicclassAsyncConfigurationSelectorextendsAdviceModeImportSelectorEnableAsync{privatestaticfinalStringASYNCEXECUTIONASPECTCONFIGURATIONCLASSNAMEorg。springframework。scheduling。aspectj。AspectJAsyncConfiguration;publicAsyncConfigurationSelector(){}NullablepublicString〔〕selectImports(AdviceModeadviceMode){switch(adviceMode){casePROXY:returnnewString〔〕{ProxyAsyncConfiguration。class。getName()};caseASPECTJ:returnnewString〔〕{org。springframework。scheduling。aspectj。AspectJAsyncConfiguration};default:returnnull;}}}
  是不是和我上面写的示例一样。
  总之,向这种还不能决定去注入哪个处理器(如果你能决定,那就直接Import那个类好了,没必要实现接口了),就可以实现此接口,写出一些判断逻辑,不同的配置情况注入不同的处理类。
  三、引入ImportBeanDefinitionRegister的实现类
  当配置类实现了ImportBeanDefinitionRegistrar接口,你就可以自定义往容器中注册想注入的Bean。
  这个接口相比与ImportSelector接口的主要区别就是,ImportSelector接口是返回一个类,你不能对这个类进行任何操作,但是ImportBeanDefinitionRegistrar是可以自己注入BeanDefinition,可以添加属性之类的。publicclassMyImportBeanimplementsImportBeanDefinitionRegistrar{paramimportingClassMetadata当前类的注解信息paramregistry注册类,其registerBeanDefinition()可以注册beanOverridepublicvoidregisterBeanDefinitions(AnnotationMetadataimportingClassMetadata,BeanDefinitionRegistryregistry){}}1、举一个简单的示例
  我们通过先通过一个简单的小示例,来理解它的基本使用
  假设有个用户配置类如下DatapublicclassUserConfig{用户名privateStringusername;手机号privateStringphone;}
  我们通过实现ImportBeanDefinitionRegistrar的方式来完成注入。publicclassMyImportBeanimplementsImportBeanDefinitionRegistrar{paramimportingClassMetadata当前类的注解信息paramregistry注册类,其registerBeanDefinition()可以注册beanOverridepublicvoidregisterBeanDefinitions(AnnotationMetadataimportingClassMetadata,BeanDefinitionRegistryregistry){构建一个BeanDefinition,Bean的类型为UserConfig,这个Bean的属性username的值为后端元宇宙AbstractBeanDefinitionbeanDefinitionBeanDefinitionBuilder。rootBeanDefinition(UserConfig。class)。addPropertyValue(username,后端元宇宙)。getBeanDefinition();把UserConfig这个Bean的定义注册到容器中registry。registerBeanDefinition(userConfig,beanDefinition);}}
  通过配置类中引入MyImportBean对象。Import(MyImportBean。class)ConfigurationpublicclassUserImportConfiguration{}
  我们再来测试下EnableMyCache(typeCacheType。REDIS)SpringBootTestRunWith(SpringRunner。class)publicclassUserServiceTest{AutowiredprivateUserConfiguserConfig;Testpublicvoidtest(){StringusernameuserConfig。getUsername();System。out。println(usernameusername);}}
  控制台输出username后端元宇宙
  说明通过ImportBeanDefinitionRegistrar方式,已经把UserConfig注入容器成功,而且还为给bean设置了新属性。
  然后我们再来思考一个问题,就比如我们在其它地方已经将UserConfig注入容器,这里会不会出现冲突,或者不冲突的情况下,属性能不能设置成功?
  我们来试下Import(MyImportBean。class)ConfigurationpublicclassUserImportConfiguration{这里通过Bean注解,将UserConfig注入Spring容器中,而且名称也叫userConfigBeanpublicUserConfiguserConfig(){returnnewUserConfig();}}
  然后我们再来跑下上面的测试用例,发现报错了。
  2、举一个复杂点的例子
  Mybatis的MapperScan就是用这种方式实现的,MapperScan注解,指定basePackages,扫描MybatisMapper接口类注入到容器中。
  这里我们自定义一个注解MyMapperScan来扫描包路径下所以带MapperBean注解的类,并将它们注入到IOC容器中。
  1)、先定义一个MapperBean注解,就相当于我们的Mapper注解定义包路径。(指定包下所有添加了MapperBean注解的类作为bean)注意这里Import(MyMapperScanImportBean。class)的使用Retention(RetentionPolicy。RUNTIME)Target(ElementType。TYPE)DocumentedpublicinterfaceMapperBean{}
  2)、一个需要注入的bean,这里加上MapperBean注解。packagecom。jincou。importselector。mapperScan;importcom。jincou。importselector。config。MapperBean;MapperBeanpublicclassUser{}
  3)、再定一个扫描包路径的注解MyMapperScan就相当于mybatis的MapperScan注解。Retention(RetentionPolicy。RUNTIME)Target(ElementType。TYPE)DocumentedImport(MyMapperScanImportBean。class)publicinterfaceMyMapperScan{扫描包路径String〔〕basePackages()default{};}
  4)、MyMapperScanImportBean实现ImportBeanDefinitionRegistrar接口publicclassMyMapperScanImportBeanimplementsImportBeanDefinitionRegistrar,ResourceLoaderAware{privatefinalstaticStringPACKAGENAMEKEYbasePackages;privateResourceLoaderresourceLoader;搜索指定包下所有添加了MapperBean注解的类,并且把这些类添加到ioc容器里面去paramimportingClassMetadata当前类的注解信息paramregistry注册类,其registerBeanDefinition()可以注册beanOverridepublicvoidregisterBeanDefinitions(AnnotationMetadataimportingClassMetadata,BeanDefinitionRegistryregistry){1。从BeanIocScan注解获取到我们要搜索的包路径AnnotationAttributesannoAttrsAnnotationAttributes。fromMap(importingClassMetadata。getAnnotationAttributes(MyMapperScan。class。getName()));if(annoAttrsnullannoAttrs。isEmpty()){return;}String〔〕basePackages(String〔〕)annoAttrs。get(PACKAGENAMEKEY);2。找到指定包路径下所有添加了MapperBean注解的类,并且把这些类添加到IOC容器里面去ClassPathBeanDefinitionScannerscannernewClassPathBeanDefinitionScanner(registry,false);scanner。setResourceLoader(resourceLoader);路径包含MapperBean的注解的beanscanner。addIncludeFilter(newAnnotationTypeFilter(MapperBean。class));扫描包下路径scanner。scan(basePackages);}OverridepublicvoidsetResourceLoader(ResourceLoaderresourceLoader){this。resourceLoaderresourceLoader;}}
  5)测试
  这里扫描的路径就是上面User实体的位置RunWith(SpringRunner。class)SpringBootTestMyMapperScan(basePackages{com。jincou。importselector。mapperScan})publicclassUserServiceTest{AutowiredprivateUseruser;Testpublicvoidtest(){System。out。println(usernameuser。getClass()。getName());}}
  运行结果usernamecom。jincou。importselector。mapperScan。User
  完美,成功!
  实现它的基本思想是:当自己需要操作BeanFactory里面的Bean的时候,那就必须只有它才能做到了。而且它还有个方便的地方,那就是做包扫描的时候,比如MapperScan类似这种的时候,用它处理更为方便(因为扫描到了直接注册即可)

5种方法提升AirPodsPro音质AirPodsPro无线耳机深受苹果用户的青睐,大多数人用过苹果耳机就不再考虑其它,但是,也有一些AirPodsPro用户反馈令人失望的低音、弱噪音消除或整体音质不佳。如……怀孕吃什么长胎不长肉对于孕妇来说除了胎儿的健康放在首位之外,其次就是孕期饮食了,孕期饮食与胎儿的成长息息相关,所以孕妈妈们要学会合理饮食。另外,孕期体重也要保持在一定范围内,上超过了合理的范围会增……孟美岐插足别人感情只是冰山一角,她的过往比你想象的更精彩都说江山代有才人出,各领风骚数百年。可纵观现在的娱乐圈,才人辈出的全盛景象尚未见到,个别明星扒道德底裤的骚操作,却能让网友们集体震惊好几年。黑白键坐享千万瞩目荣光却……细思极恐的双缝干涉实验双缝干涉实验,细思极恐你所看到的就一定是真实的吗?在我们的宏观世界,观测者和被观测者似乎并没有关联,这体现在:如果我不观测你,你就变了另一个形态,而我重新观测你,你……奇葩准上市公司竟是博彩网站借钱给实控人买别墅通过分红帮他还钱这年头,招股书错误频出,已经见怪不怪了,可你见过把自家官网都弄错的吗?创业板准上市公司、苹果与华为间接供应商万祥科技(301180。SZ)就是这样一家奇葩公司,三大行情软……2021年双十一最值得购买的手机上喜欢我的文章吗?请点上方蓝色字体关注吧选购指南11。11最值得购买的手机小雷。2021。10。26双十一来了。各种购机咨询多了起来。……皖南的秋色,藏在这里世间若有十分色彩,秋天便独占九分。秋天的色彩,是绚烂的。枫叶红、银杏黄、桂花浓一片斑斓,令人沉醉。或许你熟知,秋天木兰围场的壮美、喀纳斯的仙境、内蒙古胡杨林的不死神……1979年,83岁老农写6000字书信寄去中央,揭露捉蒋背后1979年的某一天,中央收到一封长达6000字的书信,信中内容重新讲述43年前捉蒋过程,在结尾处有写道:信中内容,均可当面对峙,这样真相就会公之于众。当这封信传到中央领导……搭配鸿蒙OS系统,华为75英寸8K电视,双11到手价不足50电视是普及率最高的家用电器之一,而电视属于大件家电,价格一般都不会太便宜,所以很多小伙伴往往选在电商节入手,比如已经到来的双11全球电商狂欢节!剁手时节到了。双11电商狂……曾无偿捐出1000亿后,再放弃首富之位,41岁的黄峥留下传奇近年来我国的发展也是十分迅速,有着许多优秀的产业喷涌而出,特别是这个互联网时代大爆发的时期,创造了许多的富豪,就像我们熟知的马云、马化腾、还有拼多多的黄峥都不失为是个神话,尤其……天问一号失联20天,终于再次被唤醒!官方已接收到火星信号我国首颗火星探测器天问一号曾经在上个月下旬处于失联状态,也就是说:地面指挥中心已经接收不到天问一号传回的信号了。不仅仅是我国的火星探测器,包括美国的火星探测器和其他国家的绕火星……恭喜国足仇人迎娶超级美女,中超弃将终成人生赢家近日,据多家叙利亚媒体证实,叙利亚著名球星、前河南建业队外援萨利赫,已经和叙利亚著名女歌星沙赫德巴尔玛达订婚。这次订婚被视作是叙利亚体坛一次标志性的文体联姻。作为一名昔日被中超……
正式归来!NBA首轮秀重返CBA,带队冲击季后赛离CBA第二阶段开赛的时间越来越近,最近很多外援都结束隔离了,哈达迪、威姆斯、拉科塞维奇、琼斯等等,CBA再次回到外援逐鹿的时代,比赛会更加精彩,非常让球迷期待。据了解,南京同……培养一位中国F1赛车手有多难?图片来源视觉中国中国首位F1正式车手周冠宇职业生涯的第三站F1比赛,吸引了诸多赛车爱好者的关注。4月10日,世界一级方程式赛车锦标赛(F1)澳大利亚大奖赛在墨尔本阿……25岁小姐姐手臂吸脂60天,大象臂终变纤细小臂又到了露腰露腿的季节,一双纤细的手臂也是格外给人增添美丽!都说背薄一寸,年轻十岁,是有点道理的,我发现手臂瘦了一圈,背好像薄了,穿什么衣服都好看今日分享一位25岁小……张柏芝穿紫色纱裙真贵气,戴20万手表丝毫不浮夸,气场很稳头条创作挑战赛随着年龄的增长,穿衣搭配的风格总是在发生着细微的变化。从年轻时候膨胀的百褶裙,到中年女性喜欢的鱼尾裙。从轻柔的薄纱质地,到细腻的真丝面料。能把年龄活成……刷宝短视频APP彻底关停曾冠名天天向上幕后实控人系聚美优品C中国网科技3月23日讯(记者杨月月)曾冠名综艺顶流《天天向上》、登陆《快乐大本营》的刷宝短视频APP彻底关停了。据中央网信办举报中心微信公众号消息,因存在发布或传播法律、……用了市面上的吸黑头仪,会导致毛孔增大吗?不知大家是否遇到过这样的烦恼?明明已经洗干净脸,却被黑头、油脂等毛孔内部的脏东西影响了一天的好心情,对于有强迫症的朋友们来说,一旦这种情况出现在自己脸上,简直是无法忍受,迫切想……培养孩子自律的四个小窍门一、帮孩子找到感兴趣的事自律的人更善于管理自己的情绪,他们在面对诱惑时能更好地审时度势,懂得拒绝,成就更好的人生。相信很多人面对诱人的美食、华丽的服装、神奇的化妆品……向太一家外出吃饭,郭碧婷身形比婆婆还胖,向佐怀中孩子不停打滚现在很多明星到了年纪也开始考虑自己的终身大事了,对于明星来说组建家庭是一件非常不容易的事情,能够长久在一起的明星夫妻在娱乐圈也是少数,很多明星在有了孩子后不久,就选择了分开,可……最近很火的过膝裙这样穿,兼具优雅和时髦,奔四的女人都爱了优雅和年龄无关,与其过度在意自己的容貌,倒不如多尝试一些时尚的穿搭,穿衣能够打造出氛围感,就算你长相平平无奇,但穿的好看也能够给人带来焕然一新的感觉。所以日常生活中大家可以多尝……突然爆雷!万门大学跑路了今天传出一家知名教育机构突然跑路。22日一早,万门的用户和员工一觉醒来懵了,公司运营的App无法登陆,苹果商店无法搜到,收费用户的vip群也全部解散。万门大学疑似解……经常反酸?别让白菜豆腐变成致癌菜据统计,我国有1。65亿人正在遭受反酸烧心的折磨!很多人用尽各种办法想要中和胃酸,缓解不适。但你知道吗?你的反酸烧心很可能是胃酸过少导致的!如果缓解反酸烧心用错方法,不仅……红米k40s在k40的基础上做到了三个保留和三个提升,我们来这两款手机的对比相信感兴趣的朋友已经了解过了,所以我就在这里简单的为大家总结一下吧,让大家更直观的了解。首先说一下三个保留保留了骁龙870处理器,这款处理器为什么好……
友情链接:易事利快生活快传网聚热点七猫云快好知快百科中准网快好找文好找中准网快软网