To keep up with Spring 6, Spring Boot released 3.0.0 on November 24, 2022. The current version is 3.0.1 (2022-12-23). Spring 6 requires JDK 17+, and naturally Spring Boot 3 requires JDK 17+ to work. For those who have been clinging to JDK 8, upgrading to Spring Boot 3 is a big challenge.
What are the significant features that Spring Boot brings to the table?
- Relies on Spring 6, requires Java 17 minimum, Java 19 compatible
- support for generating GraalVM native images, replacing the experimental Spring Native project
- requires Java EE 9 and supports Jakarta EE 10 as a minimum
- dependency migration from Java EE to Jakarta EE API
- Upgrade to Tomcat 10
For guidance on upgrading from Spring Boot 2.x to Spring Boot 3, see the official Spring Boot 3.0 Migration Guide.
For Spring Boot 1 projects, you must first upgrade to Spring Boot 2. For early Spring Boot 2, the first step is to upgrade to Spring Boot 2.7.x. Then change the JDK to version 17 or later, compile, run, and change the code if you have problems.
The most significant API change is
jakarta.servlet, for example
- javax.servlet -> jakarta.servlet
- javax.annotations -> jakarta.annotations
- javax.persistence -> jakarta.persistence
- javax.transaction -> jakarta.transaction
I have a project with Spring Boot 2.7.6 + JDK 17, upgraded directly to Spring Boot 3.0.1. then tried to compile with
mvn compile, due to changes in API package names such as
javax.servlet.http.HttpServletRequest etc. will cause compilation failure, directly replace
jakarta, such as
jakarta.servlet.http.HttpServletRequest will work.
Finally, it can be compiled by
mvn compile, but it will throw an exception at runtime.
When I come to the CalcEngineFactory code, it is clear that there is an annotation
@Named, why it is not registered as a Spring bean anymore? If I replace the annotation
@Named with Spring’s @Component, there is no problem. The problem is solved, let’s find the reason, debug, to
org.springframework.context.annotation.ClassPathBeanDefinitionScanner.doScan(String... basePackages) method.
Classes annotated with
@Named are not considered SpringBean by the
findCandidateComponents(basePackage) method, while those annotated with
@Component are. Continue following the method
scanCandidateComponents(basePackage), you can see the following code.
The logic of
false for classes annotated with
@Named and true for classes annotated with
isCandidateComponent() method uses
includedFilters to determine
Focus on this
includedFilters, which in Spring Boot 3 contains three
AnnotationTypeFilters, which are as follows
- annotationType: interface org.springframework.stereotype.Component
- annotationType: interface jakarta.annotation.ManagedBean
- annotationType: interface jakarta.inject.Named
It is true that there is
@Named, but it is not
javax.inject.Named, which we used earlier, but
javax.inject.Named comes from the
javax.inject:javax.inject dependency, it will compile fine after upgrading to Spring Boot 3, but will throw an exception at runtime.
This is why the
@Component annotation solves the problem, but of course the sub-interfaces
@Controller, etc. can also be registered as Spring beans with
This is why the
@Component annotation solves the problem, but of course sub-interfaces that use
@Component, such as
@Controller and so on, can also be registered as Spring beans.
If you still insist on
@Named, then remove the
javax.inject:javax.inject dependency and replace it with the
@jakarta.inject.Named annotation. After upgrading to Spring Boot 3, have in mind whether
javax should be replaced with
If you compare the code comments of the Spring 5 and 6
ClassPathBeanDefinitionScanner classes, it also illustrates the change from
If you still want Spring to treat classes annotated with
@javax.inject.Named as Spring beans, you need to see if you can affect the value of the
includeFilters: List<TypeFilter> variable in the
org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider. The relevant code in the
ComponentScanAnnotationParser class is as follows.
That uses the
includeFilters attributes of the @ComponentScan annotation, so we can add the following configuration to the Spring Boot Java configuration or startup class.
This will add
annotationType: interface javax.inject.Named to the default includeFilters.
Classes annotated with
@javax.inject.Named will be treated as Spring beans as well. However, I don’t recommend this approach and try to use the Spring Boot 3 (Spring 6) compliant approach with
Finally, annotation classes other than the
@Named annotation in
javax.inject:javax.inject may also not work properly and require attention.