Spring Bootadvanced features

LearningSpring Boot advanced features, includingasynchronousprogramming, event驱动, cache and 国际化etc.

1. asynchronousprogramming

Spring Bootproviding了asynchronousprogrammingsupport, 可以improvingapplication concurrentprocessingcapacity.

1.1 configurationasynchronoussupport

in 主class or configurationclass on 添加@EnableAsync注解启用asynchronoussupport:

@SpringBootApplication
@EnableAsync
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

1.2 using@Async注解

in method on 添加@Async注解, 使methodasynchronous执行:

@Service
public class AsyncService {
    
    @Async
    public CompletableFuture<String> asyncMethod() {
        //  long 时间run task
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        return CompletableFuture.completedFuture("asynchronoustaskcompletion");
    }
}

1.3 asynchronousmethod调用

in 控制器in调用asynchronousmethod:

@RestController
public class AsyncController {
    
    @Autowired
    private AsyncService asyncService;
    
    @GetMapping("/async")
    public CompletableFuture<String> asyncCall() {
        return asyncService.asyncMethod();
    }
}

2. event驱动programming

Spring Bootsupportevent驱动programming, 允许component之间througheventfor松耦合通信.

2.1 自定义event

creation自定义eventclass, inheritanceApplicationEvent:

public class CustomEvent extends ApplicationEvent {
    
    private String message;
    
    public CustomEvent(Object source, String message) {
        super(source);
        this.message = message;
    }
    
    public String getMessage() {
        return message;
    }
}

2.2 eventrelease者

usingApplicationEventPublisherreleaseevent:

@Service
public class EventPublisher {
    
    @Autowired
    private ApplicationEventPublisher publisher;
    
    public void publishEvent(String message) {
        publisher.publishEvent(new CustomEvent(this, message));
    }
}

2.3 event监听器

using@EventListener注解监听event:

@Service
public class EventListener {
    
    @EventListener
    public void handleCustomEvent(CustomEvent event) {
        System.out.println("收 to event: " + event.getMessage());
    }
}

3. cachemechanism

Spring Bootproviding了cacheabstraction, support many 种cacheimplementation, such asEhCache, Redis, Caffeineetc..

3.1 configurationcachesupport

添加cache依赖并启用cache:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>

<!-- such as果usingRedisserving ascache, 添加Redis依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

in 主class or configurationclass on 添加@EnableCaching注解:

@SpringBootApplication
@EnableCaching
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

3.2 usingcache注解

in method on usingcache注解:

@Service
public class CacheService {
    
    @Cacheable(value = "items", key = "#id")
    public Item getItemById(Long id) {
        //  from datalibraryquerydata
        return itemRepository.findById(id).orElse(null);
    }
    
    @CachePut(value = "items", key = "#item.id")
    public Item saveItem(Item item) {
        // 保存data to datalibrary
        return itemRepository.save(item);
    }
    
    @CacheEvict(value = "items", key = "#id")
    public void deleteItem(Long id) {
        //  from datalibrarydeletedata
        itemRepository.deleteById(id);
    }
    
    @CacheEvict(value = "items", allEntries = true)
    public void clearCache() {
        // 清空所 has cache
    }
}

4. 国际化support

Spring Bootsupport国际化, 可以根据user languageenvironment显示不同 message.

4.1 configuration国际化

in application.propertiesinconfiguration国际化:

# 默认language
spring.messages.basename=i18n/messages
# support languagelist
spring.messages.encoding=UTF-8
# cache时间 (秒) , -1表示不cache
spring.messages.cache-duration=-1

4.2 creation国际化resourcefile

in src/main/resources/i18nTable of Contents under creationresourcefile:

  • messages.properties (默认)
  • messages_zh_CN.properties (in文)
  • messages_en_US.properties (英文)

4.3 using国际化message

in 控制器inusingMessageSource获取国际化message:

@Controller
public class I18nController {
    
    @Autowired
    private MessageSource messageSource;
    
    @GetMapping("/i18n")
    @ResponseBody
    public String i18n(HttpServletRequest request) {
        Locale locale = request.getLocale();
        return messageSource.getMessage("welcome", null, locale);
    }
}

4.4 in Thymeleafinusing国际化

in Thymeleaf模板inusing国际化:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>国际化example</title>
</head>
<body>
    <h1 th:text="#{welcome}">Welcome</h1>
</body>
</html>

5. WebSocketsupport

Spring Bootproviding了WebSocketsupport, 可以implementation实时双向通信.

5.1 添加WebSocket依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

5.2 configurationWebSocket

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerconfigurationr {
    
    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        // 启用 simple  messageproxy
        registry.enableSimpleBroker("/topic");
        // application程序目 地 before 缀
        registry.setApplicationDestinationPrefixes("/app");
    }
    
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        // registerSTOMP端点, 允许usingSockJS客户端
        registry.addEndpoint("/ws").withSockJS();
    }
}

5.3 creationWebSocket控制器

@Controller
public class WebSocketController {
    
    @MessageMapping("/chat")
    @SendTo("/topic/messages")
    public ChatMessage sendMessage(ChatMessage message) {
        return message;
    }
    
    @MessageMapping("/join")
    @SendTo("/topic/users")
    public ChatMessage addUser(@Payload ChatMessage message, 
                               SimpMessageHeaderAccessor headerAccessor) {
        // 将user名添加 to WebSocketsession
        headerAccessor.getSessionAttributes().put("username", message.getSender());
        return message;
    }
}

6. 自定义Starter

Spring Boot Starter is 一组预configuration 依赖, 我们可以creation自己 Starter.

6.1 creationStarterprojectstructure

my-starter/       # project根Table of Contents
├── src/          # sourcescodeTable of Contents
│   ├── main/     # 主codeTable of Contents
│   │   ├── java/ # Javasourcescode
│   │   │   └── com/example/mystarter/ # packageTable of Contents
│   │   │       ├── autoconfigure/ # 自动configurationTable of Contents
│   │   │       │   ├── MyStarterAutoConfiguration.java # 自动configurationclass
│   │   │       │   └── MyStarterProperties.java # configurationpropertyclass
│   │   │       └── service/ # serviceTable of Contents
│   │   │           └── MyStarterService.java # serviceclass
│   │   └── resources/ # resourcefile
│   │       └── META-INF/ # META-INFTable of Contents
│   │           └── spring.factories # Spring Boot自动configurationfile
│   └── test/     # testcodeTable of Contents
└── pom.xml       # Mavenconfigurationfile

6.2 creationconfigurationpropertyclass

@ConfigurationProperties(prefix = "my.starter")
public class MyStarterProperties {
    
    private String name = "default";
    private boolean enabled = true;
    
    // getter and settermethod
}

6.3 creation自动configurationclass

@Configuration
@ConditionalOnClass(MyStarterService.class)
@EnableConfigurationProperties(MyStarterProperties.class)
public class MyStarterAutoConfiguration {
    
    private final MyStarterProperties properties;
    
    public MyStarterAutoConfiguration(MyStarterProperties properties) {
        this.properties = properties;
    }
    
    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnProperty(prefix = "my.starter", name = "enabled", havingValue = "true")
    public MyStarterService myStarterService() {
        return new MyStarterService(properties);
    }
}

6.4 creationserviceclass

public class MyStarterService {
    
    private final MyStarterProperties properties;
    
    public MyStarterService(MyStarterProperties properties) {
        this.properties = properties;
    }
    
    public String getMessage() {
        return "Hello, " + properties.getName() + "!";
    }
}

6.5 configurationspring.factories

in META-INF/spring.factoriesfilein添加自动configurationclass:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=
com.example.mystarter.autoconfigure.MyStarterAutoConfiguration

7. 条件化configuration

Spring Bootproviding了 many 种条件注解, 可以根据不同条件configurationBean.

7.1 常用条件注解

  • @ConditionalOnClass: 当classpath on 存 in 指定class时生效
  • @ConditionalOnMissingClass: 当classpath on 不存 in 指定class时生效
  • @ConditionalOnBean: 当Springcontainersin存 in 指定Bean时生效
  • @ConditionalOnMissingBean: 当Springcontainersin不存 in 指定Bean时生效
  • @ConditionalOnProperty: 当指定property存 in 且值匹配时生效
  • @ConditionalOnResource: 当指定resource存 in 时生效
  • @ConditionalOnWebApplication: 当application is Webapplication时生效
  • @ConditionalOnNotWebApplication: 当application不 is Webapplication时生效

7.2 using条件注解

@Configuration
public class ConditionalConfig {
    
    @Bean
    @ConditionalOnProperty(prefix = "my.service", name = "enabled", havingValue = "true")
    public MyService myService() {
        return new MyService();
    }
    
    @Bean
    @ConditionalOnMissingBean(MyService.class)
    public DefaultMyService defaultMyService() {
        return new DefaultMyService();
    }
    
    @Bean
    @ConditionalOnClass(name = "org.apache.commons.lang3.StringUtils")
    public EnhancedService enhancedService() {
        return new EnhancedService();
    }
}

8. response式programming

Spring Bootsupportresponse式programming, 可以usingSpring WebFluxcreationresponse式Webapplication.

8.1 添加WebFlux依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

8.2 creationresponse式控制器

@RestController
public class ReactiveController {
    
    @GetMapping("/reactive")
    public Flux<String> reactive() {
        return Flux.just("Hello", "World")
                   .delayElements(Duration.ofSeconds(1))
                   .doOnNext(System.out::println);
    }
    
    @GetMapping("/mono")
    public Mono<String> mono() {
        return Mono.just("Hello World")
                   .delayElement(Duration.ofSeconds(1));
    }
}

8.3 response式data访问

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
</dependency>
@Repository
public interface ReactiveItemRepository extends ReactiveMongoRepository<Item, String> {
    Flux<Item> findByCategory(String category);
    Mono<Item> findByName(String name);
}