אנטוטציית @SpringBootApplication של Spring Boot, מחלקת SpringApplication

Spring Boot @SpringBootApplication הוספת אונוטציה

האונוטציה @SpringBootApplication של Spring Boot משמשת לסימון של מחלקת תצורה שמצהירה על אחד או יותר מסדרי @Bean וגם מפעילה אוטומטית וסריקת רכיבים. זהה להצהרה על מחלקה עם @Configuration, @EnableAutoConfiguration ו- @ComponentScan.

מחלקת SpringApplication של Spring Boot

Spring Boot כיתת SpringApplication משמשת להתאמת והפעלת אפליקציית Spring מתוך שיטת main ב-Java. כיתה זו יוצרת באופן אוטומטי את ה-ApplicationContext מתוך מסלול ה-Classpath, סורקת את מחלקות התצורה ומשיקה את האפליקציה. כיתה זו מועילה מאוד בהפעלת אפליקציות Spring MVC או אפליקציות REST של Spring באמצעות Spring Boot.

דוגמת SpringBootApplication ו-SpringApplication

בשיעור האחרון על Spring RestController, יצרנו שירות רשת RESTful של Spring והפצנו אותו על Tomcat. היינו צריכים ליצור את web.xml וקובץ הקשר של spring באופן ידני. כמו כן, היינו צריכים להוסיף באופן ידני תלות ב-Spring MVC ולנהל את גרסאותיהן. כאן נשנה את הפרויקט כך שירוץ כאפליקציית Spring Boot וניפטר מקבצי ההגדרה. זה יסייע בבדיקה מהירה של לוגיקת היישום שלנו מכיוון שלא נצטרך לבנות ולהפיץ את הפרויקט ידנית לשרת ה-Tomcat החיצוני.

עליך לבדוק את הפרויקט הקיים מה-מאגר GitHub שלנו, בסעיפים הבאים נבצע את השינויים הנדרשים בקבצי הפרויקט.

התמונה למטה מציגה את מבנה הפרויקט הסופי שלנו.

הוספת תלות Maven של Spring Boot

השלב הראשון הוא לנקות את קובץ ה־pom.xml ולהגדיר אותו עבור Spring Boot. מכיוון שזו שירות REST, אנו צריכים רק את תלות ה־spring-boot-starter-web. במקרה זה, יהיה עלינו לשמור על תלותי JAXB מכיוון שאנחנו מריצים על Java 10 ורוצים לתמוך גם בבקשות ותגובות ב־XML. יהיה עלינו גם להוסיף את התוסף spring-boot-maven-plugin. תוסף זה מאפשר לנו להריץ את היישום הפשוט שלנו כיישום Spring Boot. הנה הקובץ המעודכן שלנו ב־pom.xml.

<project xmlns="https://maven.apache.org/POM/4.0.0"
	xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>Spring-RestController</groupId>
	<artifactId>Spring-RestController</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.2.RELEASE</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>
	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>10</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<!-- JAXB for XML Response needed to explicitly define from Java 9 onwards -->

		<dependency>
			<groupId>javax.xml.bind</groupId>
			<artifactId>jaxb-api</artifactId>
		</dependency>
		<dependency>
			<groupId>org.glassfish.jaxb</groupId>
			<artifactId>jaxb-runtime</artifactId>
			<version>2.3.0</version>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>javax.activation</groupId>
			<artifactId>javax.activation-api</artifactId>
			<version>1.2.0</version>
		</dependency>
	</dependencies>

	<build>
		<!-- added to remove Version from WAR file -->
		<finalName>${project.artifactId}</finalName>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>

אפשר למחוק את הספרייה WebContent או להשאיר אותה כפי שהיא, היא לא תשמש את היישום שלנו ב־Spring Boot.

קובץ היישום של Spring Boot

עכשיו עלינו ליצור מחלקת Java עם שיטת main, לסמן אותה באנוטציה @SpringBootApplication ולקרוא לשיטה SpringApplication.run().

package com.journaldev.spring;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBootRestApplication {

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

רץ את המחלקה כיישום Java והיא תפיק את הפלט הבא. הסרתי חלק מהלוגרים שאינם רלוונטיים לכאן. היישום לא ייסגר ויחכה לבקשות מהלקוח.

2018-06-18 14:33:51.276  INFO 3830 --- [           main] c.j.spring.SpringBootRestApplication     : Starting SpringBootRestApplication on pankaj with PID 3830 (/Users/pankaj/Documents/eclipse-jee-workspace/Spring-RestController/target/classes started by pankaj in /Users/pankaj/Documents/eclipse-jee-workspace/Spring-RestController)
2018-06-18 14:33:51.280  INFO 3830 --- [           main] c.j.spring.SpringBootRestApplication     : No active profile set, falling back to default profiles: default
2018-06-18 14:33:51.332  INFO 3830 --- [           main] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@38467116: startup date [Mon Jun 18 14:33:51 IST 2018]; root of context hierarchy
2018-06-18 14:33:52.311  INFO 3830 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2018-06-18 14:33:52.344  INFO 3830 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2018-06-18 14:33:52.344  INFO 3830 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/8.5.31
2018-06-18 14:33:52.453  INFO 3830 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2018-06-18 14:33:52.453  INFO 3830 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1127 ms
2018-06-18 14:33:52.564  INFO 3830 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean  : Servlet dispatcherServlet mapped to [/]
2018-06-18 14:33:52.927  INFO 3830 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/rest/employee/get/{id}],methods=[GET]}" onto public com.journaldev.spring.model.Employee com.journaldev.spring.controller.EmployeeRestController.getEmployeeByID(int)
2018-06-18 14:33:52.928  INFO 3830 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/rest/employee/getAll],methods=[GET]}" onto public java.util.List<com.journaldev.spring.model.Employee> com.journaldev.spring.controller.EmployeeRestController.getAllEmployees()
2018-06-18 14:33:52.929  INFO 3830 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/rest/employee/create],methods=[POST]}" onto public com.journaldev.spring.model.Employee com.journaldev.spring.controller.EmployeeRestController.createEmployee(com.journaldev.spring.model.Employee)
2018-06-18 14:33:52.929  INFO 3830 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/rest/employee/search/{name}],methods=[GET]}" onto public com.journaldev.spring.model.Employee com.journaldev.spring.controller.EmployeeRestController.getEmployeeByName(java.lang.String)
2018-06-18 14:33:52.929  INFO 3830 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/rest/employee/delete/{id}],methods=[DELETE]}" onto public com.journaldev.spring.model.Employee com.journaldev.spring.controller.EmployeeRestController.deleteEmployeeByID(int)
2018-06-18 14:33:53.079  INFO 3830 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2018-06-18 14:33:53.118  INFO 3830 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2018-06-18 14:33:53.124  INFO 3830 --- [           main] c.j.spring.SpringBootRestApplication     : Started SpringBootRestApplication in 2.204 seconds (JVM running for 2.633)

נקודות חשובות שאפשר להסיק מהלוגים:

  1. מזהה התהליך של אפליקציית Spring Boot הוא 3830.
  2. אפליקציית Spring Boot מפעילה את Tomcat על פורט 8080.
  3. נתיב ההקשר של האפליקציה שלנו הוא "". זה אומר שכאשר אנו קוראים ל-API שלנו, אנחנו לא צריכים לספק הקשר של סרבל.
  4. הלוגר מדפיס את כל ה-APIים שמוגדרים, ראה הודעות Mapped "{[/rest/employee/get/{id}],methods=[GET]}" וכו '.

התמונה למטה מראה דוגמה לקריאה של ה-APIים שנחשפים על ידי אפליקציית Spring Boot שלנו.

SpringBootApplication scanBasePackages

באופן ברירת המחדל, SpringApplication סורקת את חבילת מחלקות התצורה ואת כל התת-חבילות שלה. לכן אם מחלקת SpringBootRestApplication שלנו נמצאת בחבילת com.journaldev.spring.main, אז היא לא תסרוק את החבילה com.journaldev.spring.controller. אפשר לתקן את המצב הזה באמצעות המאפיין SpringBootApplication scanBasePackages.

@SpringBootApplication(scanBasePackages="com.journaldev.spring")
public class SpringBootRestApplication {
}

אובייקטים שנקבעו אוטומטית על ידי Spring Boot

מאחר ו-Spring Boot מספקת תצורה אוטומטית, קיימים הרבה אובייקטים שמקבעים על ידי המערכת. ניתן לקבל רשימה של אובייקטים אלו באמצעות קטע הקוד הבא.

ApplicationContext ctx = SpringApplication.run(SpringBootRestApplication.class, args);
String[] beans = ctx.getBeanDefinitionNames();
for(String s : beans) System.out.println(s);

למטה רשימת האובייקטים שנקבעו על ידי היישום שלנו ב-Spring Boot.

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
springBootRestApplication
org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory
employeeRestController
employeeRepository
org.springframework.boot.autoconfigure.AutoConfigurationPackages
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration
org.springframework.boot.autoconfigure.condition.BeanTypeRegistry
propertySourcesPlaceholderConfigurer
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration$TomcatWebSocketConfiguration
websocketContainerCustomizer
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration$EmbeddedTomcat
tomcatServletWebServerFactory
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration
servletWebServerFactoryCustomizer
tomcatServletWebServerFactoryCustomizer
server-org.springframework.boot.autoconfigure.web.ServerProperties
org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor
org.springframework.boot.context.properties.ConfigurationBeanFactoryMetadata
webServerFactoryCustomizerBeanPostProcessor
errorPageRegistrarBeanPostProcessor
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration$DispatcherServletConfiguration
dispatcherServlet
mainDispatcherServletPathProvider
spring.mvc-org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration$DispatcherServletRegistrationConfiguration
dispatcherServletRegistration
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration
org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration
defaultValidator
methodValidationPostProcessor
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration$WhitelabelErrorViewConfiguration
error
beanNameViewResolver
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration$DefaultErrorViewResolverConfiguration
conventionErrorViewResolver
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration
errorAttributes
basicErrorController
errorPageCustomizer
preserveErrorControllerTargetClassPostProcessor
spring.resources-org.springframework.boot.autoconfigure.web.ResourceProperties
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter$FaviconConfiguration
faviconHandlerMapping
faviconRequestHandler
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration$EnableWebMvcConfiguration
requestMappingHandlerAdapter
requestMappingHandlerMapping
mvcConversionService
mvcValidator
mvcContentNegotiationManager
mvcPathMatcher
mvcUrlPathHelper
viewControllerHandlerMapping
beanNameHandlerMapping
resourceHandlerMapping
mvcResourceUrlProvider
defaultServletHandlerMapping
mvcUriComponentsContributor
httpRequestHandlerAdapter
simpleControllerHandlerAdapter
handlerExceptionResolver
mvcViewResolver
mvcHandlerMappingIntrospector
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration$WebMvcAutoConfigurationAdapter
defaultViewResolver
viewResolver
welcomePageHandlerMapping
requestContextFilter
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration
hiddenHttpMethodFilter
httpPutFormContentFilter
org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration
mbeanExporter
objectNamingStrategy
mbeanServer
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration$Jackson2ObjectMapperBuilderCustomizerConfiguration
standardJacksonObjectMapperBuilderCustomizer
spring.jackson-org.springframework.boot.autoconfigure.jackson.JacksonProperties
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration$JacksonObjectMapperBuilderConfiguration
jacksonObjectMapperBuilder
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration$ParameterNamesModuleConfiguration
parameterNamesModule
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration$JacksonObjectMapperConfiguration
jacksonObjectMapper
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration
jsonComponentModule
org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration$StringHttpMessageConverterConfiguration
stringHttpMessageConverter
spring.http.encoding-org.springframework.boot.autoconfigure.http.HttpEncodingProperties
org.springframework.boot.autoconfigure.http.JacksonHttpMessageConvertersConfiguration$MappingJackson2HttpMessageConverterConfiguration
mappingJackson2HttpMessageConverter
org.springframework.boot.autoconfigure.http.JacksonHttpMessageConvertersConfiguration
org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration
messageConverters
org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration$JacksonCodecConfiguration
jacksonCodecCustomizer
org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration
org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration
spring.info-org.springframework.boot.autoconfigure.info.ProjectInfoProperties
org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration
spring.security-org.springframework.boot.autoconfigure.security.SecurityProperties
org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration
restTemplateBuilder
org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration$TomcatWebServerFactoryCustomizerConfiguration
tomcatWebServerFactoryCustomizer
org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration
characterEncodingFilter
localeCharsetMappingsCustomizer
org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration
multipartConfigElement
multipartResolver
spring.servlet.multipart-org.springframework.boot.autoconfigure.web.servlet.MultipartProperties

זו רשימה גדולה מאוד, ישנם הרבה אובייקטים שנקבעו אוטומטית שאנו לא משתמשים בהם. ניתן לייעל את היישום שלנו ב-Spring Boot על ידי השבתתם באמצעות השימוש במאפייני @SpringBootApplication exclude או excludeName. קטע הקוד למטה ישבת את קביעת האובייקטים המשתמשים ב-JMX וב-Multipart אוטומטית.

@SpringBootApplication(scanBasePackages = "com.journaldev.spring", exclude = {
org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration.class, org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration.class })
public class SpringBootRestApplication {
}

שימו לב שאם ננסה לשבת כיתות שאינן קביעה אוטומטית, נקבל שגיאה והיישום שלנו לא יתחיל.

@SpringBootApplication(scanBasePackages = "com.journaldev.spring", exclude = {com.journaldev.spring.controller.EmployeeRestController.class })
public class SpringBootRestApplication {
}

קטע הקוד למעלה יזרוק את השגיאה הבאה:

2018-06-18 15:10:43.602 ERROR 3899 --- [main] o.s.boot.SpringApplication: Application run failed

java.lang.IllegalStateException: The following classes could not be excluded because they are not auto-configuration classes:
	- com.journaldev.spring.controller.EmployeeRestController

זהו הכל בהקשר של האנוטציה SpringBootApplication ודוגמה של SpringApplication.

ניתן להוריד את הפרויקט הסופי מה-מאגר הקוד ב-GitHub שלנו.

Source:
https://www.digitalocean.com/community/tutorials/springbootapplication-springapplication