匿名函数托管 func-spring-boot-starter

2022年01月16日 阅读数:3
这篇文章主要向大家介绍匿名函数托管 func-spring-boot-starter,主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

匿名函数托管 func-spring-boot-starter

项目地址html

func-spring-boot-starter开源项目地址: https://gitee.com/yiur/func-spring-boot-starter
func-web-simple开源项目地址: https://gitee.com/yiur/func-web-simplejava

项目搭建

项目树结构git

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

pomweb

<?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>

yamlspring

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")apache

扫描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 获取匿名函数连接生产工厂api

@Configuration
public class FuncLinkConfig {

    @Autowired
    public FuncFactory funcFactory;

}

生成匿名函数连接tomcat

@Bean
public FuncLink funcLink() {
    return funcFactory.build();
}

配置匿名函数连接生命状态bash

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: 匿名函数绑定的回调函数类 不推荐
  • @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