Spring Boot 回顾(二):多模块下bean的注入| 8月更文挑战

2,992 阅读3分钟

前言

在实际的Spring Boot或者Spring Cloud项目开发中,我们经常需要把一些功能放到公共模块中去,比如上一篇文章中我们实现的自定义日志注解(Spring Boot 回顾(一):实现自己的第一个自定义注解),那么这时候如何让该注解正常生效呢,我们一起通过下面的demo看下吧。

引入公共模块

首先创建一个公共模块common,然后将之前的日志注解功能移植过去,处理完的结构如下 公共模块.png 然后我们在之前的测试方法上重新加上该注解@CommonSaveSystemLog(value = "测试公共日志注解"),运行看看结果,此时发现自定义注解并没有生效,打上断点发现没有进入到相应方法。我们先打印下bean看看是否是没有注册成功。先改造下启动类

@SpringBootApplication
@RequiredArgsConstructor
public class ClientApplication implements CommandLineRunner {

    final private ApplicationContext appContext;

    public static void main(String[] args) {
        SpringApplication.run(ClientApplication.class, args);
    }

    @Override
    public void run(String... args) {
        String[] beans = appContext.getBeanDefinitionNames();
        Arrays.sort(beans);
        for (String bean : beans) {
            System.out.println(bean + " of Type :: " + appContext.getBean(bean).getClass());
        }
    }
}

接着重新启动工程,看下控制台输出,发现没有找到对应的bean

image.png

@Enable模块驱动

原来新建的common是一个普通的maven项目,并不是一个Spring Boot项目,所以即使在这两个类上使用@Component注解标注,它们也不能被成功注册到各个微服务子系统的Spring IOC容器中。接下来我们使用@Enable模块驱动的方式来解决这个问题。首先我们新建一个LogConfigure配置类,在里面注册我们的bean。

public class LogConfigure {
    @Bean
    @ConditionalOnMissingBean(name = "commonSystemLogAspect")
    public CommonSystemLogAspect commonSystemLogAspect() {
        return new CommonSystemLogAspect();
    }
}

其中@ConditionalOnMissingBean注解表示当IOC容器中没有指定名称或类型的Bean时候,就注册它。这样做还有一个好处,就是如果子系统需要的话可以定义自己的日志处理方法,来覆盖我们功能模块中定义的方法。接着我们在创建一个注解来引入配置类。

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(LogConfigure.class)
public @interface MyLogEnable {
}

其中@Import就将我们刚才的实现类导入进来的,接下来,我们在启动类上添加该注解@MyLogEnable,再重新启动工程,可以看到我们的bean已经给注册到IOC中了 image.png 测试下方法看看,搞定了 image.png

总结

以上通过@Enable模块驱动的方式将公共模块的bean注入到我们想要注册的地方,接下来我们思考下为什么client模块中默认注册当前模块而没有注入其他模块的bean呢。其实在spring boot项目的启动类似,我们使用了@SpringBootApplication,而这个注解又包含@ComponentScan,@EnableAutoConfiguration,@SpringBootConfiguration。我们需要的就是@ComponentScan,使用过spring框架的小伙伴都知道,spring里有四大注解:@Service,@Repository,@Component,@Controller用来定义一个bean.@ComponentScan注解就是用来自动扫描被这些注解标识的类,最终生成ioc容器里的bean.其默认扫描范围是当前路径下的所有bean。因此如果我们要扫描其他模块下的bean,只需要配置下@ComponentScan("com.tyaa.*")即可。我们重新重启工程测试下

image.png

image.png 至此我们通过@Enable模块驱动的方式和修改@ComponentScan扫描范围的这两种方式实现了将其他模块的bean进行注入的功能。