Conception de votre propre Starter
Un starter complet pour Spring Boot peut inclure les éléments suivants :
- Module d'autoconfiguration : contient le code nécessaire à la configuration automatique.
- Module starter : fournit les dépandances nécessaires, y compris celles du module d'autoconfiguration.
Si ces deux concepts ne sont pas distincts dans votre projet, ils peuvent être combinés en un seul module.
En résumé, un starter doit offrir tout ce qui est requis pour utiliser une bibliothèque spécifique.
1.1. Nommage
- Le nom du module ne doit pas commencer par spring-boot.
- Si des clés de configuration sont fournies, elles doivent avoir un espace de noms unique et ne pas entrer en conflit avec ceux utilisés par Spring Boot (par exemple, server, management, etc.).
Par exemple, si vous créez un starter pour "acme", l'autoconfigure pourrait être nommé acme-spring-boot-autoconfig, et le starter acme-spring-boot-starter.
1.2. Module d'autoconfiguration
Il est recommandé d'inclure cette dépendance dans le module d'autoconfiguration :
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfig-proc</artifactId>
<optional>true</optional>
</dependency>
1.3. Module starter
Le starter est essentiellement un fichier jar vide dont le but est de gérer les dépendances requises.
Votre starter doit référencer directement ou indirectement le starter central de Spring Boot (spring-boot-starter).
2. Exemple Hello Starter
Voici comment créer un exemple de "Hello World" avec Spring Boot.
2.1. hello-spring-boot-autoconfig
Créons un projet Maven appelé hello-spring-boot-autoconfig.
pom.xml
<?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 http://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.1.5.RELEASE</version>
</parent>
<groupId>com.exmpl</groupId>
<artifactId>hello-spring-boot-autoconfig</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfig</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-config-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>
GreetProps.java
package com.exmpl.greet;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("my.greet")
public class GreetProps {
private String name;
private Integer age;
private String hometown;
// Getters and Setters
}
GreetService.java
package com.exmpl.greet;
public class GreetService {
private String name;
private Integer age;
private String hometown;
public GreetService(String name, Integer age, String hometown) {
this.name = name;
this.age = age;
this.hometown = hometown;
}
public String sayHello(String name) {
return "Bonjour, " + name;
}
public String greetWorld() {
return String.format("[name=%s, age=%d, hometown=%s]", this.name, this.age, this.hometown);
}
}
GreetServiceAutoConfig.java
package com.exmpl.greet;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableConfigurationProperties(GreetProps.class)
public class GreetServiceAutoConfig {
private final GreetProps greetProps;
public GreetServiceAutoConfig(GreetProps greetProps) {
this.greetProps = greetProps;
}
@Bean
@ConditionalOnMissingBean
public GreetService greetService() {
return new GreetService(this.greetProps.getName(), this.greetProps.getAge(), this.greetProps.getHometown());
}
}
META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.exmpl.greet.GreetServiceAutoConfig
mvn clean install
2.2. hello-spring-boot-starter
Dans hello-spring-boot-starter, référez-vous au module autoconfig.
pom.xml
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.exmpl</groupId>
<artifactId>hello-spring-boot-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>com.exmpl</groupId>
<artifactId>hello-spring-boot-autoconfig</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
Utilisation du starter dans un projet demo.
2.3. demo
application.properties
my.greet.name=EtudiantCheng
my.greet.age=28
my.greet.hometown=Suizhou, Hubei
DemoCtrl.java
package com.exmpl.demo.ctrl;
import com.exmpl.greet.GreetService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/demo")
public class DemoCtrl {
private final GreetService greetService;
public DemoCtrl(GreetService greetService) {
this.greetService = greetService;
}
@GetMapping("/hello/{name}")
public String hello(@PathVariable("name") String name) {
return greetService.sayHello(name);
}
@GetMapping("/info")
public String info() {
return greetService.greetWorld();
}
}
3. Amélioration du HelloWorld
Ajoutons un service de journalisation.
3.1. hello-spring-boot-autoconfig
MyLogAnnot.java
package com.exmpl.log;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyLogAnnot {
String desc() default "";
}
MyLogInterceptor.java
package com.exmpl.log;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Slf4j
public class MyLogInterceptor extends HandlerInterceptorAdapter {
private static final ThreadLocal<Long> startTimeThreadLocal = new ThreadLocal<>();
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
MyLogAnnot myLogAnnot = method.getAnnotation(MyLogAnnot.class);
if (null != myLogAnnot) {
long startTime = System.currentTimeMillis();
startTimeThreadLocal.set(startTime);
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
MyLogAnnot myLogAnnot = method.getAnnotation(MyLogAnnot.class);
if (null != myLogAnnot) {
long startTime = startTimeThreadLocal.get();
long endTime = System.currentTimeMillis();
long expendTime = endTime - startTime;
String requestUri = request.getRequestURI();
String methodName = method.getDeclaringClass().getName() + "#" + method.getName();
String methodDesc = myLogAnnot.desc();
String parameters = JSON.toJSONString(request.getParameterMap());
log.info("\nDescription: {}\nPath: {}\nMethod: {}\nParameters: {}\nDuration: {}", methodDesc, requestUri, methodName, parameters, expendTime);
}
}
}
MyLogAutoConfig.java
package com.exmpl.log;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class MyLogAutoConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyLogInterceptor());
}
}
META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.exmpl.greet.GreetServiceAutoConfig,\
com.exmpl.log.MyLogAutoConfig
3.2. demo
ProdCtrl.java
package com.exmpl.demo.ctrl;
import com.exmpl.log.MyLogAnnot;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/prod")
public class ProdCtrl {
@MyLogAnnot(desc = "Rechercher Produits")
@GetMapping("/list")
public String list() {
System.out.println("Rechercher Produits");
return "ok";
}
@MyLogAnnot(desc = "Sauvegarder Produit")
@PostMapping("/save")
public String save(@RequestBody String productVO) {
System.out.println("Sauvegarder Produit");
return "ok";
}
@MyLogAnnot(desc = "Supprimer Produit")
@GetMapping("/delete")
public String delete(@RequestParam("productId") Long productId) {
System.out.println("Supprimer Produit");
return "ok";
}
@MyLogAnnot(desc = "Détails Produit")
@GetMapping("/detail/{productId}")
public String detail(@PathVariable("productId") Long productId) {
System.out.println("Détails Produit");
return "ok";
}
}