Springboot注解@ServletComponentScan和@ComponentScan

一、SpringBoot中使用Servlet

在SpringBootApplication上使用@ServletComponentScan注解后,Servlet、Filter、Listener可以直接通过@WebServlet、@WebFilter、@WebListener注解自动注册,无需其他代码。

1.在入口Application类上加入注解@ServletComponentScan

packagecom.hui;

importorg.springframework.boot.SpringApplication;

importorg.springframework.boot.autoconfigure.SpringBootApplication;

importorg.springframework.boot.web.servlet.ServletComponentScan;

@SpringBootApplication

@ServletComponentScan

publicclassApplication{

publicstaticvoidmain(String[]args){

SpringApplication.run(Application.class,args);

}

}

2.新建Servlet类,继承HttpServlet并且加入注解@WebServlet(name=“TestServlet”,urlPatterns="/test")

packagecom.hui.qiang;

importjava.io.IOException;

importjavax.servlet.ServletException;

importjavax.servlet.annotation.WebServlet;

importjavax.servlet.http.HttpServlet;

importjavax.servlet.http.HttpServletRequest;

importjavax.servlet.http.HttpServletResponse;

@WebServlet(name="TestServlet",urlPatterns="/test")

publicclassTestServletextendsHttpServlet{

privatestaticfinallongserialVersionUID=1L;

@Override

protectedvoiddoGet(HttpServletRequestreq,HttpServletResponseresp)

throwsServletException,IOException{

System.out.println("doGet");

}

}

3.之后运行代码,在浏览器地址栏输入http://localhost:8080/test,若看到控制台打印doGet,则表示Servlet创建成功。

注意:

(1)如果不加@ServletComponentScan注解则会报404即找不到页面,控制台也扫描不到我们配置的servlet:/test,即无法被映射

(2)如果Application类和Servlet类不在同一包下,则@ServletComponentScan需要添加相应的路径,如Application类在包com.hui.xiao下,则写为@ServletComponentScan(“com.hui.xiao”)或@ServletComponentScan(“com.hui”)

二、Spring,SpringBoot中的@ComponentScan注解用法介绍

@ComponentScan

如果你理解了ComponentScan,你就理解了Spring.

Spring是一个依赖注入(dependencyinjection)框架。所有的内容都是关于bean的定义及其依赖关系。

但是,Spring不知道你定义了一个bean,或者它知道从哪里可以获取这个bean.

定义SpringBeans的第一步是使用正确的注解-@Component或@Service或@Repository.

ComponentScan做的事情就是告诉Spring从哪里找到bean

由你来定义哪些包需要被扫描。一旦你指定了,Spring将会将在被指定的包及其下级的包(subpackages)中寻找bean

下面分别介绍在SpringBoot项目和非SpringBoot项目(如简单的JSP/Servlet或者SpringMVC应用)中如何定义ComponentScan

注:@ComponentScan的不同写法

1.@ComponentScan({“com.xiao.hui”,“com.xiao.qiang”})或@ComponentScan(basePackages={“com.xiao.hui”,“com.xiao.qiang”})

2.@ComponentScan(“com.xiao”)或@ComponentScan(value=“com.xiao”)或@ComponentScan(basePackages={“com.xiao”})

3.@ComponentScan(basePackageClasses=要扫描类.class所在位置的包)意思是要扫描哪个类所在的包,如@ComponentScan(basePackageClasses=hehe.class),这种写法不如上面的那种写法好有局限性

SpringBoot项目

总结:

1.SpringBoot在写启动类的时候如果不使用@ComponentScan指明对象扫描范围,默认指扫描当前启动类所在的包里的对象,如果你的其他包都在使用了@SpringBootApplication注解的主类所在的包及其下级包,则你什么都不用做,SpringBoot会自动帮你把其他包都扫描了。为了方便,我一般都把主类放在了所有类的上一级包中,如项目所有的class文件都放在了包com.beauty的下级包中,则把springboot的主类放在包com.beauty下。

2.如果当前启动类没有包,则在启动时会报错:YourApplicationContextisunlikelytostartduetoa@ComponentScanofthedefaultpackage错误,因为启动类不能直接放在main/java文件夹下,必须要建一个包把它放进去或者使用@ComponentScan指明要扫描的包。

3.如果你有一些bean所在的包,不在主类的包及其下级包,那么你需要手动加上@ComponentScan注解并指定那个bean所在的包。

举个栗子,看下面定义的类:

packagecom.xiao.qiang.qianming;

importorg.springframework.boot.SpringApplication;

importorg.springframework.boot.autoconfigure.SpringBootApplication;

importorg.springframework.context.ApplicationContext;

importorg.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication

publicclassSpringbootApplication{

publicstaticvoidmain(String[]args){

ApplicationContextapplicationContext=

SpringApplication.run(SpringbootApplication.class,args);

for(Stringname:applicationContext.getBeanDefinitionNames()){

System.out.println(name);

}

}

}

类SpringbootApplication在com.xiao.qiang.qianming包下,这个类使用了@SpringBootApplication注解,该注解定义了Spring将自动扫描包com.xiao.qiang.qianming及其子包下的bean

如果你项目中所有的类都定义在上面的包及其子包下,那你不需要做任何事。

但假如你一个类定义在包com.xiao.hui下,则你需要将这个新包也纳入扫描的范围,有两个方案可以达到这个目的。

方案1

定义@ComponentScan(“com.xiao”),这么做扫描的范围扩大到整个父包com.xiao

@ComponentScan("com.xiao")

@SpringBootApplication

publicclassSpringbootIn10StepsApplication{

方案2

定义分别扫描两个包

@ComponentScan({"com.xiao.hui","com.xiao.qiang"})

@SpringBootApplication

publicclassSpringbootIn10StepsApplication{

1

2

3

非SpringBoot项目

在非SpringBoot项目中,我们必须显式地使用@ComponentScan注解定义被扫描的包,可以通过XML文件在应用上下文中定义或在Java代码中对应用上下文定义

Java代码方式:

@ComponentScan({"com.xiao.package1","com.xiao.package2"})

@Configuration

publicclassSpringConfiguration{

注:@Configuration和@ComponentScan注解背后会做什么呢?

其实很简单,@ComponentScan告诉Spring哪个packages的用注解标识的类会被spring自动扫描并且装入bean容器。

例如,如果你有个类用@Controller注解标识了,那么,如果不加上@ComponentScan,自动扫描该controller,那么该Controller就不会被spring扫描到,更不会装入spring容器中,因此你配置的这个Controller也没有意义。

类上的注解@Configuration是最新的用注解配置spring,也就是说这是个配置文件,和原来xml配置是等效的,只不过现在用java代码进行配置了加上一个@Configuration注解就行了,是不是很方便,不需要那么繁琐的xml配置了,这样基于注解的配置,可读性也大大增高了。

XML文件方式:

<context:component-scanbase-package=“com.xiao.package1,com.xiao.package2”/>

三、使用@ComponentScan自动扫描组件实例

包扫描会扫描只要标注了@Controller,@Service,@Repository,@Component这四个注解都会被扫描到容器中。

1、@Controller控制器(注入服务)

用于标注控制层,相当于struts中的action层

2、@Service服务(注入dao)

用于标注服务层,主要用来进行业务的逻辑处理

3、@Repository(实现dao访问)

用于标注数据访问层,也可以说用于标注数据访问组件,即DAO组件.

4、@Component(把普通pojo实例化到spring容器中,相当于配置文件中的)

泛指各种组件,就是说当我们的类不属于各种归类的时候(不属于@Controller、@Services等的时候),我们就可以使用@Component来标注这个类。

案例:<context:component-scanbase-package=”com.*”>

上面的这个例子是引入Component组件的例子,其中base-package表示为需要扫描的所有子包。

有一篇不错的文章(Spring注解详解):https://blog.csdn.net/xyh820/article/details/7303330/

新增控制层的java类:TestController和HelloController

importorg.springframework.stereotype.Controller;

@Controller

publicclassTestController{

}

importorg.springframework.web.bind.annotation.RequestMapping;

importorg.springframework.web.bind.annotation.RequestMethod;

importorg.springframework.web.bind.annotation.RestController;

@RestController

publicclassHelloController{

@RequestMapping(value="/hello",method=RequestMethod.GET)

publicStringhello(){

return"Hello,SpringBoot";

}

}

新建一个业务逻辑层类:TestService

importorg.springframework.stereotype.Service;

@Service

publicclassTestService{

}

新建一个数据库连接Dao类:TestDao

importorg.springframework.stereotype.Repository;

@Repository

publicclassTestDao{

}

新建一个Person:

publicclassPerson{

publicPerson(Stringstring,inti){

}

}

主方法测试:

springboot:

importorg.springframework.boot.SpringApplication;

importorg.springframework.boot.autoconfigure.SpringBootApplication;

importorg.springframework.context.ApplicationContext;

importorg.springframework.context.annotation.ComponentScan;

@SpringBootApplication

@ComponentScan(value="com.hui")

publicclassApplication{

publicstaticvoidmain(String[]args){

ApplicationContextapplicationContext=

SpringApplication.run(Application.class,args);

for(Stringname:applicationContext.getBeanDefinitionNames()){

System.out.println(name);

}

}

}

非springboot:

importorg.springframework.context.ApplicationContext;

importorg.springframework.context.annotation.AnnotationConfigApplicationContext;

importorg.springframework.context.annotation.Bean;

importorg.springframework.context.annotation.ComponentScan;

importorg.springframework.context.annotation.Configuration;

importcom.hui.entity.Person;

@Configuration

@ComponentScan(value="com.hui")

publicclassComponentTest{

@Bean

publicPersongetPerson(){

returnnewPerson("百度好帅",10000);

}

publicstaticvoidmain(String[]args){

@SuppressWarnings("resource")

ApplicationContextapplicationContext=

newAnnotationConfigApplicationContext(ComponentTest.class);

String[]beanNames=applicationContext.getBeanDefinitionNames();

for(Stringbean:beanNames){

System.out.println(bean);

}

}

}

运行Application:

控制台扫描到了/hello,即映射成功

把Application注释掉运行ComponentTest:

参考:

https://blog.csdn.net/Lamb_IT/article/details/80918704

https://jingyan.baidu.com/article/7908e85cc6930daf481ad2b6.html

https://blog.csdn.net/m0_37739193/article/details/85097477

相关推荐