SpringBoot automatic assembly principle & custom starter
Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.
Principle of Springboot automatic assembly
Learning Springboot, adhering to not only do the framework of the porter, it is best to understand how the framework is running, convenient to become a better porter……
In the main application entry we can see an annotation == @springBootApplication ==. The core three annotations of this annotation are:
- @ComponentScan — Scanning components & automatic assembly
- @springBootConfiguration – Inherits the @Configuration annotation and loads the Configuration file
- EnableAutoConfiguration – This is the core annotation for autowiring
The process of automatic assembly
Take a look at the @enableAutoConfiguration annotation. Idea can be entered by holding down ==Ctrl+ mouse click ==. After entering can see there is a note – > = = @ Import = = ({AutoConfigurationImportSelector. Class})This annotation will import AutoConfigurationImportSelector. Class, we continue to see selectImports () methodThe method scans == meta-INF /spring.factories== files that are stored in key-value pairs.
And one of the key = org. Springframework. Boot. Autoconfigure. EnableAutoConfiguration value value can be set with the automatic configuration class with the same effect. If you open any autoconfigure JAR, you can see the meta-INF/Spring.Factories with the same structure.
Key = org. Springframework. Boot. Autoconfigure. EnableAutoConfiguration corresponds to the value of the configuration of the class naming rule is: XxxAutoConfiguration. These autoConfigurations have multiple annotations, some of which indicate when the Settings take effect. One of the = = @ EnableConfigurationProperties ({DataSourceProperties. Class}) = = can assemble some xxxProperties class, These xxxProperties classes are annotated ==@ConfigurationProperties== and function to get the properties of the main configuration file, bind the corresponding elements, and wrap them into beans for import into the Spring container
conclusion
Here is a summary of the principle of automatic assembly (process) :
- Find spring.Factories in the meta-INF directory using the @enableAutoConfiguration annotation
- Load the xxxAutoConfiguration class set up in Spring. factories.
- Automatic assembly class = = @ ConditionalOnXXX = = to Settings to take effect, and some starter to automatic assembly through @ EnableConfigurationPropertie xxxProperties
The xxxProperties class has an annotation ==@ConfigurationProperties==, which reads the global configuration file and automatically binds to the corresponding propertiesThe @configurationProperties (prefix = “spring.cache”) attribute is a configuration file with a spring.cache prefix. If you set spring.cache.type= XXX in the global configuration file, it will be bound to type. 5. Complete auto assembly!
Hand lift a starter
Now that you know how to automate the starter, let’s write a starter!
Follow me through, you may encounter problems along the way, but when you encounter problems, you will better understand the underlying implementation.
The initial step
- Create an empty project
2. Create two new Modules (Maven & Spring Initalizr)
Note the naming rules here, when we name artifac: XXX — spring-boot-starter –> (Maven module name), XXX — spring-boot-autoconfigure –> (SpringBoot module name), XXX — spring-boot-autoconfigure –> (SpringBoot module name), XXX — spring-boot-autoconfigure –> (SpringBoot module name) But do not conform to the agreement of the operation, it is recommended to follow the agreement!
XXX refers to your own name, such as mybatis is: mybatis-spring-boot-starter
XXX – spring – the boot – starter to write
XML == add our ==xxx-spring-boot-configure== dependency.
Pom. XML:
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.zzt.starter</groupId>
<artifactId>zzt001-spring-boot-starter</artifactId>
<version>1.0 the SNAPSHOT</version>
<! -- Initiator: introduce automatic configuration module -->
<dependencies>
<dependency>
<groupId>com.zzt.starter</groupId>
<artifactId>zzt001-spring-boot-starter-autoconfigurer</artifactId>
<version>0.0.1 - the SNAPSHOT</version>
</dependency>
</dependencies>
</project>
Copy the code
If you don’t know how to fill in the dependency, just go to the ==xxx-spring-boot-configure== pum. XML and look for the copy paste:
XXX – spring – the boot – configurater writing
The steps are as follows:
- Delete the main program ==XXXSpringBootApplication== and ==pox. XML build configuration == and ==test directory ==, ++ only keep the most basic start ++
Pom. XML:
<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.2.7. RELEASE</version>
<relativePath/> <! -- lookup parent from repository -->
</parent>
<groupId>com.zzt.starter</groupId>
<artifactId>zzt001-spring-boot-starter-autoconfigurer</artifactId>
<version>0.0.1 - the SNAPSHOT</version>
<name>zzt001-spring-boot-starter-autoconfigurer</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<! -- Just introduce the basic starter-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<! Spring Boot Configuration Annotation Proessor not found in classpath -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>2.2.2. RELEASE</version>
</dependency>
</dependencies>
</project>
Copy the code
We may be prompted later when we use ==@ConfigurationProperties==
Spring Boot Configuration Annotation Proessor not found in classpath
Copy the code
Add one more dependency, see pom.xml above.
- Write xxxAutoConfiguration & xxxService & xxxProperties
In this case my XXX is Person
Write PersonProperties first:
package com.zzt.starter;* Reprint please state the author */
import org.springframework.boot.context.properties.ConfigurationProperties;
// The following annotations are useful for future use of our starter
// You can set zzt.first.info= the value you want to write to in application.properties
@ConfigurationProperties(prefix = "zzt.first")
public class PersonProperties {
private String info;/ / info corresponding to ZZT. First. Info
public String getInfo(a) {
return info;
}
public void setInfo(String info) {
this.info = info; }}Copy the code
Next, write the PersonService class:
package com.zzt.starter;* Reprint please state the author */
import org.springframework.stereotype.Service;
public class PersonService {
PersonProperties personProperties;
public PersonProperties getPersonProperties(a) {
return personProperties;
}
public void setPersonProperties(PersonProperties personProperties) {
this.personProperties = personProperties;
}
public void say(String info){
System.out.println("Diy Starter---- configuration information -----info:"+personProperties.getInfo());
System.out.println("Passed info:"+info); }}Copy the code
Finally write the PersonAutoConfiguration class:
package com.zzt.starter;* Reprint please state the author */
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConditionalOnWebApplication // The Settings take effect in the Web application
@EnableConfigurationProperties(PersonProperties.class)
public class PersonAutoConfiguration {
@Autowired
PersonProperties personProperties;
@Bean
public PersonService personService(a){
PersonService personService=new PersonService();
personService.setPersonProperties(personProperties);
returnpersonService; }}Copy the code
- “> < resources== META-INF==” factories== spring.factories==” If you find that automatic injection is not possible for later use, consider whether there is an error
Set up the object to load in spring.factories:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.zzt.starter.PersonAutoConfiguration
Copy the code
After the two modules above are written, the directory will look something like this
Yellow is where the OR is created!
Packaging project
Once you’ve written it, package it to your Maven repository. Pay attention to the order in which you package it! Package xxx-spring-boot-configure and xxx-spring-boot-starter
Package like a normal Maven project
Practical use
Create a Springboot, select web, in fact also can not choose but I wrote in the automatic configuration class = = = = @ ConditionalOnWebApplication, so choose web, main use is feel so good observation
- Write your own controller
package com.zzt.dicengspringboot.Controller;* Reprint please state the author */
import com.zzt.starter.PersonService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class PersonController {
@Autowired
private PersonService personService;
@RequestMapping("/person")
public String person(a){
System.out.println("Accessed person");
this.personService.say("ok!");
return "Go back to your IDE and see if the output works!"; }}Copy the code
- Set the info value in application.properties
# configure your starter's Settings zzt.first.info=successCopy the code
- To start the project, type localhost:8080/person for access
You will see output on the Console:Output correct!
- After compiling, the project catalog is as follows (yellow is to be modified and filled in) :
Some errors you might encounter
- Controller is in the wrong location, so we can’t access localhost:8080/person
- Cannot scan PersonService, cannot @autowired
The solution is to add a scan, see the comment for an example:
package com.zzt.dicengspringboot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
// @componentScan ({"com.zzt.starter"}
//@ComponentScan({"com.zzt.dicengspringboot.Controller"})
// If the level of the directory is not set correctly, it may not be able to scan
public class DicengSpringBootApplication {
public static void main(String[] args) { SpringApplication.run(DicengSpringBootApplication.class, args); }}Copy the code
There you have it, starter!
If you have any questions, please feel free to communicate with us.