SpringBoot多模块开发之Bean的导入引用

        日常开发过程中,可能是一个单Module的单体项目,那么随着功能复杂,我们可能会出进行项目分模块化开发,比较典型就是按照功能进行Module的划分,然后通过maven依赖方式实现多模块之间的沟通,比如类似这种(Demo):

假如上图moduleMain 需要依赖moduleOne ,我们可以在前者的pom文件中直接引入后者

那么有个问题,moduleOne虽然被moduleMain依赖,但是moduleOne的bean也会在moduleMain启动时候被扫描同时会被实例化吗???

                                                        显然不会!!!

这里就涉及springboot项目启动时候关于IOC容器的扫描,我们都会在每个单独module的主类加上@SpringBootApplication注解,实质上它是一个复合注解

那么关于bean的扫描主要是在@ComponentScan这个注解 ,默认会扫描当前module的主类(也就是加了@SpringBootApplication的类)所在包以及子包中所有声明为bean(通常就是加@Configuration、@Component、@Service等等)的类,然后进行扫描并注册到IOC容器当中并且受其管理,然后我们就可以通过@Autowired或者@Resource方式来在项目中进行注入引用。

回到我们的主题,就是我moduleMain通过maven依赖方式依赖了moduleOne这个模块,并且我要扫描到moduleOne模块中的所标识为bean的类进行注册使用,答案有好多种方式,一下讲几种开发常用的方式::

①:通过指定主类扫描的包路径(最简单 最直接方式)

我这里com.drMain是启动类的包路径,com.drOne就是要引入的moduleOne的包路径

@使用@Import注解

先在主类(也就是moduleMain)中定义一个类,通过@Configuration标记为是一个配置类,然后再加入@Import 表明要引入的类

可见上述 MainConfig 是一个配置类,该类会在IoC容器初始化时被扫描并初始化为Bean,那么在IoC容器扫描这个配置类的同时,也会读取到它上面的@Import注解,而@Import注解中指定了被通过maven依赖的moduleOne模块的类ModuleOneService,这就可以使得ModuleOneService类也被加入扫描的候选类,最终在moduleMain模块启动时候也被扫描且也被实例化为Bean并交给IoC容器管理。

注意::导入的ModuleOneService 还可以是一个被@ComponentScan标识的类 ,那么启动时候就会扫描到ModuleOneService所有包以及所有子包下所有标识为bean的类

③通过注解方式封装@Import(较为灵活)

实质上还是和上述第二种本质一样

我们可以自定义一个@Interface注解

还是和上述一样通过@Import方式引入被依赖模块的ModuleOneService

然后将这个自定义注解加入到启动类上使用(我们平时微服务开发使用的@EnableDsicoveryClient以及异步开发使用的@EnableAsync 本质上都是通过这种注解引用方式实现的,虽然可能实现细节不大相同,但是本质一样!!!)

④动态导入之实现 ImportSelector接口

importSelector是spring给我们提供的一个扩展接口,用于我们动态的决定哪些配置类应该被导入使用,

定义一个类实现ImportSelector

最后返回一个string类型数组表明我们要引入的bean,数组表明可以写入多个,通过逗号分隔开来

然后再通过和之前自定义配置类方式实现

⑤动态导入之实现ImportBeanDefinitionRegistar

public class ModuleMainService implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, org.springframework.beans.factory.support.BeanDefinitionRegistry registry) {
        GenericBeanDefinition genericBeanDefinition = new GenericBeanDefinition();
        genericBeanDefinition.setBeanClass(ModuleOneService.class);
        registry.registerBeanDefinition("moduleOneService", genericBeanDefinition);
        System.out.println("ModuleMainService::registerBeanDefinitions");
    }

最后同样地通过配置类使用@Import方式指定导入这实现了ImportBeanDefinitionRegistrar接口的类

以上就是几种常用方式,实质上大体分为两种,

第一种 通过指定扫描包路径实现

第二种 ②③④⑤都是通过@Import方式实现

最后 我们在进行第二大种比较灵活方式引用时候还可以再灵活些,实现条件式地(conditional)import ,也就是符合我们某种或某几种条件才进行import

下面举两个:

@ConditonOnProperty

读取到某个配置,并且配置满足指定情况再import

@Configuration
@Import(com.drOne.service.ModuleOneService.class)
@Import(ModuleOneApplication.class)
//@Import(ModuleMainService.class)
@ConditionalOnProperty(prefix = "com.drOne.moduleOneService", name = "enabled", havingValue = "true")
//@ConditionalOnBean(ModuleMainAssistantService.class)
public class MainConfig {
}

存在com.drOne.moduleOneService.enable配置 并且value是enabled时候

@ConditionBean

当IOC中存在某个或者某些bean的时候才进行import

@Configuration
@Import(com.drOne.service.ModuleOneService.class)
@Import(ModuleOneApplication.class)
//@Import(ModuleMainService.class)
//@ConditionalOnProperty(prefix = "com.drOne.moduleOneService", name = "enabled", havingValue = "true")
@ConditionalOnBean({ModuleMainAssistantService.class, ModuleMainService.class})
public class MainConfig {
}

当已经有ModuleMainAssistantService、ModuleMainService这个两个bean时候再import

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值