Spring注解扫描:ComponentScan使用及原理详解

概述

当下Spring Boot之所以能成为主流首选开发框架,得益于其核心思想:约定大于配置和Spring提供的基于注解配置式开发,解决了繁琐的XML文件配置问题,大大提高了开发效率。基于Spring MVC三层架构框架开发的项目中大量用到@Controller, @Service...等注解,即使这些类在不同包路径下,都能被注入到Spring容器中,然后可以相互之间进行依赖注入、使用。这时候就有一个问题了:Spring是如何将声明了@Component注解的Bean注入到Spring容器当中的呢?怎么做到bean的类定义可以随意写在不同包路径下?答案就是今天的主角@ComponentScan,该注解告诉Spring扫描那些包路径下的类,然后判断如果类使用了@Component,@Controller, @Service...等注解,就注入到Spring容器中。

之前我们讲过一个注解@Component,它就是声明当前类是一个bean组件,那@ComponentScan注解顾名思义就是扫描声明了@Component注解的类,然后注入到Spring容器中的。这时候你可能会问@Controller, @Service...等注解为什么也会被扫描、注入到Spring容器中。 接下来我们就看看这些注解@Controller, @Service, @Repository@Component的关系,从这些注解的定义上来看都声明了@Component,所以都是@Component衍生注解,其作用及属性和@Component是一样,只不过是提供了更加明确的语义化,是spring框架为我们提供明确的三层使用的注解,使我们的三层对象更加清晰

@Controller:一般用于表现层的注解。
@Service:一般用于业务层的注解。
@Repository:一般用于持久层的注解。
@RestController:是@Controller的衍生注解,主要用于前后端分离,接口返回JSON格式数据的表现层注解

Spring-Boot vs Spring-Framework 版本对照关系 | Spring-Boot | Spring-Framework | Java Version Range | | -------------- | ---------------- | ------------------ | | 3.1.2 | 6.1.x | JDK 17 - JDK 23 | | 3.1.2 | 6.0.11 | JDK 17 - JDK 21 | | 2.7.14 | 5.3.29 | JDK 8 - JDK 21 | | 2.6.15 | 5.3.27 | JDK 8 - JDK 21 | | 2.5.15 | 5.3.27 | JDK 8 - JDK 21 | | 2.4.13 | 5.3.13 | JDK 8 - JDK 21 | | 2.3.12.RELEASE | 5.2.15.RELEASE | JDK 8 - JDK 9 | | 2.3.6.RELEASE | 5.2.11.RELEASE | JDK 9 - JDK 9 |

其它Spring Boot的参考

## Spring Exit Codes ### Overview

Every application returns an exit code on exit; this code can be any integer value including negative values.

In this quick tutorial, we’re going to find out how we can return exit codes from a Spring Boot application.

Spring Boot and Exit Codes

A Spring Boot application will exit with code 1 if an exception occurs at startup. Otherwise, on a clean exit, it provides 0 as the exit code.

Spring registers shutdown hooks with the JVM to ensure the ApplicationContext closes gracefully on exit. In addition to that, Spring also provides the interface org.springframework.boot.ExitCodeGenerator. This interface can return the specific code when System.exit() is called.

Implementing Exit Codes

Spring Boot provides four methods that allow us to work with exit codes.

The ExitCodeGenerator interface and ExitCodeExceptionMapper allow us to specify custom exit codes, while the ExitCodeEvent allows us to read the exit code on exit. Moreover, it’s even possible for exceptions to implement the ExitCodeGenerator interface.

ExitCodeGenerator

Let’s create a class that implements the ExitCodeGenerator interface. We have to implement the method getExitCode() which returns an integer value:

@SpringBootApplication
public class ExitCodeGeneratorDemoApplication implements ExitCodeGenerator {

    public static void main(String[] args) {
        System.exit(SpringApplication
        .exit(SpringApplication.run(DemoApplication.class, args)));
    }

    @Override
    public int getExitCode() {
        return 42;
    }
}

Here, the ExitCodeGeneratorDemoApplication class implements the ExitCodeGenerator interface. Also, we wrapped the call to SpringApplication.run() with SpringApplication.exit().

On exit, the exit code will now be 42.

ExitCodeExceptionMapper

Now let’s find out how we can return an exit code based on a runtime exception. For this, we implement a CommandLineRunner which always throws a NumberFormatException and then register a bean of type ExitCodeExceptionMapper:

@Bean
CommandLineRunner createException() {
    return args -> Integer.parseInt("test") ;
}

@Bean
ExitCodeExceptionMapper exitCodeToexceptionMapper() {
    return exception -> {
        // set exit code based on the exception type
        if (exception.getCause() instanceof NumberFormatException) {
            return 80;
        }
        return 1;
    };
}

Within the ExitCodeExceptionMapper, we simply map the exception to a certain exit code.

ExitCodeEvent

Next, we’ll capture an ExitCodeEvent to read the exit code of our application. For this, we simply register an event listener which subscribes to ExitCodeEvents (named DemoListener in this example):

@Bean
DemoListener demoListenerBean() {
    return new DemoListener();
}

private static class DemoListener {
    @EventListener
    public void exitEvent(ExitCodeEvent event) {
        System.out.println("Exit code: " + event.getExitCode());
    }
}

Now, when the application exits, the method exitEvent() will be invoked and we can read the exit code from the event.

Exception with Exit Code

An exception can also implement the ExitCodeGenerator interface. When throwing such exceptions, Spring Boot returns the exit code provided by the implemented getExitCode() method. For instance:

public class FailedToStartException extends RuntimeException implements ExitCodeGenerator {

    @Override
    public int getExitCode() {
        return 42;
    }
}

If we throw an instance of FailedToStartException, Spring Boot will detect this exception as an ExitCodeGenerator and report 42 as the exit code.

Conclusion

In this article, we’ve gone through multiple options provided by Spring Boot to work with exit codes.

It’s very important for any application to return the right error code while exiting. The exit code determines the state of the application when the exit happened. In addition to that, it helps in troubleshooting.

Code samples can be found over on GitHub.

Spring 核心特性

Spring 中的 @Scheduled 注解