在Spring mvc当中经常可以看到@ComponentScan这个注解,
那么怎么样去理解它呢?
1.配置视图控制器
package com.apress.prospringmvc.bookstore.web.config;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = { "com.apress.prospringmvc.bookstore.web" })
public class WebMvcContextConfiguration extends WebMvcConfigurerAdapter {
@Override
public void addViewControllers(final ViewControllerRegistry registry) {
registry.addViewController("/index.htm").setViewName("index");
}
}
2.基于注解的Controller
package com.apress.prospringmvc.bookstore.web;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class IndexController {
@RequestMapping(value = "/index.htm")
public ModelAndView indexPage() {
return new ModelAndView(“index");
}
}
那么对于配置的视图控制器加了
@Configuration 和@ComponentScan注解背后会做什么呢?
其实很简单,@ComponentScan告诉Spring 哪个packages 的用注解标识的类 会被spring自动扫描并且装入bean容器。
例如,如果你有个类用@Controller注解标识了,那么,如果不加上@ComponentScan,自动扫描该controller,那么该Controller就不会被spring扫描到,更不会装入spring容器中,因此你配置的这个Controller也没有意义。
类上的注解@Configuration 是最新的用注解配置spring,也就是说这是个配置文件,和原来xml配置是等效的,只不过现在用java代码进行配置了 加上一个@Configuration注解就行了,是不是很方便,不需要那么繁琐的xml配置了,这样基于注解的配置,可读性也大大增高了。
@Configuration
@ComponentScan(basePackages = "org.example", nameGenerator = MyNameGenerator.class)
public class AppConfig {
...
}
在xml中的写法如此:
<beans>
<context:component-scan base-package="org.example"
name-generator="org.example.MyNameGenerator" />
</beans>
@componentScan注解的方法如下图:
Spring Boot学习笔记1:Spring, Spring Boot中的@Component 和@ComponentScan注解用法介绍
通过本文你将学到:
Component Scan是什么?
为什么ComponentScan很重要?
项目中Spring Boot会对哪些包自动执行扫描(Component Scan)?
如何利用Spring Boot定义扫描范围?
项目启动时关于Component Scan的常见报错
@ComponentScan
如果你理解了ComponentScan,你就理解了Spring.
Spring是一个依赖注入(dependency injection)框架。所有的内容都是关于bean的定义及其依赖关系。
定义Spring Beans的第一步是使用正确的注解-@Component或@Service或@Repository.
但是,Spring不知道你定义了某个bean除非它知道从哪里可以找到这个bean.
ComponentScan做的事情就是告诉Spring从哪里找到bean
由你来定义哪些包需要被扫描。一旦你指定了,Spring将会将在被指定的包及其下级的包(sub packages)中寻找bean
下面分别介绍在Spring Boot项目和非Spring Boot项目(如简单的JSP/Servlet或者Spring MVC应用)中如何定义Component Scan
Spring Boot项目
总结:
如果你的其他包都在使用了@SpringBootApplication注解的main app所在的包及其下级包,则你什么都不用做,SpringBoot会自动帮你把其他包都扫描了
如果你有一些bean所在的包,不在main app的包及其下级包,那么你需要手动加上@ComponentScan注解并指定那个bean所在的包
举个栗子,看下面定义的类
package com.in28minutes.springboot.basics.springbootin10steps;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
@SpringBootApplication
public class SpringbootIn10StepsApplication {
public static void main(String[] args) {
ApplicationContext applicationContext =
SpringApplication.run(SpringbootIn10StepsApplication.class, args);
for (String name : applicationContext.getBeanDefinitionNames()) {
System.out.println(name);
}
}
}
类 SpringbootIn10StepsApplication
在com.in28minutes.springboot.basics.springbootin10steps
包下,这个类使用了@SpringBootApplication
注解,该注解定义了Spring将自动扫描包com.in28minutes.springboot.basics.springbootin10steps
及其子包下的bean
如果你项目中所有的类都定义在上面的包及其子包下,那你不需要做任何事。
但假如你一个类定义在包com.in28minutes.springboot.somethingelse
下,则你需要将这个新包也纳入扫描的范围,有两个方案可以达到这个目的。
方案1
定义@CoponentScan(“com.in28minutes.springboot”)
这么做扫描的范围扩大到整个父包com.in28minutes.springboot
@ComponentScan(“com.in28minutes.springboot”)
@SpringBootApplication
public class SpringbootIn10StepsApplication {
方案2
定义分别扫描两个包
@ComponentScan({“com.in28minutes.springboot.basics.springbootin10steps”,”com.in28minutes.springboot.somethingelse”})
@ComponentScan({"com.in28minutes.springboot.basics.springbootin10steps","com.in28minutes.springboot.somethingelse"})
@SpringBootApplication
public class SpringbootIn10StepsApplication {
非Spring Boot项目
在非Spring Boot项目中,我们必须显式地使用@ComponentScan注解定义被扫描的包,可以通过XML文件在应用上下文中定义或在Java代码中对应用上下文定义
Java代码方式
@ComponentScan({"com.in28minutes.package1","com.in28minutes.package2"})
@Configuration
public class SpringConfiguration {
XML文件方式
<context:component-scan base-package="com.in28minutes.package1, com.in28minutes.package2" />
项目中常见关于Component Scan的报错
你是否在项目启动中遇到过类似这样的报错:
WARNING: No mapping found for HTTP request with URI [/spring-mvc/login] in DispatcherServlet with name ‘dispatcher’
WARNING: No mapping found for HTTP request with URI [/list-todos] in DispatcherServlet with name ‘dispatcher’
或者:
ERROR:No qualifying bean of type [com.in28minutes.springboot.jpa.UserRepository] found for dependency [com.in28minutes.springboot.jpa.UserRepository]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}…
报错的根因都是bean没有被Spring找到
遇到这些错误你应该检查:
你是否给类加了正确的注解@Controller,@Repository,@Service或@Component
你是否在应用上下文定义了Component Scan
报错类所在的包是否在Component Scan中指定的包的范围
@Component and @ComponentScan 的区别
@Component 和 @ComponentScan的使用目的不一样
- 在某个类上使用@Component注解,表明当需要创建类时,这个被注解的类是一个候选类。就像是举手。
- @ComponentScan 用于扫描指定包下的类。就像看都有哪些举手了。