原理

 使用过springboot的小伙伴们,一定知道springboot整合了好多的功能,如dubbo、webMVC等,其声明了相应的注解类

@EnableDubbo、@EnableWebMvc来作为此组件的开关。

其实现原理也很简单,springboot模拟了Java的spi机制,实现了自己的spi机制,以达到组件之间的解耦效果。第三方只需要在组件资源的根目录下添加META-INF文件夹,在META-INF文件夹下面添加名为spring.factories的文件,并将组件的入口类的全限定类名加入文件中,springboot启动时即可加载。org.springframework.core.io.support.SpringFactoriesLoader#loadFactories完成了加载的工作,属性FACTORIES_RESOURCE_LOCATION指定了加载的路径"META-INF/spring.factories"。



整合自定义的组件,到springboot项目中

 笔者这里创建了一个简单的MVC项目,开发了一个接口/buge/mvp,并返回一个“你很帅!”的字符串的这样一个简单的组件。

项目结构:

springboot 插件热插拔 springboot 插件化_加载

同时在项目的根目录中创建META-INF/spring.factories文件,并加入org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.buge.dubboapi.starter.Config的配置信息。

重点看下Config类,此类即为组件的配置类:

 

springboot 插件热插拔 springboot 插件化_spring boot_02


 注意@ConditionalOnBean:当spring容器中含有Buge这个bean时,才会加载Config,可作为组件的一个开关使用;

那何时去生成Buge的bean呢?这需要借助于spring的@Impor注解,来注入自定义的类,交由spring来管理。

项目中@EnableBuge注解,即完成了注入buge的工作。下图可看到,在注解类上添加了@Import(Buge.class)

 

springboot 插件热插拔 springboot 插件化_加载_03

这里做个小总结:@EnableBuge注解即为我们组件的开关,若添加了此注解,会促使spring加载Buge到spring容器中,而springboot通过spi机制加载的Config类是需要容器中有Buge,所以添加了@EnableBuge注解,Config会生效,组件的功能才可用。当然,把Config类上的 @ConditionalOnBean 去掉后,就没这个bean的限制了。但笔者认为,这个开关还是有必要的!

测试

将以上组件打包,放入本地maven仓库中。创建一个springboot项目,导入组件的依赖。在springboot的启动类上加入@EnableBuge注解。

springboot 插件热插拔 springboot 插件化_java_04

 启动服务,调用组件接口,看结果:

springboot 插件热插拔 springboot 插件化_spring_05

 是的,我们开发的组件生效了!倘若想关闭组件的功能,把启动类上的@EnableBuge去掉即可,如下图。继续测试一波:

springboot 插件热插拔 springboot 插件化_java_06

启动服务,调用组件接口,看结果:

springboot 插件热插拔 springboot 插件化_springboot 插件热插拔_07

返回404,组件功能关闭!

到此为止,我们就完成了自定义组件,就整合到了springboot中。

  思考

整合组件到springboot中,是很简单的事情,而开发一个NB组件,才是难点、重点。如mybatis-spring组件,就对spring进行了大量的扩展。mybatis生成了自己的ClassPathMapperScanner,定义了mybatis的扫描规则,以至于spring可加载mapper接口,并对其生成代理,把代理类交由spring容器管理,并暴露给用户使用。使用者只需在配置类中添加@MapperScan注解,指定扫描的路径,就可使用mybatis的功能!