spring组件轻量化,但配置重量级的特点促使了springboot的诞生。springboot开发几乎不需要什么配置,极大地提高了开发效率,这要得益于springboot强大的自动装配逻辑。 玩转springboot,首先要搞明白它的自动装配的原理是什么,比较复杂
理解自动装配原理后,本人就试想这样一种场景,有两个项目,A和B, 项目A打成jar包引入到项目B中,那么项目B能够拿A中的Bean来直接使用吗?即刻动手试试:
新建项目A,创建service接口和实现类,并打成jar包供B引入,如下图:
新建项目B,引入A的jar包,项目B新建提供入口方法PhoneController,注入PhoneServiceImpl,调用sayHello()方法,启动,诶~报错了,如下图所示:
错误提示:Consider defining a bean of type ‘com.qq.demoa.demoa.service.impl.PhoneServiceImpl’ in your configuration.考虑在你的配置环境中定义一个PhoneServiceImpl类型的bean。 很明显,springboot启动类只能扫描到本项目中定义的bean(并且启动类文件的目录深度要放在定义的bean文件的上级,不能是同级和bean的下一级),而jar包里定义好的bean则要JavaConfig那样的注入bean,bean随用随取即可,如下图:
这是一种简单的实现方式,本文为了探究自动装配,采用另外一种方案,步骤如下:
项目B中新建spring.factories,内容为自定义的类PhoneServiceAutoConfiguration(见下图), 自定义类PhoneServiceAutoConfiguration中有两个关键注解,@ConditionalOnClass和@Import ,@ConditionalOnClass注解意思为在类路径下必须要能找到被该注解标识的类;
@Import(注解意思为可以导入配置类或者Bean到当前类中)
经过这样配置后,启动项目B并请求入口controller,我们发现bean已经被成功注入,请求也得以成功!
这里简要说明一下springboot是怎么完成bean的自动配置的: 入口starter启动类上有个复合注解@SpringBootApplication,点进去里面包含一个关键注解@EnableAutoConfiguration,再点击去发现@Import({AutoConfigurationImportSelector.class}),这个注解可以粗略地理解为会把所有包含META-INF/spring.factories文件的项目中的配置给读入,而bean自动配置就是在spring.factories中定义的XXXAutoConfiguration中,通过@ConditionalOnClass({XXX.class})和 @Import({XXX.class})来实现的。
OK,好记性不如烂笔头,自己动手做个记录,方便以后翻看。
补充一点:项目A打jar包时要注意一个问题,使用springboot默认的springboot-maven-plugin打包的第一级目录为Boot-INF,无法给别的项目引用,应该把其替换掉,换成传统项目的maven打包。
把默认的打包方式替换掉:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
替换成:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source> <!--指明源码用的Jdk版本-->
<target>1.8</target> <!--指明打包后的Jdk版本-->
</configuration>
</plugin>
</plugins>
</build>