Introduction to SpringBoot
Significance
spring integrates multiple frameworks and requires a lot of configuration files. To simplify configuration, the springboot framework has been introduced.
Advantage
Embedded web server
Auto starter dependencies, simplify dependency references - no version issues
Automatically configure spring - you don't need to write a lot of configuration files
Provide production-level monitoring, health testing, and external configuration
shortcoming
The encapsulation is too deep and the internal principle is complex
Faster version iteration
Background of times
Micro-services: divide functionality into modules, deploy on multiple servers, and invoke them through http
Distributed: Micro-services involve distributed issues.
Using springboot+springcloud
To configure
Configuration process
Create a maven empty project
Configure pom.xml file
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.4.10-SNAPSHOT</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>net.xmclass</groupId> <artifactId>online_xmclass</artifactId> <version>0.0.1-SNAPSHOT</version> <name>online_xmclass</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.4</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.7.0</version> </dependency> <!--guava Dependent Packages--> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>19.0</version> </dependency> <dependency> <groupId>com.google.gcloud</groupId> <artifactId>gcloud-java-bigquery</artifactId> <version>0.1.7</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> <repository> <id>spring-snapshots</id> <name>Spring Snapshots</name> <url>https://repo.spring.io/snapshot</url> <releases> <enabled>false</enabled> </releases> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots> <enabled>false</enabled> </snapshots> </pluginRepository> <pluginRepository> <id>spring-snapshots</id> <name>Spring Snapshots</name> <url>https://repo.spring.io/snapshot</url> <releases> <enabled>false</enabled> </releases> </pluginRepository> </pluginRepositories> </project>
Main method
@SpringBootApplication public class OnlineXmclassApplication { public static void main(String[] args) { SpringApplication.run(OnlineXmclassApplication.class, args); } }
Simplified configuration
application.properties - Main configuration file, no xml needed. All configurations are in this file
Write Business
test
Simplified deployment
<plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin>
Pack into jar packages Note to cancel the cmd Quick Edit mode
Dependency Management
Develop an import starter scene launcher: Scene-related dependencies are automatically introduced whenever a scene is introduced
Introduced dependencies do not require version number attention and have automatic version arbitration
Modify Version Number
Manually controlled version:
<properties> <java.version>1.8</java.version> </properties>
Or add version number version
Automatic Configuration
Automatic Configuration Features
Automatically Match tomcat
Automatically Match Spring MVC
Automatically pair common web features such as character encoding issues (with interceptors)
Default package structure
The package in which the main program resides and all subpackages below it are scanned. Instead of configuring package scanning, the main program is written at the next level of the project package.
Use @ComponentScan("com.example")
All configurations have default values
Load all the scenarios introduced by automatic configuration on demand before the scene is automatically configured
Principle of automatic configuration
Boot Load Automatic Configuration Class
@SpringBootApplication @MapperScan("net.xmclass.online_xmclass.mapper") @EnableTransactionManagement public class OnlineXmclassApplication { public static void main(String[] args) { SpringApplication.run(OnlineXmclassApplication.class, args); } }
@SpringBootApplication - Configuration Class
@EnableAutoConfiguration
1. Use getAutoConfiguration Entry (annotation Metadata); Batch import some components into the container
2. Call List configurations = getCandidateConfigurations (annotation Metadata, attributes) to get all the configuration classes that need to be imported into the container
3. Load Map <String, List > Load SpringFactories (@Nullable ClassLoader classLoader) using the factory; Get all the components
4. From META-INF/spring.factories location to load a file.
Default scan all META-INF/spring in our current system. Files in factories location
Spring-boot-autoconfigure-2.3.4. RELEASE. The jar package also contains META-INF/spring.factories
@AutoConfigurationPackage @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration {}
Include AutoConfiguration Package
@Import(AutoConfigurationPackages.Registrar.class) //Import a component into a container public @interface AutoConfigurationPackage {} //Import a series of components into a container using Registrar //Imports all components under a specified package, under which MainApplication resides.
Include @Import(AutoConfigurationImportSelector.class)
1,2,3,4 Nested Models 1,utilize getAutoConfigurationEntry(annotationMetadata);Batch import some components into the container 2,call List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes)Get all the configuration classes that need to be imported into the container 3,Use factory loading Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader);Get all the components 4,from META-INF/spring.factories Location to load a file. Default scan all in our current system META-INF/spring.factories Location file spring-boot-autoconfigure-2.3.4.RELEASE.jar There are also packages META-INF/spring.factories
Container function
@Configuration
1. Register bean instance with @bean in configuration class, default single instance
2. The configuration class itself is also a bean instance
3. Method of proxyBeanMethods proxy bean s
Full:true guarantees that the component returned by how many times the bean object has been called is a single instance, and each call will look in the IOC container for existence
Lite:false does not check whether it has been created, how many times each bean object has been called and the components returned are newly created, multi-instance
@Configuration(proxyBeanMethods = false) //Tell SpringBoot that this is a configuration class==configuration file public class MyConfig { /** * Full:Externally, regardless of how many times this component registration method is invoked in the configuration class to obtain a single instance object from a previously registered container * @return */ @Bean //Add components to the container. The id of the component is the method name. The return type is the component type. The value returned is the instance of the component in the container public User user01(){ User zhangsan = new User("zhangsan", 18); //user components depend on Pet components zhangsan.setPet(tomcatPet()); return zhangsan; } @Bean("tom") public Pet tomcatPet(){ return new Pet("tomcat"); } }
Other
@Controller @Service @Component @Respository
@Import
import(User.class,DBHelper.class)
Create bean instances of these two classes in a container
@Conditional - Conditional Assembly
Property Configuration
We know that in a project, a lot of time we need to use some configuration information, which may have different configurations in test and production environments, and may be modified later according to actual business conditions. In this case, we can not write these configurations to death in code, preferably in the configuration file.
Scenarios with a small amount of configuration information
For example, in a microservice architecture, the most common scenario is that a service needs to call another service to get information it provides. In the configuration file of the service, the address of the called service needs to be configured. For example, in the current service, we need to call an order microservice to get information about the order, assuming the port number of the order service is 8002. Then we can configure it as follows:
server: port: 8001 # Configure the address of a microservice url: # Address of order micro-service orderUrl: http://localhost:8002
How do I get this configured order service address in the business code? We can solve this with the @Value annotation. Add an attribute to the corresponding class and use the @Value annotation on the attribute to get the configuration information in the configuration file as follows:
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/test") public class ConfigController { private static final Logger LOGGER = LoggerFactory.getLogger(ConfigController.class); @Value("${url.orderUrl}") private String orderUrl; @RequestMapping("/config") public String testConfig() { LOGGER.info("=====The order service address obtained is:{}", orderUrl); return "success"; } }
The @Value annotation gives you the value corresponding to the key in the configuration file via ${key}. Let's start the project and when you type localhost:8080/test/config in your browser to request service, you can see that the console prints out the address of the order service:
Scenarios with multiple configuration information
One more problem is that as business complexity increases, there may be more and more micro-services in a project, and a module may need to call more than one micro-service to get different information, so you need to configure the addresses of multiple micro-services in a configuration file. However, in the code that calls these microservices, it would be too cumbersome and unscientific for such a microservice address to be introduced using the @Value annotation.
Therefore, in a real project, when the business is tedious and the logic is complex, you need to consider encapsulating one or more configuration classes. For example, if in the current service, a business needs to call order micro-service, user micro-service and shopping cart micro-service at the same time, get information about order, user and shopping cart respectively, and then do some logical processing on the information. Then in the configuration file, we need to configure the addresses of these microservices:
# Configure addresses for multiple microservices url: # Address of order micro-service orderUrl: http://localhost:8002 # Address of user microservice userUrl: http://localhost:8003 # Address of Shopping Cart Micro Service shoppingUrl: http://localhost:8004
@Component @ConfigurationProperties(prefix = "url") public class MicroServiceUrl { private String orderUrl; private String userUrl; private String shoppingUrl; // Omit get and set methods }
Use the @ConfigurationProperties annotation and prefix to specify a prefix, then the attribute names in this class are those in the configuration after the prefix is removed, one-to-one. That is, the prefix name + attribute name is the key defined in the configuration file. At the same time, this class needs to be annotated with @Component, put this class as a component in the Spring container, let Spring manage it, and inject it directly when we use it.
Note that using the @ConfigurationProperties annotation requires importing its dependencies
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency>
Interceptor
Content of Spring MVC
Processor interceptors for SpringMVC are similar to Filter filters in Servlet development for preprocessing and postprocessing processors. Developers can define some interceptors themselves to implement specific functions.
The difference between a filter and an interceptor:
Interceptor is a specific application of AOP thought.
Filter
Part of the servlet specification that any java web project can use
After configuring /* in url-pattern, all resources to be accessed can be intercepted
Interceptor
Interceptors are the Spring MVC framework itself, and can only be used by projects that use the Spring MVC framework
Interceptors will only intercept access to the controller methods, and will not intercept access to jsp/html/css/image/js
Interceptors in springboot are placed in ioc containers
Understand
aop proxy, with additional processing before and after the controller method, preHandle returns true as release and false as intercept
Example
Write an interceptor
package com.kuang.interceptor; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class MyInterceptor implements HandlerInterceptor { //Execute before method of request processing //If true is returned to execute the next interceptor //Do not execute the next interceptor if false is returned public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception { System.out.println("------------Pre-processing------------"); return true; } //Execute after request handling method execution public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { System.out.println("------------After treatment------------"); } //Perform cleanup after dispatcher Servlet processing. public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { System.out.println("------------Clear------------"); } }
Write a Controller to receive requests
package com.kuang.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; //Test interceptor controller @Controller public class InterceptorController { @RequestMapping("/interceptor") @ResponseBody public String testFunction() { System.out.println("The method in the controller executed"); return "hello"; } }
Interceptor Configuration
@Configuration public class IntercepterConfig implements WebMvcConfigurer { //This is equivalent to configuring bean s in a configuration file, essentially injecting LoginIntercepter objects through IOC only once @Bean LoginIntercepter loginIntercepter(){ return new LoginIntercepter(); } @Bean CorsIntercepter corsIntercepter() {return new CorsIntercepter();} @Override public void addInterceptors(InterceptorRegistry registry) { //Intercept all paths, this cross-domain configuration is on top registry.addInterceptor(corsIntercepter()).addPathPatterns("/**"); registry.addInterceptor(loginIntercepter()).addPathPatterns("/api/v1/pri/*/*/**") //Do not block which paths, note to start with/ .excludePathPatterns("/api/v1/pri/user/login","/api/v1/pri/user/register"); WebMvcConfigurer.super.addInterceptors(registry); } }
excludePathPatterns Unblocked Path (controller s method)
Path intercepted by addPathPatterns (controller s method)