# 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; } } ```