匿名函式託管 func-spring-boot-starter
專案地址
func-spring-boot-starter開源專案地址: https://gitee.com/yiur/func-spring-boot-starter
func-web-simple開源專案地址: https://gitee.com/yiur/func-web-simple
專案搭建
專案樹結構
func-web-simple
│ pom.xml
└─ src
└─ main
├─ java
│ └─ com
│ └─ simple
│ └─ web
│ │ FuncApplication.java
│ │
│ ├─ callback
│ │ DefaultCallback.java
│ │
│ ├─ config
│ │ FuncLinkConfig.java
│ │
│ ├─ controller
│ │ ResultController.java
│ │
│ ├─ func
│ │ HttpLink.java
│ │ OutMessage.java
│ │
│ └─ lambda
│ LambdaConfig.java
│
└─ resources
application.yml
pom
<?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.resolving.func</groupId>
<artifactId>func-web-simple</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!--core-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.9</version>
</dependency>
<!--func-->
<dependency>
<groupId>func.spring.boot</groupId>
<artifactId>func-spring-boot-starter</artifactId>
<version>1.0.4.RELEASE</version>
</dependency>
<!--boot-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.3.12.RELEASE</version>
</dependency>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.3.12.RELEASE</version>
</dependency>
<!--test-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.3.12.RELEASE</version>
</dependency>
<!--熱部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<version>2.3.12.RELEASE</version>
<optional>true</optional>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
yaml
server:
port: 7000
tomcat:
uri-encoding: utf-8
servlet:
encoding:
charset: utf-8
spring:
application:
name: func-web-simple
devtools:
restart:
enabled: true
additional-paths: src/main/java
exclude: WEB-INF/**
func:
link:
# 預設代理模式
singleton: true
# 預設開啟lambda模式
lambda: true
# 預設的callback回撥函式類
call-back: com.simple.web.callback.DefaultCallback
# logger 配置
logger:
# 預設false 不輸出日誌
enable-log: false
# 如果FuncLambda配置了turn-on-log為true的話且funcLink中沒有對應的log功能,輸出已經日誌
message: "call method --> ?{methodName}(?{parameterSource})"
配置啟動類
@EnableFuncLambda("com.simple.web.lambda")
掃描com.simple.web.lambda包下的介面
@EnableWebMvc
@EnableFuncLambda("com.simple.web.lambda")
@SpringBootApplication
public class FuncApplication {
public static void main(String[] args) {
SpringApplication.run(FuncApplication.class, args);
}
}
配置匿名函式連結
FuncFactory 獲取匿名函式連結生產工廠
@Configuration
public class FuncLinkConfig {
@Autowired
public FuncFactory funcFactory;
}
生成匿名函式連結
@Bean
public FuncLink funcLink() {
return funcFactory.build();
}
配置匿名函式連結生命狀態
setObject(key, lambda表示式) 鏈式程式設計
-
key: (Bean name 或 refs) + : + FuncToolEnum類定義的可用狀態
-
小工具:
FuncToolKey<String, FuncToolType>
用於setObject中的key -
public FuncToolKey<String, FuncToolType> funcToolKey = (bean, toolEnum) -> FuncString.format(FuncStringType.FUNC_LINK_FORMAT, bean, toolEnum);
-
funcFactory.build() .<FuncLogger>setObject(funcToolKey.splice("link-log", FuncToolType.LIFE_START_KEY), set -> "link-log => ?{methodName}");
-
-
lambda: setObject 是一個泛型方法,所以前面的泛型用於約束後面的lambda表示式
@Bean
public FuncLink funcLink() {
return funcFactory.build()
.<FuncLogger>setObject("link-log:log", set -> "link-log => ?{methodName}");
}
@Bean
public FuncLink funcLink() {
return funcFactory.build()
.<FuncCallbackThen<String, String>>setObject("outMessage:callback-then", data -> FuncString.format("[ { \"key\": \"replace\", \"value\": \"?\" } ]", data));
}
全配置
@Configuration
public class FuncLinkConfig {
@Autowired
public FuncFactory funcFactory;
/**
* tool key lambda
*/
public FuncToolKey<String, FuncToolType> funcToolKey = (bean, toolEnum) -> FuncString.format(FuncStringType.FUNC_LINK_FORMAT, bean, toolEnum);
@Bean
public FuncLink funcLink() {
FuncLink build = funcFactory.build()
.<FuncLogger>setObject("link-log:log", set -> "link-log => ?{methodName}");
setOutMessage(build);
return build;
}
private void setOutMessage(FuncLink funcLink) {
funcLink // OutMessage State of life
.<FuncLifeStart>setObject(funcToolKey.splice("outMessage", FuncToolType.LIFE_START_KEY), data -> {
if (data.size() > 1) {
data.put("message", FuncString.format("start() -> { ? }", data.get("message")));
}
return data;
})
.<FuncCallbackThen<String, String>>setObject("outMessage:callback-then", data -> FuncString.format("[ { \"key\": \"replace\", \"value\": \"?\" } ]", data))
.<FuncCallbackError<String>>setObject("outMessage:callback-error", error -> error instanceof InvocationTargetException ? ((InvocationTargetException) error).getTargetException().getMessage() : error.getMessage())
.<FuncLifeEnd<String, String>>setObject("outMessage:life-end", data -> data);
}
}
匿名函式連結的用法
life 匿名函式執行前與執行完畢
life 匿名函式執行前與執行完畢生命狀態 不推薦
@Bean
public FuncLink funcLink() {
return funcFactory.build()
.<FuncLife<String, String>>setObject("outMessage:life", new FuncLife<String, String>() {
@Override
public Map<String, Object> start(Map<String, Object> map) {
return map;
}
@Override
public String end(String data) {
return data;
}
});
}
life-start 匿名函式執行前生命狀態 推薦
@Bean
public FuncLink funcLink() {
return funcFactory.build()
.<FuncLifeStart>setObject(funcToolKey.splice("outMessage:life-start", FuncToolType.LIFE_START_KEY), data -> {
if (data.size() > 1) {
data.put("message", FuncString.format("start() -> { ? }", data.get("message")));
}
return data;
})
}
life-end 匿名函式執行完畢生命狀態 推薦
@Bean
public FuncLink funcLink() {
return funcFactory.build()
.<FuncLifeEnd<String, String>>setObject("outMessage:life-end", data -> data);
}
life-start + life-end 組合 推薦
@Bean
public FuncLink funcLink() {
return funcFactory.build()
.<FuncLifeStart>setObject(funcToolKey.splice("outMessage:life-start", FuncToolType.LIFE_START_KEY), data -> {
if (data.size() > 1) {
data.put("message", FuncString.format("start() -> { ? }", data.get("message")));
}
return data;
})
.<FuncLifeEnd<String, String>>setObject("outMessage:life-end", data -> data);
}
callback 匿名函式執行成功或失敗,回撥函式
callback 匿名函式執行成功或失敗回撥 不推薦
@Bean
public FuncLink funcLink() {
return funcFactory.build()
.<FuncCallback<String, String>>setObject("outMessage:callback", new FuncCallback<String, String>() {
@Override
public String then(String s) {
return s;
}
@Override
public String error(Exception e) {
return e.getMessage();
}
});
}
callback-then 匿名函式執行成功回撥 推薦
@Bean
public FuncLink funcLink() {
return funcFactory.build()
.<FuncCallbackThen<String, String>>setObject("outMessage:callback-then", data -> FuncString.format("[ { \"key\": \"replace\", \"value\": \"?\" } ]", data));
}
callback-error 匿名函式執行失敗回撥 推薦
@Bean
public FuncLink funcLink() {
return funcFactory.build()
.<FuncCallbackError<String>>setObject("outMessage:callback-error", error -> error instanceof InvocationTargetException ? ((InvocationTargetException) error).getTargetException().getMessage() : error.getMessage());
}
logger 匿名函式執行前輸出資訊
log 匿名函式執行前輸出資訊 1.0.4使用
@Bean
public FuncLink funcLink() {
return funcFactory.build()
.<FuncLogger>setObject("link-log:log", set -> "link-log => ?{methodName}");
}
匿名函式配置
編寫匿名函式託管的介面
-
OutMessage
-
@Component public interface OutMessage { /** * 輸出 * @param message text * @param args replace * @return string */ String out(String message, String... args); /** * 輸出 * @param message text * @return string */ String out(String message); }
-
HttpLink
-
@Component public interface HttpLink { /** * 返回關聯 * @return object */ Object link(); }
匿名函式寫法
@FuncConfiguration 匿名函式配置註解
@FuncConfiguration
public class LambdaConfig {
}
@FuncLambda 宣告為匿名函式
- 提供給匿名函式額外功能的註解為
- @FuncParameter: 匿名函式連結想呼叫到函式引數變數,必須使用
- value: 變數名,匿名函式連結收到Map<K, V>鍵值對
- @EnableLog: 匿名函式呼叫前輸出函式資訊
- @CallbackClass: 匿名函式繫結的回撥函式類 不推薦
- @FuncParameter: 匿名函式連結想呼叫到函式引數變數,必須使用
- @FuncLambda屬性解析
- classFile: 匿名函式託管的介面
- refs: 宣告一個ref,提供給匿名函式連結使用
- bean: 匿名函式託管的介面,自動裝配物件別名,可以不用預設為首字母縮寫的類名
- 特性:
- 匿名函式託管的介面方法,返回值可以不一致callback成功回撥接收的值就是匿名函式返回的值,但回撥函式返回的值必須與介面函式返回的值一致
- refs可以引用多個ref包括Bean,進行統一配置減少耦合度
@FuncLambda(classFile = OutMessage.class, refs = { "link-log" })
public String out(@FuncParameter("message") String message, @FuncParameter("args") String... args) {
return FuncString.format(message, args);
}
全配置
@FuncConfiguration
public class LambdaConfig {
@EnableLog
@FuncLambda(classFile = OutMessage.class, refs = { "link-log" })
public String out(@FuncParameter("message") String message, @FuncParameter("args") String... args) {
return FuncString.format(message, args);
}
@EnableLog
@FuncLambda(classFile = OutMessage.class, refs = { "link-log" })
public String out(@FuncParameter("message") String message) {
return FuncString.format(message + "/no");
}
@EnableLog
@CallbackClass(DefaultCallback.class)
@FuncLambda(classFile = HttpLink.class, refs = { "link-log" })
public Map<String, String> link() {
Map<String, String> map = new HashMap<>(10);
map.put("百度", "http://www.baidu.com");
map.put("BiliBili", "http://www.bilibili.com");
map.put("localhost", "http://localhost:7000");
map.put("部落格", "https://www.cnblogs.com/yiur-bgy/p/15521428.html");
return map;
}
}
WEB 測試
@RestController 編寫api
@RestController
public class ResultController {
@Autowired
public OutMessage outMessage;
@Autowired
public HttpLink httpLink;
@RequestMapping("/replace")
public String replace(String message, String... args) {
return outMessage.out(message, args);
}
@RequestMapping("/replace/no")
public String replace(String message) {
return outMessage.out(message);
}
@RequestMapping("/hello/{message}")
public String hello(@PathVariable("message") String message) {
return outMessage.out(message);
}
@RequestMapping("/httpLink")
public Object httpLink() {
return httpLink.link();
}
}
測試 api
- 測試成功回撥
- [http://localhost:7000/replace?message=hello ?&args=func-spring-boot-starter](http://localhost:7000/replace?message=hello ?&args=func-spring-boot-starter)
- 返回:[ { "key": "replace", "value": "hello func-spring-boot-starter" } ]
- 測試失敗回撥
- [http://localhost:7000/replace?message=hello ??&args=func-spring-boot-starter](http://localhost:7000/replace?message=hello ??&args=func-spring-boot-starter)
- 返回:The current parameter is inconsistent with the number of matching characters
- 其他測試
- http://localhost:7000/httpLink
- 返回:{"localhost":"http://localhost:7000","部落格":"https://www.cnblogs.com/yiur-bgy/p/15521428.html","百度":"http://www.baidu.com","BiliBili":"http://www.bilibili.com"}
- http://localhost:7000/replace/no?message=hello
- 返回:[ { "key": "replace", "value": "hello/no" } ]