第一个问题:对于ComponentScan注解,它只是扫描所在包的java类,但是,更多时候真正需要的是可以扫描所指定的类
@ComponentScan 存在着两个配置项 ,一个是basePackages,另外一个是basePackageClasses。
* basePackages可以配置一个java包的数组,Spring会根据它的配置扫描相对应的包和子包,将配置好的Bean,装配起来;
* basePackageClasses可以配置多个类,Spring会根据配置的类所在的包,为包和子包进行扫描装配对应的Bean。
为了验证@ComponentScan的两个配置项,首先定义一个接口IStaffService,
package pro.jamal.blog.demo6; import pro.jamal.blog.demo5.annotation.Staff; /** * @author: lyj * @Date: 2019/6/8 */ public interface IStaffService { public void printStaffInfo(Staff staff); }
使用接口来编写一些操作类是Spring所推荐的,他可以将定义和实现相分离,这样更为灵活。这里添加一个IStaffService的实现类。
package pro.jamal.blog.demo6; import org.springframework.stereotype.Component; import pro.jamal.blog.demo5.annotation.Staff; /** * @author: lyj * @Date: 2019/6/8 */ @Component public class StaffServiceImpl implements IStaffService { @Override public void printStaffInfo(Staff staff) { System.out.println("[id="+staff.getId()+"]"); System.out.println("[name="+staff.getName()+"]"); System.out.println("[salary="+staff.getSalary()+"]"); } }
这里的@Compent表明它Spring所需要的Bean,而且实现了对应IStaffService接口所定义的printStaffInfo方法。
为了装配StaffService和Staff的两个Bean,需要给@ComponentScan加上对应的配置,
package pro.jamal.blog.demo6; import org.springframework.context.annotation.ComponentScan; import pro.jamal.blog.demo5.annotation.Staff; import pro.jamal.blog.demo6.service.impl.StaffServiceImpl; /** * @author: lyj * @Date: 2019/6/8 */ //这里会扫描两个包及其子包 //@ComponentScan(basePackages = {"pro.jamal.blog.demo5.annotation","pro.jamal.blog.demo6"}) //这里会扫描两个类所在的包及其子包 @ComponentScan(basePackageClasses = {Staff.class, StaffServiceImpl.class}) public class ApplicationConfig { }
* 如果采用多个@ComponentScan去定义对应的包,但每定一个@ComponentScan,Spring就会为所定义的类生成一个新的对象,也就是所配制的Bean将会生成多个实例,这个往往不是我们需要的。
* 对于已定义basePackages和basePackageClasses的@ComponentScan,Spring会进行专门的区分,也就是说在同一个@ComponentScan中即使重复定义相同的包或者存在其子包定义,也不会造成同一个Bean的多次扫描,而导致一个配置生成多个对象。因此建议不要采用多个@ComponentScan注解进行配置,因为一定有重复的包和子包就会产生重复的对象,这不是我们所需要的。对于basePackages和basePackageClasses的选择问题,basePackage的可读性会更好一些,因此在项目中会优先选择使用它,但是在大量重构的工程中,尽量不要使用basePackages,因为很多时候重构修改包名需要反复地配置,而IDE不会给你任何提示。而采用basePackagesClasses,当你对包移动的时候,IDE会有报错提示,并且可以轻松处理这些错误。
测试
package pro.jamal.blog.demo6; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import pro.jamal.blog.demo5.annotation.Staff; import pro.jamal.blog.demo6.service.impl.StaffServiceImpl; /** * @author: lyj * @Date: 2019/6/8 */ public class Client { public static void main(String[] args) { ApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfig.class); Staff staff = context.getBean(Staff.class); StaffServiceImpl staffService = context.getBean(StaffServiceImpl.class); staffService.printStaffInfo(staff); } }