An overview,

At present, Spring Boot has developed to 2.3.4.RELEASE, and there are a lot of pitfalls in upgrading from Spring Boot1.x step by step to the current 2.3.4. It is very important to understand the features of the new version, which can help us avoid many unnecessary troubles.

Spring. IO/projects/sp…

The latest official RELEASE is 2.3.4

 

Since I have been working on components for the Spring Boot stack, I have recently been refactoring some of the basic components, so I will review the features of the current version from scratch. This article only introduces some features of the current Spring Boot 2.3.4.RELEASE. We will not expand on the properties.

Start from scratch with Application

First of all, we will initialize each project for testing. You can use the official https://start.spring.io/ production, or use the plug-in Spring Boot of IDEA to initialize the project.

1. Startup Failure

If the application fails to start, Spring Boot will help us print the information about the failure in the log. For example, if I start the application using port 6080 for the second time, I will be prompted as follows

***************************APPLICATION FAILED TO START***************************Description:Embedded servlet container failed to start. Port 6080 was already in use.Action:Identify and stop the process that's listening on port 8080 or configure this application to listen on another port.
Copy the code

It’s nice to have this kind of friendly prompt, and Spring Boot also provides us with more extended interface FailureAnalyzer and abstract class FailureAnalyzer that responds to it. If we do not meet its default startup exception information, we can do some custom development with FailureAnalyzer (such as printing the stack when an exception occurs, etc.). The FailureAnalyzer extension uses SPI. So we need to create meta-INF /spring.factories in our application to declare our implementation.

/** Create our own class first, and we can use our own needs for exception interception, PortInUseException * @className LearningFailureAnalyzer * @author QIANGLU * @date 2020/9/23 9:10 PM * @version 1.0 */public Class LearningFailureAnalyzer extends AbstractFailureAnalyzer<PortInUseException> {private static  final Logger LOGGER = LoggerFactory.getLogger(LearningFailureAnalyzer.class); @override protected FailureAnalysis Analyze (Throwable rootFailure, PortInUseException cause) {logger. error(" I have an exception, Wow aka aka aka aka "); Return new FailureAnalysis(" port: "+cause.getPort()+" occupied ",cause.getMessage(),rootFailure); }}// Create a meta-INF /spring.factories The following org. Springframework. Boot. Diagnostics. FailureAnalyzer = \ Com. Qianglu. Chapter1. Failure. LearningFailureAnalyzer / / third cloth start our application twice, you will find, Printing information is that we need the * * * * * * * * * * * * * * * * * * * * * * * * * * * the APPLICATION FAILED TO START * * * * * * * * * * * * * * * * * * * * * * * * * * * Description: port: Action:Port 6080 is already in useCopy the code

This thing can be used in many scenarios, we think about whether there is a point of inspiration

2. Lazy Initialization

When Spring Boot first came out, people teased it for being slow to load, but now it’s lazy. By allowing your application to start lazy loading, your Beans do not need to be created at project startup. This can save you a lot of startup time, but there are pros and cons. Lazy loading in web applications can cause many of your Web-related beans to be lazily loaded until a request comes in.

And the official thing is, if you delay initialization, then some problems might be found later. For example, we used to have some configuration mismatches and would often report XXXbean could not be found at startup. Hey hey, now can not, the same start success, only when you use to give you off the chain, ask you afraid.

There is also the official prompt for late initialization, which can lead to a small initial JVM memory performance, but be careful to configure enough memory for future object creation (I think this is not a problem in general, do not need too much attention).

Let’s take a look at two configurations:

  • Use SpringApplication to call the setLazyInitialization method
  • Use the configuration spring.main.lazy-initialization=true

If you have Lazy initialization and some special type of initialization, you can configure @lazy (false) to turn off Lazy loading.

3. Configure the Banner

This thing to tell the truth I do not know what to use, before we are configured with a Buddha to protect safety, entertainment is greater than the actual bar, of course, there may be no point to GET.

The configuration is also simple: place banner.txt in your classpath and specify the location of the file via the spring.banner.location configuration. Of course, there are a lot of attributes, but I don’t want to talk about encoding, GIF, version and so on.

4. Configure your SpringApplication

We usually start classes by calling SpringApplication.run directly. But if you think it’s too simple to be interesting, springApplication.run has a lot of interesting properties that you can check out, like I turned off the banner

public static void main(String[] args) { SpringApplication app = new SpringApplication(MySpringConfiguration.class); app.setBannerMode(Banner.Mode.OFF); app.run(args); }Copy the code

Of course, there are many configuration properties. You can also configure SpringApplication properties using application.yml.

5. Fluent Builder API

The SpringApplicationBuilder class is available to help you create multiple levels of ApplicationContext using a stream build. SpringApplicationBuilder can help us build a hierarchy in such a way as springApplication.run

new SpringApplicationBuilder()        .sources(Parent.class)        .child(Application.class)        .bannerMode(Banner.Mode.OFF)        .run(args);
Copy the code

6. Application Availability

This is about Liveness and Readiness in K8S, which have become the heart of Spring Boot.

To recap, Liveness and Readiness represent all aspects of application state in K8S.

Liveness is a health check. If Liveness fails, the application is in a faulty state and cannot be recovered. Restart the application.

The Readiness state is used to tell the application whether Readiness is ready to accept client requests. If Readiness is not ready, K8S cannot route traffic.

We can use code to monitor Readiness and do what we need to do

@Componentpublic class ReadinessStateExporter { @EventListener public void onStateChange(AvailabilityChangeEvent<ReadinessState> event) { switch (event.getState()) { case ACCEPTING_TRAFFIC: // xxxxx break; case REFUSING_TRAFFIC: // xxxxxx break; }}}Copy the code

We can also change this state for dynamic degradation and isolation if the application fails and cannot be recovered, which is really cool and I suggest you give it a try

@Componentpublic class LocalCacheVerifier { private final ApplicationEventPublisher eventPublisher; public LocalCacheVerifier(ApplicationEventPublisher eventPublisher) { this.eventPublisher = eventPublisher; } public void checkLocalCache() { try { //... } catch (CacheCompletelyBrokenException ex) { AvailabilityChangeEvent.publish(this.eventPublisher, ex, LivenessState.BROKEN); }}}Copy the code

Application Events and Listeners

Spring Boot’s event notification mechanism is a great decoupler, including the distributed remote notification mechanism used by Spring Cloud. This is the core of this mechanism, which adds a layer of middleware for message delivery.

Some events are triggered before the ApplicationContext is created, so in many cases you cannot declare these events using @Beans. It is best to use SpringApplication. AddListeners (…). And SpringApplicationBuilder. Listeners (…). To register the listener.

But if you’re really having trouble with these load times, a handy way to do this is to configure the SPI extension directly in meta-INF/Spring. factories with your listener, for example: org.springframework.context.ApplicationListener=com.example.project.MyListener

The order of events that will be sent at startup is described:

ApplicationStartingEvent sends an event at the start of a run

2, ApplicationEnvironmentPreparedEvent when the Environment is used in this context to send events

3, ApplicationContextInitializedEvent before all the bean definitions, ApplicationContext ready and ApplicationContextInitializers send events has been called

ApplicationPreparedEvent emits an event before the configuration is refreshed and after the bean definition is loaded

ApplicationStartedEvent refreshes the context before executing the implementation of CommandLineRunner

6, AvailabilityChangeEvent send LivenessState.CORRECT the surface application is active

ApplicationReadyEvent is sent after executing the CommandLineRunner interface

8. AvailabilityChangeEvent ReadinessState.ACCEPTING_TRAFFIC indicates that the application can access traffic

ApplicationFailedEvent Sends an application startup failure event

The above is only the event of SpringApplicationEvent, generally we do not need to operate on these, with you have to know its existence, so as not to know how to find a problem, in fact, someone else Spring Boot has been sent to you.

8. Web properties

Normally, using SpringApplication will create the ApplicationContext for us correctly. The way to determine the WebApplicationType, which is the application type, is very simple:

  • If there is a use AnnotationConfigServletWebServerApplicationContext Spring MVC
  • If you don’t put in Spring MVC, but Spring WebFlux exist, use AnnotationConfigReactiveWebServerApplicationContext
  • Have no word with AnnotationConfigApplicationContext
  • If you use Spring MVC and Spring WebFlux WebClient, the Spring MVC suite is used by default, Unless you set SpringApplication. SetWebApplicationType (WebApplicationType) to force change.

(Accessing Application Arguments)

If you want to access SpringApplication.run(…) Parameters, you actually can inject a org. Springframework. Boot. ApplicationArguments object, ApplicationArguments this interface provides the original String [] parameters and parsed option and the option of access, On the demo:

import org.springframework.boot.*; import org.springframework.beans.factory.annotation.*; import org.springframework.stereotype.*; @Componentpublic class MyBean { @Autowired public MyBean(ApplicationArguments args) { boolean debug = args.containsOption("debug"); List<String> files = args.getNonOptionArgs(); // if run with "--debug logfile.txt" debug=true, files=["logfile.txt"] }}Copy the code

Environment variable in the Spring the Boot also registered a CommandLinePropertySource, we can use @ Value to obtain an environment variable.

Use ApplicationRunner or CommandLineRunner

They’re also used a lot if you need to load something at startup. Both interfaces provide a run method, which will be used in springApplication.run (…). Called before execution is complete. Which of these interfaces are suitable for processing something before the application receives a request?

Here’s a practical example

import org.springframework.boot.*; import org.springframework.stereotype.*; @Componentpublic class MyBean implements CommandLineRunner { public void run(String... args) { // Do something... }}Copy the code

If we define the multiple CommandLineRunner or ApplicationRunner implementation, sometimes need a Order to perform again, then you can use org. Springframework. Core. The annotation. The annotations to define the Order.

11. Application Exit

Each SpringApplication registers a shutdown hook with the JVM to ensure a normal exit. Make sure the @predestroy annotation and DisposableBean interface callbacks are executed.

. In addition, if you want to use SpringApplication exit () returns some special exit code, can realize org. Springframework. Boot. ExitCodeGenerator interface, passed to the System. The exit () to return. Such as:

@SpringBootApplicationpublic class ExitCodeApplication { @Bean public ExitCodeGenerator exitCodeGenerator() { return () - > 42; } public static void main(String[] args) { System.exit(SpringApplication.exit(SpringApplication.run(ExitCodeApplication.class, args))); }}Copy the code

The ExitCodeGenerator interface can be implemented with exceptions. When such an exception is encountered, Spring Boot returns the exit code provided by the implemented getExitCode() method

12. Admin Features

. We can use the spring application. Admin. Enabled properties to open the administrator functions. Opened it will give all your SpringApplicationAdminMXBean exposed to MBeanServer, of course, you can also use this feature to remote operation your application. But you need to understand the safety implications and don’t mess around if you don’t have to.

Third, summary

Well, it is too late today, I will write this first, in fact, these contents of the official write are clearly plain, but their own masturbation is still very cool, very comfortable. In fact, in the course of masturbating you will combine your actual knowledge points for some thinking, the new features will also give you a lot of future basic design inspiration. I hope you have more time and energy, at least when I need to know that there is such a thing, there is a direction.