Spring IoC 容器的工作是通过管理对象的生命周期和配置来保持业务逻辑清晰,但是 Spring 容器并不会自动知道要管理哪些 bean。所以我们来告诉 Spring 应该处理哪些 bean 以及如何处理,很简单这就是 Spring 的 @Component 和 @ComponentScan 注释的作用所在。
Spring的@Component注释的作用
创建一个由 Spring 管理的 JavaBean,那么引起 IoC 容器注意的一种方法就是用 Spring 的 @Component 注释来装饰该类,其他注解@Service等同于@Component,这里以@Component注解来统一说明。
以下代码显示两个类由 Spring 容器管理,因此都使用 @Component 注释进行修饰。但是,简单地将 @Component 注释添加到 JavaBean 并不意味着它将自动由Spring 框架进行管理。只有当明确告知容器搜索 @Component 注释的类时,注释才会使 Spring 管理修饰的类。这就是 @ComponentScan 注释的作用所在。
@Component
public class Score {
int wins, losses, ties;
}
@Component
public class Game {
@Autowired
private Score score;
public void playTheGame(String gesture) {
score.wins++;
}
}
Spring 的 @ComponentScan 注解起什么作用?
如果在初始化期间,Spring 容器加载了一个使用 @ComponentScan 注释修饰的 bean,Spring 将在该类的包和子包中搜索带有 @Component 注释的类。如果找到,Spring IoC 容器将自动管理它们。
在下面的代码中,SimpleExample 类既用 @ComponentScan 注释修饰,又在 Spring IoC 容器初始化时加载到 Spring 的 ApplicationContext 中。ApplicationContext 是代表 Spring IoC 容器的 Java 接口的名称。
@ComponentScan
public class SimpleExample {
public static void main(String[] args) {
SpringApplication springApp = new SpringApplication(Score.class, Game.class);
ApplicationContext springContainer = springApp.run(args);
Game game = springContainer.getBean(Game.class);
game.playTheGame("rock");
System.out.print(game.score.wins);
System.out.print(game.score.wins); // prints 1
}
}
当此代码运行时,Game类和Score类都由Spring容器管理。当main方法运行时,会从容器中拉取Game类的实例,并通过Spring的依赖注入机制初始化Game的分数,当将获胜次数打印到控制台时,显示了正确的输出1。
Spring 的 @Component 和 @ComponentScan 一起
可以看到,@ComponentScan 和 @Component 注释一起起作用。@Component 注释表示如果在组件扫描期间发现某个类,则该类应该由Spring IoC 容器进行管理,而使用 @ComponentScan 注释修饰的类才是真正触发组件扫描的类。
@SpringBootApplication注解
实际使用中我们用到更多的是这个@SpringBootApplication注解,并没有看到ComponentScan,那是因为@SpringBootApplication这个注解帮我们做了很多事情,已经自动帮我引入了@ComponentScan注解,同时有默认的扫描Component策略。
ComponentScan扫描包的策略
指定包
@ComponentScan(basePackages = "com.example")
public class SpingbootBannerDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpingbootBannerDemoApplication.class, args);
}
}
过滤掉指定的class
@ComponentScan(basePackages = "com.example", excludeFilters = {@ComponentScan.Filter(type= FilterType.CUSTOM, classes={HelloWorld.class}) })
public class SpingbootBannerDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpingbootBannerDemoApplication.class, args);
}
}