# spring-boot-starter-awesome-annotation
**Repository Path**: kepler_wang/spring-boot-starter-awesome-annotation
## Basic Information
- **Project Name**: spring-boot-starter-awesome-annotation
- **Description**: 基于springboot的自定义注解库,如需要请联系15901296447(同微信),邮箱kai15901296447@163.com
- **Primary Language**: Java
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2021-10-28
- **Last Updated**: 2022-05-11
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
## 1.功能说明
利用AOP与Agent进行架构解耦,逻辑重复利用,目前提供的功能有:
1. FTP/SFTP扫描文件功能
2. Agent无感知修正目标服务逻辑
3. 线程操作不同种类对象,不同对象有序,相同对象并行
待添加功能:
1. 对称Socket Agent 单项端口通讯
如有问题请联系 15901296447
## 2.添加依赖
```
com.gitee.awesome.annotation
spring-boot-starter-awesome-annotation
1.0-SNAPSHOT
```
## 3.快速开始
### 1.FTP/SFTP扫描文件功能
根据自定义逻辑,按照固定频率,检查指定FTP/SFTP地址下的文件名称,根据自定义逻辑决定文件名是否符合要求
#### 1.项目启动类 扫描配置添加包路径
```
@SpringBootApplication(scanBasePackages = {"com.springframework.boot.awesome.annotation"})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
```
#### 2.使用注解
```
@Component
public class MonitorTest {
@MonitorFTPFile(
url = "ftp://kepler:kepler@127.0.0.1:21/home/otms/jt/kepler",
millisecondsFrequency = 10000,
millisecondsTimeout = 60000,
monitorClassPackage = "xxx.xxx.xxx",
exceptionHandlerClassPackage = "xxx.xxx.xxx"
)
public void monitorTest(){
System.out.println("扫描文件结束");
}
}
```
参数说明:
1. url: 标准FTP字符串,格式:ftp(sftp)://{用户名}:{密码}@{IP地址}:{端口}{扫描的绝对路径}
2. millisecondsFrequency: 扫描周期,单位毫秒,范围:0 - 10 * 60 * 1000 (最长5分钟)
3. millisecondsTimeout:扫描超时时间,单位毫秒,范围:0 - 2 * 60 * 60 * 1000 (最长2小时)
4. monitorClassPackage: 扫描实现类全路径, 需要实现MonitorFTPFileInterface接口
5. exceptionHandlerClassPackage: 异常处理类全路径,需要实现MonitorFTPFileExceptionHandler接口 非必须
#### 3.扫描实现
```
public class MonitorTest implements MonitorFTPFileInterface {
@Override
public boolean monitorFile(List list) {
for(String s : list){
System.out.println("目前FTP目录文件名: " + s);
if(s.equals("demo.txt")){
return true;
}
}
return false;
}
}
```
扫描逻辑,如果找到符合要求的文件列表,返回true,否则返回false,扫描类需要实现MonitorFTPFileInterface接口
#### 4.异常处理实现
```
public class MonitorHandleExceptionTest implements MonitorFTPFileExceptionHandler {
@Override
public void handleFTPUrlIllegalException(FTPUrlIllegalException e) {}
@Override
public void handleMonitorClassNotFoundException(MonitorClassNotFoundException e) {}
@Override
public void handleMonitorClassNotImplementException(MonitorClassNotImplementException e) {}
@Override
public void handleInterruptedException(InterruptedException e) {}
@Override
public void handleTimeoutException(TimeoutException e) {}
@Override
public void handleClassNotFoundException(ClassNotFoundException e) {}
@Override
public void handleIllegalAccessException(IllegalAccessException e) {}
@Override
public void handleInstantiationException(InstantiationException e) {}
@Override
public void handleInvocationTargetException(InvocationTargetException e) {}
@Override
public void handleIPErrorException(IPErrorException e) {}
@Override
public void handleJSchException(JSchException e) {}
@Override
public void handleIOException(IOException e) {}
@Override
public void handleFTPCloseErrorException(FTPCloseErrorException e) {}
@Override
public void handleUserNameOrPasswordErrorException(UserNameOrPasswordErrorException e) {}
@Override
public void handleSftpException(SftpException e) {}
@Override
public void handlePortErrorException(PortErrorException e) {}
@Override
public void handleFrequencyLimitException(FrequencyLimitException e) {}
@Override
public void handleTimeoutLimitException(TimeoutLimitException e) {}
}
```
异常处理类可以不进行配置,非必须,如果进行配置则需要实现MonitorFTPFileExceptionHandler接口;如果未配置则异常直接抛出
### 2.Agent无感知修正目标服务逻辑
java Agent修改目标代码逻辑,对方无感知,以修改目标方法入参为例
#### 1.构建Agent逻辑
```
public static void premain(String options, Instrumentation instrumentation){
instrumentation.addTransformer(new AgentClassFileTransformer(
"com/springframework/boot/awesome/annotation/Business",
"doSomeThing",
"java.lang.String,java.lang.String",
"$1 = com.agent.test.NewClass.newClassMethodChangeValue($1);",
AgentType.BEFORE
));
}
```
参数说明:
1. targetClassPackage 目标类全名,以"/"代替"."分隔
2. targetClassMethod 目标类方法
3. targetClassMethodParams 目标类方法入参类型全名,以","逗号分隔
4. agentCode 切入代码 ("$1"可以取到目标方法第一个入参,以此类推), 示例为修正目标方法第一个入参
5. agentLocation 切入位置 before代表在目标方法前执行, after代表在目标方法后执行
#### 2.构建切入目标的方法
```
public class NewClass {
public static String newClassMethodChangeValue(String s){
System.out.println("旧值: " + s);
s = "kepler";
System.out.println("新值: " + s);
return s;
}
}
```
#### 3.目标代码示例
```
public class Application {
public static void main(String[] args) {
new Business().doSomeThing("a", "b");
}
}
```
#### 4.执行指令
```
java -javaagent:./{agent包名}.jar -jar {目标服务包名}.jar
```
#### 5.架构原理说明
通过javassist动态修改目标服务字节码. 通过-javaagent参数进行执行,动态修正原逻辑代码
javassist依赖版本
```
org.javassist
javassist
3.25.0-GA
```
#### 6.其他使用示例
在方法执行前插入代码
```
doSomeThing.insertBefore("System.out.println(\"doSomeThing.insertBefore\");");
```
在方法执行后插入代码
```
doSomeThing.insertAfter("System.out.println(\"doSomeThing.insertAfter\");");
```
定义一个新类方法并切入目标前运行
```
doSomeThing.insertBefore("com.springframework.boot.awesome.annotation.agent.NewClass().newClassStaticMethod();");
```
定义一个新类方法并切入目标后运行
```
doSomeThing.insertAfter("new com.springframework.boot.awesome.annotation.agent.NewClass().newClassMethod();");
```
更改目标方法入参 按照代码执行顺序,添加织入代码
```
doSomeThing.insertBefore("" +
"System.out.println($1); " +
"System.out.println($2); " +
"$1=\"cccc\"; " +
"$2=\"dddd\"; " +
"System.out.println($1); " +
"System.out.println($2); "
);
```
更改目标方法入参, 实现通过织入方法实现
```
doSomeThing.insertBefore("$1 = com.springframework.boot.awesome.annotation.agent.NewClass.newClassMethodChangeValue($1);");
```
### 3.线程操作不同种类对象,不同对象有序,相同对象并行
注解控制线程操作对象的顺序,与执行顺序
#### 1.项目启动类 扫描配置添加包路径
```
@SpringBootApplication(scanBasePackages = {"com.springframework.boot.awesome.annotation"})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
```
#### 2.使用注解
```
@Component
public class FlowTest {
@FlowExecute(
flowExecuteClassPackageArgs = {"xxx.xxx.xxx", "yyy.yyy.yyy"},
flowExecuteThreadCountArgs = {2, 3},
flowExecuteThreadNameTemplate = {"flow-execute-thread-name-1", "flow-execute-thread-name-2"}
)
public void flowExecuteTest(){
System.out.println("执行文件结束");
}
}
```
参数说明:
1. flowExecuteClassPackageArgs: 需要顺序执行的类,按照数组下标从0开始执行,需要实现FlowExecuteInterface接口
2. flowExecuteThreadCountArgs: 每个需要执行类的线程执行数,按照下标从0与flowExecuteClassPackageArgs参数对应
3. flowExecuteThreadNameTemplate: 每个执行类的线程名称,按照下标从0与flowExecuteClassPackageArgs参数对应
#### 3.执行逻辑实现
```
public class FlowExecuteTest implements FlowExecuteInterface {
@Override
public boolean execute() {
System.out.println("执行逻辑");
// return true;
return false;
}
}
```