怎样去理解@ComponentScan注解

在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);
        }
    }
}

SpringbootIn10StepsApplicationcom.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 用于扫描指定包下的类。就像看都有哪些举手了。

猜你喜欢

转载自blog.csdn.net/nizhengjia888/article/details/85065747