├── .github ├── FUNDING.yml └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── .gitignore ├── LICENSE ├── example ├── pom.xml └── src │ ├── main │ ├── java │ │ └── org │ │ │ └── fastlight │ │ │ └── fastaop │ │ │ └── example │ │ │ ├── AopExample.java │ │ │ └── handler │ │ │ ├── LogAccess.java │ │ │ └── LogHandler.java │ └── resources │ │ └── META-INF │ │ └── aspect │ │ └── fast.aspect.supports.txt │ └── test │ ├── java │ ├── RootClassTest.java │ └── org │ │ └── fastlight │ │ └── fastaop │ │ └── example │ │ ├── AsyncTest.java │ │ ├── CtxAsserts.java │ │ ├── CustomDefinedTest.java │ │ ├── FastCalculatorTest.java │ │ ├── GenericTest.java │ │ ├── InnerClassTest.java │ │ ├── InterfaceTest.java │ │ ├── LambdaTest.java │ │ ├── MultiAroundTest.java │ │ ├── RecursionTest.java │ │ └── SupportTest.java │ └── resources │ └── META-INF │ └── aspect │ └── fast.aspect.supports.txt ├── fastaop ├── pom.xml └── src │ └── main │ ├── java │ └── org │ │ └── fastlight │ │ └── aop │ │ ├── annotation │ │ ├── FastAspect.java │ │ ├── FastAspectAround.java │ │ ├── FastAspectVar.java │ │ └── FastNone.java │ │ ├── handler │ │ ├── FastAspectContext.java │ │ ├── FastAspectHandler.java │ │ ├── FastAspectHandlerBuilder.java │ │ ├── FastAspectSpiHandler.java │ │ └── FastAspectSpiHandlerBuilder.java │ │ ├── processor │ │ ├── AnnotationProcessor.java │ │ ├── AspectSupportTypes.java │ │ ├── FastAspectAroundProcessor.java │ │ ├── FastAspectProcessor.java │ │ └── FastAspectVarProcessor.java │ │ ├── translator │ │ ├── FastAspectAroundTranslator.java │ │ ├── FastAspectTranslator.java │ │ └── FastAspectVarTranslator.java │ │ └── util │ │ ├── BannerLogger.java │ │ └── FastAspectProperties.java │ └── resources │ └── META-INF │ └── aspect │ └── aspect.config.properties ├── fastapt ├── pom.xml └── src │ └── main │ └── java │ └── org │ └── fastlight │ └── apt │ ├── annotation │ └── FastMarkedMethod.java │ ├── model │ ├── InvokeMethodType.java │ ├── MetaAnnotation.java │ ├── MetaMethod.java │ ├── MetaParameter.java │ ├── MetaType.java │ └── compile │ │ ├── AnnotationCompile.java │ │ ├── ClassCompile.java │ │ ├── MethodCompile.java │ │ └── ParameterCompile.java │ ├── processor │ ├── BaseAnnotationProcessor.java │ ├── BaseFastProcessor.java │ └── BaseFastSpiProcessor.java │ ├── translator │ └── BaseFastTranslator.java │ └── util │ ├── FastCollections.java │ ├── FastMaps.java │ └── ReflectUtils.java ├── pom.xml ├── readme-zh.md ├── readme.md └── resource ├── Alibaba-CodeStyle.xml ├── aop-debug.sh ├── aop-dev.sh ├── install.sh └── logo.png /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: maven/Java 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: ['http://pan.sudoyc.com:7878/s/ZskW9QqCTxB439b/preview']# Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Maven template 3 | .idea/ 4 | target/ 5 | pom.xml.tag 6 | pom.xml.releaseBackup 7 | pom.xml.versionsBackup 8 | pom.xml.next 9 | release.properties 10 | dependency-reduced-pom.xml 11 | buildNumber.properties 12 | .mvn/timing.properties 13 | # https://github.com/takari/maven-wrapper#usage-without-binary-jar 14 | .mvn/wrapper/maven-wrapper.jar 15 | *.iml 16 | 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 fast-light 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /example/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | fastaop-parent 7 | org.fastlight 8 | 1.0.2-SNAPSHOT 9 | ../pom.xml 10 | 11 | 4.0.0 12 | 13 | example 14 | 15 | 16 | 8 17 | 8 18 | 19 | 20 | 21 | org.fastlight 22 | fastaop 23 | 24 | 25 | junit 26 | junit 27 | test 28 | 29 | 30 | 31 | 32 | 33 | org.apache.maven.plugins 34 | maven-assembly-plugin 35 | 2.3 36 | 37 | false 38 | 39 | jar-with-dependencies 40 | 41 | 42 | 43 | true 44 | lib/ 45 | org.fastlight.fastaop.example.AopExample 46 | 47 | 48 | 49 | 50 | 51 | make-assembly 52 | package 53 | 54 | assembly 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /example/src/main/java/org/fastlight/fastaop/example/AopExample.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.fastaop.example; 2 | 3 | import org.fastlight.aop.annotation.FastAspectVar; 4 | import org.fastlight.aop.handler.FastAspectContext; 5 | import org.fastlight.fastaop.example.handler.LogAccess; 6 | 7 | /** 8 | * 一个简单的 FastAop 调用 demo 9 | * 10 | * @author ychost@outlook.com 11 | * @date 2021-03-27 12 | */ 13 | public class AopExample { 14 | @LogAccess 15 | public static void main(String[] args) { 16 | @FastAspectVar FastAspectContext context = FastAspectContext.currentContext(); 17 | System.out.println(context.toString()); 18 | System.out.println("[FastAop Hello]"); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /example/src/main/java/org/fastlight/fastaop/example/handler/LogAccess.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.fastaop.example.handler; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Target; 5 | 6 | /** 7 | * 打印方法的调用时间 8 | * @author ychost@outlook.com 9 | * @date 2021-04-10 10 | */ 11 | @Target(ElementType.METHOD) 12 | public @interface LogAccess { 13 | } 14 | -------------------------------------------------------------------------------- /example/src/main/java/org/fastlight/fastaop/example/handler/LogHandler.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.fastaop.example.handler; 2 | 3 | import java.time.LocalDateTime; 4 | import java.time.format.DateTimeFormatter; 5 | 6 | import org.fastlight.aop.annotation.FastAspectAround; 7 | import org.fastlight.aop.handler.FastAspectContext; 8 | import org.fastlight.aop.handler.FastAspectHandler; 9 | 10 | /** 11 | * @author ychost@outlook.com 12 | * @date 2021-03-28 13 | */ 14 | @FastAspectAround(support = LogAccess.class) 15 | public class LogHandler implements FastAspectHandler { 16 | 17 | /** 18 | * 环绕模式切入方法体 19 | */ 20 | @Override 21 | public Object processAround(FastAspectContext ctx) throws Exception { 22 | String time = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); 23 | System.out.printf("[%s] -- [%s.%s]\n", time, 24 | ctx.getMetaMethod().getMetaOwner().getType().getName(), 25 | ctx.getMetaMethod().getName() 26 | ); 27 | // 调用原始方法执行 28 | return ctx.proceed(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /example/src/main/resources/META-INF/aspect/fast.aspect.supports.txt: -------------------------------------------------------------------------------- 1 | org.fastlight.fastaop.example.handler.LogAccess -------------------------------------------------------------------------------- /example/src/test/java/RootClassTest.java: -------------------------------------------------------------------------------- 1 | import org.fastlight.fastaop.example.CtxAsserts; 2 | import org.fastlight.aop.annotation.FastAspect; 3 | import org.fastlight.aop.annotation.FastAspectVar; 4 | import org.fastlight.aop.handler.FastAspectContext; 5 | import org.junit.Test; 6 | 7 | import java.lang.reflect.Method; 8 | 9 | /** 10 | * 无 Package 的类测试 11 | * 12 | * @author ychost@outlook.com 13 | * @date 2021-03-29 14 | */ 15 | public class RootClassTest { 16 | @FastAspect 17 | @Test 18 | public void noPackage() { 19 | @FastAspectVar 20 | FastAspectContext ctx = FastAspectContext.currentContext(); 21 | Method method = new Object() {}.getClass().getEnclosingMethod(); 22 | CtxAsserts.assertEq(ctx, RootClassTest.class, method); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /example/src/test/java/org/fastlight/fastaop/example/AsyncTest.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.fastaop.example; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Target; 5 | import java.util.concurrent.ExecutionException; 6 | import java.util.concurrent.ExecutorService; 7 | import java.util.concurrent.Executors; 8 | import java.util.concurrent.Future; 9 | import java.util.concurrent.FutureTask; 10 | import java.util.concurrent.TimeUnit; 11 | import java.util.concurrent.TimeoutException; 12 | 13 | import org.fastlight.aop.annotation.FastAspect; 14 | import org.fastlight.aop.annotation.FastAspectAround; 15 | import org.fastlight.aop.handler.FastAspectContext; 16 | import org.fastlight.aop.handler.FastAspectHandler; 17 | import org.fastlight.apt.model.MetaMethod; 18 | import org.junit.Assert; 19 | import org.junit.Test; 20 | 21 | /** 22 | * @author ychost@outlook.com 23 | * @date 2021-04-06 24 | */ 25 | @FastAspect 26 | public class AsyncTest { 27 | @Test 28 | public void test() throws ExecutionException, InterruptedException { 29 | doAsync(); 30 | doInMainThread(); 31 | Future future = getFuture(); 32 | String str = future.get(); 33 | Assert.assertEquals("hello", str); 34 | assertMainThread(true); 35 | } 36 | 37 | @Async 38 | public Future getFuture() { 39 | assertMainThread(false); 40 | return new AsyncResult<>("hello"); 41 | } 42 | 43 | @Async 44 | public void doAsync() { 45 | // 判断线程 46 | assertMainThread(false); 47 | } 48 | 49 | public void doInMainThread() { 50 | assertMainThread(true); 51 | } 52 | 53 | void assertMainThread(boolean isMainThread) { 54 | Assert.assertEquals(isMainThread, Thread.currentThread().getName().contains("main")); 55 | } 56 | 57 | /** 58 | * 异步注解 59 | */ 60 | @Target(ElementType.METHOD) 61 | public static @interface Async { 62 | 63 | } 64 | 65 | @FastAspectAround 66 | public static class AsyncHandler implements FastAspectHandler { 67 | 68 | private static final ExecutorService EXECUTOR_SERVICE = Executors.newFixedThreadPool(8); 69 | 70 | @Override 71 | public boolean support(MetaMethod metaMethod) { 72 | return metaMethod.isAnnotated(Async.class); 73 | } 74 | 75 | /** 76 | * 模仿 Spring 的 Async 写的 77 | */ 78 | @Override 79 | public Object processAround(FastAspectContext ctx) throws Exception { 80 | if (Future.class.isAssignableFrom(ctx.getMetaMethod().getReturnType())) { 81 | FutureTask futureTask = new FutureTask<>(() -> ((Future)ctx.proceed()).get()); 82 | EXECUTOR_SERVICE.execute(futureTask); 83 | return futureTask; 84 | } else { 85 | EXECUTOR_SERVICE.execute(ctx::invoke); 86 | return null; 87 | } 88 | } 89 | } 90 | 91 | public static class AsyncResult implements Future { 92 | private Object result = null; 93 | 94 | public AsyncResult(Object data) { 95 | result = data; 96 | } 97 | 98 | @Override 99 | public boolean cancel(boolean mayInterruptIfRunning) { 100 | return false; 101 | } 102 | 103 | @Override 104 | public boolean isCancelled() { 105 | return false; 106 | } 107 | 108 | @Override 109 | public boolean isDone() { 110 | return false; 111 | } 112 | 113 | @Override 114 | public T get() throws InterruptedException, ExecutionException { 115 | return (T)result; 116 | } 117 | 118 | @Override 119 | public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { 120 | return (T)result; 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /example/src/test/java/org/fastlight/fastaop/example/CtxAsserts.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.fastaop.example; 2 | 3 | import org.fastlight.aop.handler.FastAspectContext; 4 | import org.junit.Assert; 5 | 6 | import java.lang.reflect.Method; 7 | import java.util.Arrays; 8 | import java.util.Objects; 9 | 10 | /** 11 | * @author ychost@outlook.com 12 | * @date 2021-03-30 13 | */ 14 | public class CtxAsserts { 15 | /** 16 | * ownerType,method,args 均相等 17 | */ 18 | public static void assertEq(FastAspectContext ctx, Class ownerType, String methodName, Object... args) { 19 | // 校验方法正确 20 | Method method = Arrays.stream(ownerType.getDeclaredMethods()).filter(v -> !v.isBridge()) 21 | .filter(v -> Objects.equals(methodName, v.getName())) 22 | .limit(1) 23 | .findFirst() 24 | .orElseThrow(() -> new RuntimeException("not found method " + ownerType.getName() + "." + methodName)); 25 | assertEq(ctx, ownerType, method, args); 26 | } 27 | 28 | public static void assertEq(FastAspectContext ctx, Class ownerType, Method method, Object... args) { 29 | // 静态类没有 this 30 | if (ctx.getMetaMethod().isStatic()) { 31 | Assert.assertNull(ctx.getThis()); 32 | } else { 33 | Assert.assertNotNull(ctx.getThis()); 34 | } 35 | // 对于生成的匿名类,其 ownerType 为子类 36 | Assert.assertTrue(ctx.getMetaMethod().getMetaOwner().getType().isAssignableFrom(ownerType)); 37 | Assert.assertArrayEquals(args, ctx.getArgs()); 38 | Assert.assertEquals(method, ctx.getMetaMethod().getMethod()); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /example/src/test/java/org/fastlight/fastaop/example/CustomDefinedTest.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.fastaop.example; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Target; 5 | import java.time.LocalDateTime; 6 | import java.time.format.DateTimeFormatter; 7 | 8 | import org.fastlight.aop.annotation.FastAspectAround; 9 | import org.fastlight.aop.handler.FastAspectContext; 10 | import org.fastlight.aop.handler.FastAspectHandler; 11 | import org.junit.Assert; 12 | import org.junit.Test; 13 | 14 | /** 15 | * @author ychost@outlook.com 16 | * @date 2021-04-07 17 | */ 18 | public class CustomDefinedTest { 19 | 20 | private static volatile boolean isLogged = false; 21 | 22 | @Test 23 | @LogAccess 24 | public void test() { 25 | Assert.assertTrue(isLogged); 26 | } 27 | 28 | @Target(ElementType.METHOD) 29 | public @interface LogAccess { 30 | 31 | } 32 | 33 | @FastAspectAround(support = LogAccess.class, order = 100) 34 | public static class LogAccessHandler implements FastAspectHandler { 35 | 36 | @Override 37 | public Object processAround(FastAspectContext ctx) throws Exception { 38 | Assert.assertEquals(100, getOrder()); 39 | String time = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); 40 | System.out.printf("[%s] -- %s", time, ctx.getMetaMethod().getName()); 41 | isLogged = true; 42 | return ctx.proceed(); 43 | } 44 | 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /example/src/test/java/org/fastlight/fastaop/example/FastCalculatorTest.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.fastaop.example; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Target; 5 | 6 | import org.fastlight.aop.annotation.FastAspect; 7 | import org.fastlight.aop.annotation.FastAspectAround; 8 | import org.fastlight.aop.handler.FastAspectHandler; 9 | import org.fastlight.aop.handler.FastAspectContext; 10 | import org.fastlight.apt.model.MetaMethod; 11 | import org.junit.Assert; 12 | import org.junit.Test; 13 | 14 | /** 15 | * 修复一个损坏的计算器 16 | * 17 | * @author ychost@outlook.com 18 | * @date 2021-04-02 19 | */ 20 | @FastAspect 21 | public class FastCalculatorTest { 22 | 23 | /** 24 | * 单测入口 25 | */ 26 | @Test 27 | public void calcTest() { 28 | int res = add(3, 2); 29 | Assert.assertEquals(5, res); 30 | } 31 | 32 | /** 33 | * 待修复的加法逻辑 34 | */ 35 | @CalcRepair 36 | int add(int a, int b) { 37 | throw new RuntimeException("this is a broken calculator"); 38 | } 39 | 40 | /** 41 | * 修复注解 42 | */ 43 | @Target(ElementType.METHOD) 44 | public @interface CalcRepair { 45 | } 46 | 47 | /** 48 | * 修复 calc 的切面 49 | */ 50 | @FastAspectAround(support = CalcRepair.class, order = 1) 51 | public static class CalcRepairHandler implements FastAspectHandler { 52 | 53 | @Override 54 | public Object processAround(FastAspectContext ctx) throws Exception { 55 | Assert.assertEquals(123, getOrder()); 56 | int a = (int)ctx.getArgs()[0]; 57 | int b = (int)ctx.getArgs()[1]; 58 | return a + b; 59 | } 60 | 61 | @Override 62 | public int getOrder() { 63 | return 123; 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /example/src/test/java/org/fastlight/fastaop/example/GenericTest.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.fastaop.example; 2 | 3 | import org.fastlight.aop.annotation.FastAspect; 4 | import org.fastlight.aop.annotation.FastAspectVar; 5 | import org.fastlight.aop.handler.FastAspectContext; 6 | import org.junit.Assert; 7 | import org.junit.Test; 8 | 9 | import java.lang.reflect.Method; 10 | import java.util.ArrayList; 11 | import java.util.Arrays; 12 | import java.util.List; 13 | import java.util.stream.Collectors; 14 | 15 | /** 16 | * 泛型方法测试 17 | * 18 | * @author ychost@outlook.com 19 | * @date 2021-03-30 20 | */ 21 | public class GenericTest { 22 | @Test 23 | public void bridgeTest() { 24 | Assert.assertEquals("3", new FastList().get(3)); 25 | } 26 | 27 | @FastAspect 28 | public static class FastList extends ArrayList { 29 | @Override 30 | public String get(int index) { 31 | // 泛型重载 JVM 会生成两个 get 方法,仅返回类型不一样 32 | // 通过 isBridge 可以区别 33 | @FastAspectVar FastAspectContext ctx = FastAspectContext.currentContext(); 34 | List methods = Arrays.stream(FastList.class.getDeclaredMethods()) 35 | .filter(v -> v.getName().equals("get")) 36 | .collect(Collectors.toList()); 37 | Assert.assertEquals(2, methods.size()); 38 | CtxAsserts.assertEq(ctx, FastList.class, new Object() { 39 | }.getClass().getEnclosingMethod(), index); 40 | return String.valueOf(index); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /example/src/test/java/org/fastlight/fastaop/example/InnerClassTest.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.fastaop.example; 2 | 3 | import org.fastlight.aop.annotation.FastAspect; 4 | import org.fastlight.aop.annotation.FastAspectVar; 5 | import org.fastlight.aop.handler.FastAspectContext; 6 | import org.junit.Test; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | /** 12 | * 内部类测试,含静态内部类,和动态内部类 13 | * 14 | * @author ychost@outlook.com 15 | * @date 2021-03-29 16 | */ 17 | @FastAspect 18 | public class InnerClassTest { 19 | @Test 20 | public void test() { 21 | @FastAspectVar FastAspectContext ctx = FastAspectContext.currentContext(); 22 | CtxAsserts.assertEq(ctx, InnerClassTest.class, "test"); 23 | InnerStatic innerStatic = new InnerStatic(); 24 | innerStatic.test(); 25 | innerStatic.test(new Object()); 26 | innerStatic.test(new ArrayList<>()); 27 | new InnerDynamic().test(); 28 | } 29 | 30 | @FastAspect 31 | public static class InnerStatic { 32 | public void test() { 33 | @FastAspectVar FastAspectContext ctx = FastAspectContext.currentContext(); 34 | CtxAsserts.assertEq(ctx, getClass(), new Object() { 35 | }.getClass().getEnclosingMethod() 36 | ); 37 | } 38 | 39 | /** 40 | * 重载 +1 41 | */ 42 | public void test(Object overload) { 43 | @FastAspectVar FastAspectContext ctx = FastAspectContext.currentContext(); 44 | CtxAsserts.assertEq(ctx, getClass(), new Object() { 45 | }.getClass().getEnclosingMethod(), overload 46 | ); 47 | } 48 | 49 | /** 50 | * 重载 +2 51 | */ 52 | public void test(List overload) { 53 | @FastAspectVar FastAspectContext ctx = FastAspectContext.currentContext(); 54 | CtxAsserts.assertEq(ctx, getClass(), new Object() { 55 | }.getClass().getEnclosingMethod(), overload 56 | ); 57 | } 58 | } 59 | 60 | @FastAspect 61 | public class InnerDynamic { 62 | public void test() { 63 | @FastAspectVar FastAspectContext ctx = FastAspectContext.currentContext(); 64 | CtxAsserts.assertEq(ctx, getClass(), "test"); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /example/src/test/java/org/fastlight/fastaop/example/InterfaceTest.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.fastaop.example; 2 | 3 | import org.fastlight.aop.annotation.FastAspect; 4 | import org.fastlight.aop.annotation.FastAspectVar; 5 | import org.fastlight.aop.handler.FastAspectContext; 6 | import org.junit.Test; 7 | 8 | /** 9 | * 接口测试 10 | * 11 | * @author ychost@outlook.com 12 | * @date 2021-04-01 13 | */ 14 | public class InterfaceTest { 15 | @Test 16 | public void test() { 17 | new PowerFace() {}.test(); 18 | } 19 | 20 | @FastAspect 21 | interface PowerFace { 22 | default void test() { 23 | @FastAspectVar 24 | FastAspectContext ctx = FastAspectContext.currentContext(); 25 | CtxAsserts.assertEq(ctx, getClass(), new Object() {}.getClass().getEnclosingMethod()); 26 | } 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /example/src/test/java/org/fastlight/fastaop/example/LambdaTest.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.fastaop.example; 2 | 3 | import org.fastlight.aop.annotation.FastAspect; 4 | import org.fastlight.aop.annotation.FastAspectVar; 5 | import org.fastlight.aop.handler.FastAspectContext; 6 | import org.junit.Assert; 7 | import org.junit.Test; 8 | 9 | import java.util.function.Supplier; 10 | 11 | /** 12 | * 方法含 lambda 测试 13 | * 14 | * @author ychost@outlook.com 15 | * @date 2021-03-29 16 | */ 17 | @FastAspect 18 | public class LambdaTest { 19 | 20 | @Test 21 | public void test() { 22 | String data = supply().get(); 23 | anonymousSupply().get(); 24 | } 25 | 26 | public Supplier supply() { 27 | @FastAspectVar FastAspectContext ctx = FastAspectContext.currentContext(); 28 | Assert.assertEquals(ctx.getMetaMethod().getMetaOwner().getType(), LambdaTest.class); 29 | CtxAsserts.assertEq(ctx, LambdaTest.class, "supply"); 30 | return () -> "ok"; 31 | } 32 | 33 | public Supplier anonymousSupply() { 34 | @FastAspectVar FastAspectContext ctx = FastAspectContext.currentContext(); 35 | CtxAsserts.assertEq(ctx, LambdaTest.class, "anonymousSupply"); 36 | return new Supplier() { 37 | @Override 38 | public String get() { 39 | try { 40 | // 方法内部类是不会切入的 41 | @FastAspectVar FastAspectContext ctx = FastAspectContext.currentContext(); 42 | Assert.fail(); 43 | } catch (Exception ignore) { 44 | 45 | } 46 | return null; 47 | } 48 | }; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /example/src/test/java/org/fastlight/fastaop/example/MultiAroundTest.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.fastaop.example; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Target; 5 | 6 | import org.fastlight.aop.annotation.FastAspect; 7 | import org.fastlight.aop.annotation.FastAspectAround; 8 | import org.fastlight.aop.handler.FastAspectHandler; 9 | import org.fastlight.aop.handler.FastAspectContext; 10 | import org.fastlight.apt.model.MetaMethod; 11 | import org.junit.Assert; 12 | import org.junit.Test; 13 | 14 | /** 15 | * 多个切面执行顺序测试 16 | * 17 | * @author ychost@outlook.com 18 | * @date 2021-04-02 19 | */ 20 | @FastAspect 21 | public class MultiAroundTest { 22 | @Test 23 | public void test() { 24 | Assert.assertEquals("m1", aroundTest("m1")); 25 | Assert.assertEquals("m2", aroundTest("abc")); 26 | } 27 | 28 | @MultiAround 29 | public String aroundTest(String m) { 30 | return "mmmmm"; 31 | } 32 | 33 | @Target(ElementType.METHOD) 34 | public @interface MultiAround { 35 | 36 | } 37 | 38 | @FastAspectAround 39 | public static class Around1 implements FastAspectHandler { 40 | @Override 41 | public boolean support(MetaMethod metaMethod) { 42 | return metaMethod.isAnnotated(MultiAround.class); 43 | } 44 | 45 | @Override 46 | public Object processAround(FastAspectContext ctx) throws Exception { 47 | if (!ctx.getMetaMethod().isAnnotated(MultiAround.class)) { 48 | return ctx.proceed(); 49 | } 50 | if ("m1".equals(ctx.getArgs()[0])) { 51 | return "m1"; 52 | } 53 | return ctx.proceed(); 54 | } 55 | 56 | @Override 57 | public int getOrder() { 58 | return 100; 59 | } 60 | } 61 | 62 | @FastAspectAround 63 | public static class Around2 implements FastAspectHandler { 64 | @Override 65 | public boolean support(MetaMethod metaMethod) { 66 | return metaMethod.isAnnotated(MultiAround.class); 67 | } 68 | 69 | @Override 70 | public Object processAround(FastAspectContext ctx) throws Exception { 71 | if (!ctx.getMetaMethod().isAnnotated(MultiAround.class)) { 72 | return ctx.proceed(); 73 | } 74 | return "m2"; 75 | } 76 | 77 | @Override 78 | public int getOrder() { 79 | return 101; 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /example/src/test/java/org/fastlight/fastaop/example/RecursionTest.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.fastaop.example; 2 | 3 | import java.util.concurrent.atomic.AtomicInteger; 4 | 5 | import org.fastlight.aop.annotation.FastAspectAround; 6 | import org.fastlight.aop.handler.FastAspectContext; 7 | import org.fastlight.aop.handler.FastAspectHandler; 8 | import org.junit.Assert; 9 | import org.junit.Test; 10 | 11 | /** 12 | * @author ychost@outlook.com 13 | * @date 2021-04-12 14 | */ 15 | public class RecursionTest { 16 | public static AtomicInteger times = new AtomicInteger(0); 17 | 18 | @Test 19 | public void test() { 20 | count(30); 21 | Assert.assertEquals(30, times.get()); 22 | } 23 | 24 | @TimeCount 25 | void count(int end) { 26 | if (end <= 1) { 27 | return; 28 | } 29 | count(--end); 30 | } 31 | 32 | public @interface TimeCount { 33 | 34 | } 35 | 36 | @FastAspectAround(support = TimeCount.class) 37 | public static class TimeCountHandler implements FastAspectHandler { 38 | 39 | @Override 40 | public Object processAround(FastAspectContext ctx) throws Exception { 41 | times.addAndGet(1); 42 | return ctx.proceed(); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /example/src/test/java/org/fastlight/fastaop/example/SupportTest.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.fastaop.example; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Target; 5 | import java.util.Optional; 6 | import java.util.concurrent.atomic.AtomicInteger; 7 | 8 | import org.fastlight.aop.annotation.FastAspect; 9 | import org.fastlight.aop.annotation.FastAspectAround; 10 | import org.fastlight.aop.handler.FastAspectHandler; 11 | import org.fastlight.aop.handler.FastAspectContext; 12 | import org.fastlight.apt.model.MetaAnnotation; 13 | import org.fastlight.apt.model.MetaMethod; 14 | import org.junit.Assert; 15 | import org.junit.Test; 16 | 17 | /** 18 | * @author ychost 19 | * @date 2021-04-03 20 | */ 21 | @FastAspect 22 | public class SupportTest { 23 | private static final AtomicInteger SUPPORT_TIMES = new AtomicInteger(0); 24 | 25 | @Test 26 | public void test() { 27 | support(); 28 | notSupport(); 29 | Assert.assertEquals(SUPPORT_TIMES.get(), 1); 30 | } 31 | 32 | @Support 33 | void support() { 34 | 35 | } 36 | 37 | @Support(value = false) 38 | void notSupport() { 39 | 40 | } 41 | 42 | @Target(ElementType.METHOD) 43 | public @interface Support { 44 | boolean value() default true; 45 | } 46 | 47 | @FastAspectAround 48 | public static class SupportAround implements FastAspectHandler { 49 | 50 | /* 51 | * 只会被执行一次,可提升程序效率 52 | */ 53 | @Override 54 | public boolean support(MetaMethod metaMethod) { 55 | MetaAnnotation annotation = metaMethod.getAnnotation(Support.class); 56 | return (boolean)Optional.ofNullable(annotation).map(v -> v.getValue("value")).orElse(false); 57 | } 58 | 59 | @Override 60 | public Object processAround(FastAspectContext ctx) throws Exception { 61 | SUPPORT_TIMES.addAndGet(1); 62 | return ctx.proceed(); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /example/src/test/resources/META-INF/aspect/fast.aspect.supports.txt: -------------------------------------------------------------------------------- 1 | org.fastlight.fastaop.example.CustomDefinedTest.LogAccess 2 | org.fastlight.fastaop.example.RecursionTest.TimeCount -------------------------------------------------------------------------------- /fastaop/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | fastaop-parent 7 | org.fastlight 8 | 1.0.2-SNAPSHOT 9 | ../pom.xml 10 | 11 | 4.0.0 12 | ${fast.version} 13 | 14 | fastaop 15 | 16 | fastaop 17 | java fast aop framework 18 | https://github.com/fast-light/fastaop 19 | 20 | 21 | 8 22 | 8 23 | 24 | 25 | 26 | org.fastlight 27 | fastapt 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /fastaop/src/main/java/org/fastlight/aop/annotation/FastAspect.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.aop.annotation; 2 | 3 | import org.fastlight.aop.handler.FastAspectHandlerBuilder; 4 | import org.fastlight.aop.handler.FastAspectSpiHandlerBuilder; 5 | 6 | import java.lang.annotation.*; 7 | 8 | /** 9 | * 注入切面逻辑,必须实现接口 {@link org.fastlight.aop.handler.FastAspectHandler} 10 | * 11 | * @author ychost@outlook.com 12 | * @date 2021-03-27 13 | */ 14 | @Retention(RetentionPolicy.SOURCE) 15 | @Target({ElementType.TYPE, ElementType.METHOD}) 16 | @Documented 17 | public @interface FastAspect { 18 | 19 | /** 20 | * 构造器,最好别变 21 | */ 22 | Class builder() default FastAspectSpiHandlerBuilder.class; 23 | } 24 | -------------------------------------------------------------------------------- /fastaop/src/main/java/org/fastlight/aop/annotation/FastAspectAround.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.aop.annotation; 2 | 3 | import java.lang.annotation.Annotation; 4 | import java.lang.annotation.Documented; 5 | import java.lang.annotation.ElementType; 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.RetentionPolicy; 8 | import java.lang.annotation.Target; 9 | 10 | import org.fastlight.aop.handler.FastAspectHandler; 11 | 12 | /** 13 | * 自动生成 SPI 文件 14 | * 15 | * @author ychost@outlook.com 16 | * @date 2021-03-28 17 | */ 18 | @Retention(RetentionPolicy.SOURCE) 19 | @Target({ElementType.TYPE}) 20 | @Documented 21 | public @interface FastAspectAround { 22 | /** 23 | * 会自动生成方法覆盖 support,只要方法或者类包含该注解就运行标注的 handler 24 | */ 25 | Class support() default FastNone.class; 26 | 27 | /** 28 | * 指定切面的拦截顺序,优先取 override 的 order() 方法,然后取这个 29 | */ 30 | int order() default FastAspectHandler.DEFAULT_ORDER; 31 | } 32 | -------------------------------------------------------------------------------- /fastaop/src/main/java/org/fastlight/aop/annotation/FastAspectVar.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.aop.annotation; 2 | 3 | import java.lang.annotation.*; 4 | 5 | import org.fastlight.aop.handler.FastAspectContext; 6 | 7 | /** 8 | * 能够在方法内部引入切面上下文,含方法名,入参,注解,所在类等信息{@link FastAspectContext} 9 | * 10 | * @author ychost@outlook.com 11 | * @date 2021-03-27 12 | */ 13 | @Retention(RetentionPolicy.SOURCE) 14 | @Target({ElementType.LOCAL_VARIABLE}) 15 | @Documented 16 | public @interface FastAspectVar { 17 | } 18 | -------------------------------------------------------------------------------- /fastaop/src/main/java/org/fastlight/aop/annotation/FastNone.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.aop.annotation; 2 | 3 | /** 4 | * default 等值可以用到,类似 NULL 5 | * 6 | * @author ychost@outlook.com 7 | * @date 2021-04-07 8 | */ 9 | public @interface FastNone { 10 | } 11 | -------------------------------------------------------------------------------- /fastaop/src/main/java/org/fastlight/aop/handler/FastAspectContext.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.aop.handler; 2 | 3 | import java.util.Map; 4 | 5 | import com.google.common.collect.Maps; 6 | import org.fastlight.apt.model.MetaMethod; 7 | 8 | /** 9 | * @author ychost@outlook.com 10 | * @date 2021-03-27 11 | */ 12 | @SuppressWarnings("unchecked") 13 | public class FastAspectContext { 14 | /** 15 | * handler 构造器 16 | */ 17 | public static final String EXT_META_BUILDER_CLASS = "fast.meta_handler_builder_class"; 18 | 19 | /** 20 | * 构造 handler 的时候需要线程安全 21 | */ 22 | public static final Object HANDLER_LOCKER = new Object(); 23 | 24 | /** 25 | * 每个 context 进入切面 handler 的时候都会 copy 一份,然后赋值这个为 handlerIndex 26 | * 可以解决多线程调用 ctx.proceed() 的问题 27 | */ 28 | private int supportIndex; 29 | 30 | /** 31 | * 方法元数据 32 | */ 33 | private MetaMethod metaMethod; 34 | 35 | /** 36 | * 当前调用的 this,静态方法就是 null 37 | * 通过弱引用防止多线程持有 context 造成内存泄漏 38 | */ 39 | private Object owner; 40 | /** 41 | * 方法的入参 42 | */ 43 | private Object[] args; 44 | 45 | /** 46 | * 扩展属性,可自定义添加,仅在方法内有效,比如在 preHandle 放入方法的执行时间戳,然后再 postHandle 能算出方法的耗时 47 | */ 48 | private Map extensions; 49 | 50 | /** 51 | * 构造一个上下文 52 | */ 53 | public static FastAspectContext create(MetaMethod metaMethod, Object owner, Object[] args) { 54 | // 这是系统初始化的,配置准许切面调用 55 | FastAspectContext ctx = new FastAspectContext(-1); 56 | ctx.metaMethod = metaMethod; 57 | ctx.owner = owner; 58 | ctx.args = args; 59 | return ctx; 60 | } 61 | 62 | public FastAspectContext(int supportIndex) { 63 | this.supportIndex = supportIndex; 64 | } 65 | 66 | /** 67 | * 获取入参 map,丢掉了注解 68 | */ 69 | public Map getParamMap() { 70 | Map map = Maps.newHashMap(); 71 | for (int i = 0; i < metaMethod.getParameters().length; i++) { 72 | map.put(metaMethod.getParameters()[i].getName(), args[i]); 73 | } 74 | return map; 75 | } 76 | 77 | /** 78 | * 全局 Handler 缓存 79 | */ 80 | private static final Map, FastAspectHandler> HANDLER_MAP = Maps.newHashMap(); 81 | 82 | /** 83 | * 构造一个 Handler,线程安全的,通过缓存来优化性能 84 | */ 85 | protected FastAspectHandler getHandler() { 86 | try { 87 | Class builderClass = getMetaExtension(EXT_META_BUILDER_CLASS); 88 | if (builderClass == null) { 89 | builderClass = FastAspectSpiHandlerBuilder.class; 90 | } 91 | FastAspectHandler handler = HANDLER_MAP.get(builderClass); 92 | if (handler != null) { 93 | return handler; 94 | } 95 | synchronized (HANDLER_LOCKER) { 96 | handler = HANDLER_MAP.get(builderClass); 97 | if (handler != null) { 98 | return handler; 99 | } 100 | FastAspectHandlerBuilder builder = builderClass.newInstance(); 101 | handler = builder.build(); 102 | HANDLER_MAP.put(builderClass, handler); 103 | return handler; 104 | } 105 | } catch (Exception e) { 106 | throw new RuntimeException(e); 107 | } 108 | } 109 | 110 | /** 111 | * 通过注解可以替换内部实现,将其引用到局部变量 112 | */ 113 | public static FastAspectContext currentContext() { 114 | throw new RuntimeException("[FastAop] context not find @FastAspect"); 115 | } 116 | 117 | /** 118 | * 添加扩展属性,方法内有效 119 | * 120 | * @param key 扩展 key 121 | * @param val 扩展 value 122 | */ 123 | public void addExtension(String key, Object val) { 124 | if (extensions == null) { 125 | extensions = Maps.newHashMap(); 126 | } 127 | extensions.put(key, val); 128 | } 129 | 130 | /** 131 | * 获取扩展属性 132 | * 133 | * @param key 扩展 key 134 | * @param 扩展 value 类型 135 | * @return 扩展 value 136 | */ 137 | public T getExtension(String key) { 138 | if (extensions == null) { 139 | return null; 140 | } 141 | return (T)extensions.get(key); 142 | } 143 | 144 | /** 145 | * 添加全局的元数据扩展,每个 Method 有唯一的一个缓存池 146 | * 147 | * @param key 扩展 key 148 | * @param value 扩展 value 149 | */ 150 | public void addMetaExtension(String key, Object value) { 151 | getMetaMethod().addMetaExtension(key, value); 152 | } 153 | 154 | /** 155 | * 获取全局的元数据扩展,每个 Method 有唯一的缓存池 156 | * 157 | * @param key 扩展 key 158 | * @param 扩展 value 的类型 159 | * @return 扩展 value 160 | */ 161 | public T getMetaExtension(String key) { 162 | return getMetaMethod().getMetaExtension(key); 163 | } 164 | 165 | public MetaMethod getMetaMethod() { 166 | return metaMethod; 167 | } 168 | 169 | public Object getOwner() { 170 | return owner; 171 | } 172 | 173 | /** 174 | * 获取当前环境的 this 可能为空 175 | * 176 | * @return 调用调用的 this 177 | */ 178 | 179 | public Object getThis() { 180 | return getOwner(); 181 | } 182 | 183 | public Object[] getArgs() { 184 | return args; 185 | } 186 | 187 | /** 188 | * 生成的代码调用入口,也可看做无抛出异常的 proceed 189 | */ 190 | public Object invoke(Object... args) { 191 | try { 192 | return proceed(args); 193 | } catch (Exception e) { 194 | throw new RuntimeException(e); 195 | } 196 | } 197 | 198 | /** 199 | * 切面 handler 调用入口,仅支持单线程调用 200 | */ 201 | public Object proceed(Object... args) throws Exception { 202 | // 调用下一个处理器,handlerIndex 从 -1 开始的 203 | // 复制一份,防止多线程问题影响到 args 和 handlerIndex 204 | FastAspectContext ctx = copy(supportIndex + 1); 205 | if (args.length > 0) { 206 | ctx.args = args; 207 | } 208 | return getHandler().processAround(ctx); 209 | } 210 | 211 | /** 212 | * 是否有 handler 进行切面处理 213 | */ 214 | public boolean support() { 215 | return getHandler().support(this.metaMethod); 216 | } 217 | 218 | /** 219 | * 浅复制一个 context,解决多线程的问题 220 | */ 221 | protected FastAspectContext copy(int supportIndex) { 222 | FastAspectContext ctx = new FastAspectContext(supportIndex); 223 | ctx.args = args; 224 | ctx.metaMethod = metaMethod; 225 | ctx.owner = owner; 226 | ctx.extensions = extensions; 227 | return ctx; 228 | } 229 | 230 | /** 231 | * spi 处理的 supports 的索引 232 | */ 233 | protected int getSupportIndex() { 234 | return supportIndex; 235 | } 236 | 237 | /** 238 | * 设置处理器索引,禁止私自调用 239 | */ 240 | protected void setSupportIndex(int supportIndex) { 241 | this.supportIndex = supportIndex; 242 | } 243 | } 244 | -------------------------------------------------------------------------------- /fastaop/src/main/java/org/fastlight/aop/handler/FastAspectHandler.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.aop.handler; 2 | 3 | import org.fastlight.apt.model.MetaMethod; 4 | 5 | /** 6 | * 切面的生命周期回调,主要有 preHandle,returnHandle,errorHandle,postHandle 7 | * 8 | * @author ychost@outlook.com 9 | * @date 2021-03-27 10 | */ 11 | public interface FastAspectHandler { 12 | 13 | int DEFAULT_ORDER = 0; 14 | 15 | /** 16 | * 执行顺序,数字越小越先执行 17 | * 18 | * @return 执行顺序 19 | */ 20 | default int getOrder() { 21 | return DEFAULT_ORDER; 22 | } 23 | 24 | /** 25 | * 环绕处理 26 | * 27 | * @param ctx 切面上下文 28 | * @return 方法返回值 29 | * @throws Exception 切面执行异常或者方法调用异常 30 | */ 31 | Object processAround(FastAspectContext ctx) throws Exception; 32 | 33 | /** 34 | * 切面是否支持该方法,结果会缓存,一般是通过方法的注解来过滤,缓存之后可提高切面执行效率 35 | * 36 | * @param metaMethod 方法元数据 37 | * @return true 切面会被执行 38 | */ 39 | default boolean support(MetaMethod metaMethod) { 40 | return true; 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /fastaop/src/main/java/org/fastlight/aop/handler/FastAspectHandlerBuilder.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.aop.handler; 2 | 3 | /** 4 | * FastAspect 直接调用的 Handler,系统会生成单例模式 5 | * 6 | * @author ychost@outlook.com 7 | * @date 2021-03-27 8 | */ 9 | public interface FastAspectHandlerBuilder { 10 | /** 11 | * 构造一个切面执行器,会通过 {@link org.fastlight.aop.annotation.FastAspect} 生成的代码直接引用 12 | * 13 | * @return 切面执行器 14 | */ 15 | FastAspectHandler build(); 16 | } 17 | -------------------------------------------------------------------------------- /fastaop/src/main/java/org/fastlight/aop/handler/FastAspectSpiHandler.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.aop.handler; 2 | 3 | import java.util.Comparator; 4 | import java.util.List; 5 | import java.util.ServiceLoader; 6 | import java.util.Set; 7 | 8 | import com.google.common.collect.ImmutableList; 9 | import com.google.common.collect.Lists; 10 | import com.google.common.collect.Sets; 11 | import org.fastlight.apt.model.InvokeMethodType; 12 | import org.fastlight.apt.model.MetaMethod; 13 | 14 | /** 15 | * 通过 SPI 注入执行器,然后代理调用他们 16 | * 17 | * @author ychost@outlook.com 18 | * @date 2021-03-27 19 | */ 20 | public class FastAspectSpiHandler implements FastAspectHandler { 21 | /** 22 | * support 等于 true 的 handler 索引 23 | */ 24 | public static final String SUPPORT_INDICES = "fast.supportIndices"; 25 | 26 | /** 27 | * SPI 注入进来的执行器,不可变类型 28 | */ 29 | private volatile List spiHandlers = ImmutableList.of(); 30 | 31 | /** 32 | * 初始化标志 33 | */ 34 | private volatile boolean isInit = false; 35 | 36 | /** 37 | * 初始化锁 38 | */ 39 | private final Object initLock = new Object(); 40 | 41 | /** 42 | * 单例 43 | */ 44 | public static final FastAspectSpiHandler SINGLETON = new FastAspectSpiHandler(); 45 | 46 | /** 47 | * 只能是单例模式 48 | */ 49 | protected FastAspectSpiHandler() { 50 | 51 | } 52 | 53 | /** 54 | * 获取实例,注意没有初始化 55 | */ 56 | public static FastAspectSpiHandler getInstance() { 57 | return SINGLETON; 58 | } 59 | 60 | /** 61 | * 通过 SPI 注入 Handlers 62 | */ 63 | public void initHandlers() { 64 | if (isInit) { 65 | return; 66 | } 67 | synchronized (initLock) { 68 | if (isInit) { 69 | return; 70 | } 71 | try { 72 | List handlers = Lists.newArrayList(); 73 | ServiceLoader serviceLoader = ServiceLoader.load(FastAspectHandler.class); 74 | for (FastAspectHandler handler : serviceLoader) { 75 | // 防止重复添加 76 | if (handlers.stream().noneMatch(v -> v.getClass().equals(handler.getClass()))) { 77 | handlers.add(handler); 78 | } 79 | } 80 | handlers.sort(Comparator.comparingInt(FastAspectHandler::getOrder)); 81 | spiHandlers = ImmutableList.copyOf(handlers); 82 | } finally { 83 | isInit = true; 84 | } 85 | } 86 | } 87 | 88 | /** 89 | * {@inheritDoc} 90 | */ 91 | @Override 92 | public Object processAround(FastAspectContext ctx) throws Exception { 93 | List supports = getSupportIndices(ctx.getMetaMethod()); 94 | if (supports.size() < ctx.getSupportIndex()) { 95 | throw new RuntimeException( 96 | "[FastAop] support index error for method " + ctx.getMetaMethod().getMethod().getName() 97 | ); 98 | } 99 | // 调用原始方法 100 | if (supports.size() == ctx.getSupportIndex()) { 101 | try { 102 | // 赋值标志位,递归调用原始方法,然后会调用原始逻辑 103 | ctx.getMetaMethod().setInvokeMethodType(InvokeMethodType.ORIGIN); 104 | return ctx.getMetaMethod().getMethod().invoke(ctx.getThis(), ctx.getArgs()); 105 | } finally { 106 | ctx.getMetaMethod().setInvokeMethodType(InvokeMethodType.AOP); 107 | } 108 | } 109 | // 调用链式处理 110 | return spiHandlers.get(supports.get(ctx.getSupportIndex())).processAround(ctx); 111 | } 112 | 113 | /** 114 | * 遍历执行器的 support,并缓存 index 115 | */ 116 | @Override 117 | public boolean support(MetaMethod metaMethod) { 118 | List supportIndices = getSupportIndices(metaMethod); 119 | // 当前方法有支持的切面逻辑且线程标识为调用下一个切面逻辑 120 | boolean support = supportIndices.size() > 0 && metaMethod.getInvokeMethodType() == InvokeMethodType.AOP; 121 | // 递归调用也支持切面 122 | if (!support) { 123 | metaMethod.setInvokeMethodType(InvokeMethodType.AOP); 124 | } 125 | return support; 126 | } 127 | 128 | /** 129 | * 获取支持该方法的切面索引 130 | */ 131 | protected List getSupportIndices(MetaMethod metaMethod) { 132 | List supportIndices = metaMethod.getMetaExtension(SUPPORT_INDICES); 133 | if (supportIndices != null) { 134 | return supportIndices; 135 | } 136 | // metaMethod 是全局的 137 | //noinspection SynchronizationOnLocalVariableOrMethodParameter 138 | synchronized (metaMethod) { 139 | supportIndices = metaMethod.getMetaExtension(SUPPORT_INDICES); 140 | if (supportIndices != null) { 141 | return supportIndices; 142 | } 143 | supportIndices = Lists.newArrayList(); 144 | for (int i = 0; i < spiHandlers.size(); i++) { 145 | if (spiHandlers.get(i).support(metaMethod)) { 146 | supportIndices.add(i); 147 | } 148 | } 149 | metaMethod.addMetaExtension(SUPPORT_INDICES, supportIndices); 150 | return supportIndices; 151 | } 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /fastaop/src/main/java/org/fastlight/aop/handler/FastAspectSpiHandlerBuilder.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.aop.handler; 2 | 3 | /** 4 | * 基于 SPI 的切面构造器,系统默认的 builder,里面会去代理执行 SPI 注入进来的切面逻辑 5 | * 6 | * @author ychost@outlook.com 7 | * @date 2021-03-27 8 | */ 9 | public class FastAspectSpiHandlerBuilder implements FastAspectHandlerBuilder { 10 | /** 11 | * SPI 代理执行器 12 | */ 13 | public static final FastAspectSpiHandler FAST_ASPECT_SPI_HANDLER = FastAspectSpiHandler.getInstance(); 14 | 15 | static { 16 | FAST_ASPECT_SPI_HANDLER.initHandlers(); 17 | } 18 | 19 | @Override 20 | public FastAspectHandler build() { 21 | return FAST_ASPECT_SPI_HANDLER; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /fastaop/src/main/java/org/fastlight/aop/processor/AnnotationProcessor.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.aop.processor; 2 | 3 | import com.google.auto.service.AutoService; 4 | import com.google.common.collect.Lists; 5 | import org.fastlight.apt.processor.BaseAnnotationProcessor; 6 | import org.fastlight.apt.processor.BaseFastProcessor; 7 | import javax.annotation.processing.ProcessingEnvironment; 8 | 9 | import javax.annotation.processing.Processor; 10 | import javax.annotation.processing.SupportedAnnotationTypes; 11 | import javax.annotation.processing.SupportedSourceVersion; 12 | import javax.lang.model.SourceVersion; 13 | import java.util.List; 14 | import org.fastlight.aop.util.BannerLogger; 15 | 16 | 17 | /** 18 | * 注解处理的总入口,java 编译器有个优化,同一个元素只会经过一个 processor,所以这里遍历所有元素并给所有处理器执行 19 | * 20 | * @author ychost@outlook.com 21 | * @date 2021-03-27 22 | */ 23 | @AutoService(Processor.class) 24 | @SupportedAnnotationTypes({"*"}) 25 | @SupportedSourceVersion(SourceVersion.RELEASE_8) 26 | public class AnnotationProcessor extends BaseAnnotationProcessor { 27 | 28 | List> processors = Lists.newArrayList( 29 | new FastAspectProcessor(), 30 | new FastAspectAroundProcessor(), 31 | new FastAspectVarProcessor() 32 | ); 33 | 34 | @Override 35 | protected List> getProcessors() { 36 | return processors; 37 | } 38 | 39 | @Override 40 | public synchronized void init(ProcessingEnvironment environment) { 41 | BannerLogger.printBanner(); 42 | super.init(environment); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /fastaop/src/main/java/org/fastlight/aop/processor/AspectSupportTypes.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.aop.processor; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.InputStreamReader; 5 | import java.net.URL; 6 | import java.util.Enumeration; 7 | import java.util.Set; 8 | 9 | import com.google.common.base.Charsets; 10 | import com.google.common.collect.Sets; 11 | import org.apache.commons.lang3.StringUtils; 12 | import org.fastlight.aop.annotation.FastAspect; 13 | 14 | /** 15 | * 用户可以自由添加注解到 supports.txt 里面实现切面注入 16 | * 17 | * @author ychost 18 | * @date 2021-04-07 19 | **/ 20 | public class AspectSupportTypes { 21 | private static final String TYPES_FILE = "META-INF/aspect/fast.aspect.supports.txt"; 22 | 23 | private static Set SUPPORT_TYPES = null; 24 | 25 | private static final Object SUPPORT_LOCKER = new Object(); 26 | 27 | public static Set getSupportTypes() { 28 | if (SUPPORT_TYPES != null) { 29 | return SUPPORT_TYPES; 30 | } 31 | try { 32 | synchronized (SUPPORT_LOCKER) { 33 | if (SUPPORT_TYPES != null) { 34 | return SUPPORT_TYPES; 35 | } 36 | SUPPORT_TYPES = Sets.newHashSet(); 37 | // 加入默认植入注解 38 | SUPPORT_TYPES.add(FastAspect.class.getName()); 39 | // 扫描用户自定义注解 40 | Enumeration urls = AspectSupportTypes.class.getClassLoader().getResources(TYPES_FILE); 41 | while (urls.hasMoreElements()) { 42 | URL url = urls.nextElement(); 43 | try (BufferedReader reader = new BufferedReader( 44 | new InputStreamReader(url.openStream(), Charsets.UTF_8))) { 45 | String line; 46 | while ((line = reader.readLine()) != null) { 47 | String aspect = line.split("#")[0].trim(); 48 | if (StringUtils.isNotBlank(aspect)) { 49 | SUPPORT_TYPES.add(aspect); 50 | } 51 | } 52 | } 53 | } 54 | return SUPPORT_TYPES; 55 | } 56 | } catch (Exception e) { 57 | throw new RuntimeException(e); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /fastaop/src/main/java/org/fastlight/aop/processor/FastAspectAroundProcessor.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.aop.processor; 2 | 3 | import javax.lang.model.element.AnnotationMirror; 4 | import javax.lang.model.element.TypeElement; 5 | 6 | import com.sun.tools.javac.code.Type; 7 | import com.sun.tools.javac.tree.JCTree.JCClassDecl; 8 | import org.fastlight.aop.annotation.FastAspectAround; 9 | import org.fastlight.aop.annotation.FastNone; 10 | import org.fastlight.aop.handler.FastAspectHandler; 11 | import org.fastlight.aop.translator.FastAspectAroundTranslator; 12 | import org.fastlight.apt.processor.BaseFastSpiProcessor; 13 | 14 | /** 15 | * @author ychost@outlook.com 16 | * @date 2021-03-28 17 | */ 18 | public class FastAspectAroundProcessor extends BaseFastSpiProcessor { 19 | 20 | @Override 21 | protected Class supportSpiTypes() { 22 | return FastAspectHandler.class; 23 | } 24 | 25 | @Override 26 | public void processTypeElement(TypeElement typeElement, AnnotationMirror atm) { 27 | super.processTypeElement(typeElement, atm); 28 | Type supportType = getAtValueData(atm, "support"); 29 | int order = Integer.parseInt(getAtValueData(atm, "order").toString()); 30 | FastAspectAroundTranslator translator = getTranslator(); 31 | JCClassDecl jcClassDecl = javacTrees.getTree(typeElement); 32 | // 覆盖 getOrder 和 support 方法 33 | if (!((FastNone.class.getName()).equals(supportType.toString()) 34 | && !translator.isOverrideSupport(jcClassDecl))) { 35 | translator.addSupportMethod(jcClassDecl, supportType); 36 | } 37 | if (order != FastAspectHandler.DEFAULT_ORDER 38 | && !translator.isOverrideGetOrder(jcClassDecl)) { 39 | translator.addGetOrder(jcClassDecl, order); 40 | } 41 | } 42 | 43 | public FastAspectAroundTranslator getTranslator() { 44 | return new FastAspectAroundTranslator(treeMaker, names.table, messager); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /fastaop/src/main/java/org/fastlight/aop/processor/FastAspectProcessor.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.aop.processor; 2 | 3 | import java.util.List; 4 | import java.util.Optional; 5 | import java.util.Set; 6 | 7 | import javax.lang.model.element.AnnotationMirror; 8 | import javax.lang.model.element.Element; 9 | import javax.lang.model.element.ExecutableElement; 10 | import javax.lang.model.element.TypeElement; 11 | 12 | import com.google.common.collect.Sets; 13 | import com.sun.tools.javac.code.Symbol; 14 | import com.sun.tools.javac.tree.JCTree.JCClassDecl; 15 | import com.sun.tools.javac.tree.JCTree.JCMethodDecl; 16 | import org.fastlight.aop.annotation.FastAspect; 17 | import org.fastlight.aop.annotation.FastNone; 18 | import org.fastlight.aop.translator.FastAspectTranslator; 19 | import org.fastlight.apt.model.compile.MethodCompile; 20 | import org.fastlight.apt.processor.BaseFastProcessor; 21 | import org.fastlight.apt.util.FastCollections; 22 | 23 | /** 24 | * @author ychost@outlook.com 25 | * @date 2021-03-27 26 | */ 27 | public class FastAspectProcessor extends BaseFastProcessor { 28 | 29 | @Override 30 | public Set getSupportedAnnotationTypes() { 31 | return Sets.newHashSet("*"); 32 | } 33 | 34 | /** 35 | * 随机算一个支持植入代码的注解 36 | */ 37 | AnnotationMirror getSupportAtm(Element element) { 38 | List atms = element.getAnnotationMirrors(); 39 | if (FastCollections.isEmpty(atms)) { 40 | return null; 41 | } 42 | Set supportTypes = AspectSupportTypes.getSupportTypes(); 43 | for (AnnotationMirror atm : atms) { 44 | if (supportTypes.contains(atm.getAnnotationType().toString())) { 45 | return atm; 46 | } 47 | } 48 | return null; 49 | } 50 | 51 | @Override 52 | public void processExecutableElement(ExecutableElement executableElement, AnnotationMirror atm) { 53 | Symbol.ClassSymbol ownerElement = getOwnerElement(executableElement, Symbol.ClassSymbol.class); 54 | JCMethodDecl jcMethodDecl = javacTrees.getTree(executableElement); 55 | if (jcMethodDecl == null || ownerElement == null) { 56 | return; 57 | } 58 | // 优先取方法上面的注解 59 | atm = getSupportAtm(executableElement); 60 | if (atm == null) { 61 | atm = getSupportAtm(ownerElement); 62 | } 63 | if (atm == null) { 64 | return; 65 | } 66 | // 不切构造函数和初始化 67 | if (!Optional.ofNullable(jcMethodDecl.getReturnType()).map(v -> v.type).isPresent()) { 68 | return; 69 | } 70 | // 不切匿名类 71 | if (!Optional.ofNullable(jcMethodDecl.sym).map(v -> v.owner).map(v -> v.type).isPresent()) { 72 | return; 73 | } 74 | MethodCompile methodCompile = new MethodCompile(); 75 | methodCompile.setMethodDecl(jcMethodDecl); 76 | methodCompile.setOwnerElement(ownerElement); 77 | // 仅有 FastAspect 可指定 builder 78 | if (FastAspect.class.getName().equals(atm.getAnnotationType().toString())) { 79 | methodCompile.addExtension("builder", getAtValueData(atm, "builder")); 80 | } 81 | methodCompile.setMethodElement(executableElement); 82 | FastAspectTranslator translator = getTranslator(methodCompile); 83 | // 防止重复织入 84 | if (translator.isMarkedMethod()) { 85 | return; 86 | } 87 | JCClassDecl ownerClass = javacTrees.getTree(ownerElement); 88 | // 1. 添加类元数据缓存 89 | translator.addMetaOwnerVar(ownerClass); 90 | // 2. 添加方法元数据缓存 91 | translator.addMetaMethodVar(ownerClass); 92 | // 3. 方法内部织入切面代码 93 | translator.weaveMethod(); 94 | // 4. 处理 return 和 局部变量 95 | jcMethodDecl.accept(translator); 96 | } 97 | 98 | /** 99 | * 获取语法树遍历器 100 | * 101 | * @param methodCompile 注入上下文变量 102 | */ 103 | protected FastAspectTranslator getTranslator(MethodCompile methodCompile) { 104 | FastAspectTranslator translator = new FastAspectTranslator(treeMaker, names.table, messager); 105 | translator.init(methodCompile); 106 | return translator; 107 | } 108 | 109 | @Override 110 | public void processTypeElement(TypeElement typeElement, AnnotationMirror atm) { 111 | processExecutableOfTypeElement(typeElement, atm, true); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /fastaop/src/main/java/org/fastlight/aop/processor/FastAspectVarProcessor.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.aop.processor; 2 | 3 | import com.google.common.collect.Sets; 4 | import com.sun.tools.javac.tree.JCTree; 5 | import org.fastlight.aop.annotation.FastAspectVar; 6 | import org.fastlight.aop.translator.FastAspectVarTranslator; 7 | import org.fastlight.apt.processor.BaseFastProcessor; 8 | 9 | import javax.lang.model.element.AnnotationMirror; 10 | import javax.lang.model.element.ExecutableElement; 11 | import javax.lang.model.element.TypeElement; 12 | import java.util.Set; 13 | 14 | /** 15 | * @author ychost@outlook.com 16 | * @date 2021-03-28 17 | */ 18 | public class FastAspectVarProcessor extends BaseFastProcessor { 19 | 20 | @Override 21 | public Set getSupportedAnnotationTypes() { 22 | return Sets.newHashSet("*"); 23 | } 24 | 25 | @Override 26 | public void processExecutableElement(ExecutableElement executableElement, AnnotationMirror atm) { 27 | JCTree.JCMethodDecl methodDecl = javacTrees.getTree(executableElement); 28 | TypeElement ownerElement = getOwnerElement(executableElement, TypeElement.class); 29 | if (ownerElement == null || methodDecl == null) { 30 | return; 31 | } 32 | FastAspectVarTranslator translator = getTranslator(); 33 | methodDecl.accept(translator); 34 | if (!translator.isAtCtxVar() || translator.isAtAspect()) { 35 | return; 36 | } 37 | translator.checkClass(javacTrees.getTree(ownerElement)); 38 | if (!translator.isAtAspect()) { 39 | logError(String.format("[FastAop] %s.%s local var @FastAspectVar not match @FastAspect in Method or Class", 40 | ownerElement.toString(), executableElement.toString() 41 | )); 42 | } 43 | } 44 | 45 | @Override 46 | public void processTypeElement(TypeElement typeElement, AnnotationMirror atm) { 47 | processExecutableOfTypeElement(typeElement, atm, true); 48 | } 49 | 50 | FastAspectVarTranslator getTranslator() { 51 | return new FastAspectVarTranslator(treeMaker, names.table, messager); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /fastaop/src/main/java/org/fastlight/aop/translator/FastAspectAroundTranslator.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.aop.translator; 2 | 3 | import java.util.Optional; 4 | 5 | import javax.annotation.processing.Messager; 6 | 7 | import com.sun.tools.javac.code.Flags; 8 | import com.sun.tools.javac.code.Symbol; 9 | import com.sun.tools.javac.code.Type; 10 | import com.sun.tools.javac.code.TypeTag; 11 | import com.sun.tools.javac.tree.JCTree; 12 | import com.sun.tools.javac.tree.JCTree.JCBlock; 13 | import com.sun.tools.javac.tree.JCTree.JCClassDecl; 14 | import com.sun.tools.javac.tree.JCTree.JCExpression; 15 | import com.sun.tools.javac.tree.JCTree.JCIdent; 16 | import com.sun.tools.javac.tree.JCTree.JCMethodDecl; 17 | import com.sun.tools.javac.tree.JCTree.JCReturn; 18 | import com.sun.tools.javac.tree.JCTree.JCVariableDecl; 19 | import com.sun.tools.javac.tree.TreeMaker; 20 | import com.sun.tools.javac.util.List; 21 | import com.sun.tools.javac.util.Name.Table; 22 | import org.apache.commons.lang3.StringUtils; 23 | import org.fastlight.aop.handler.FastAspectHandler; 24 | import org.fastlight.apt.model.MetaMethod; 25 | import org.fastlight.apt.translator.BaseFastTranslator; 26 | import org.fastlight.apt.util.FastCollections; 27 | 28 | /** 29 | * @author ychost@outlook.com 30 | * @date 2021-04-07 31 | */ 32 | public class FastAspectAroundTranslator extends BaseFastTranslator { 33 | public static final String SUPPORT_METHOD = "support"; 34 | public static final String GET_ORDER_METHOD = "getOrder"; 35 | public static final String META_METHOD_PARAM = "metaMethod"; 36 | 37 | public FastAspectAroundTranslator(TreeMaker treeMaker, 38 | Table names, 39 | Messager messager) { 40 | super(treeMaker, names, messager); 41 | } 42 | 43 | /** 44 | * 是否已经覆写了 support 方法 45 | */ 46 | public boolean isOverrideSupport(JCClassDecl jcClassDecl) { 47 | return containMethod(jcClassDecl, SUPPORT_METHOD, m -> { 48 | if (FastCollections.size(m.params) != 1) { 49 | return false; 50 | } 51 | // 含有一个参数且参数类型是 MetaMethod 52 | return Optional.of(m.params.get(0)).map(v -> v.vartype) 53 | .filter(v -> v instanceof JCIdent) 54 | .map(v -> ((JCIdent)v).sym) 55 | .map(Symbol::toString) 56 | .orElse(StringUtils.EMPTY) 57 | .equals(MetaMethod.class.getName()); 58 | }); 59 | } 60 | 61 | /** 62 | * 是否已经覆写了 getOrder() 方法 63 | */ 64 | public boolean isOverrideGetOrder(JCClassDecl jcClassDecl) { 65 | return containMethod(jcClassDecl, GET_ORDER_METHOD, m -> FastCollections.isEmpty(m.params)); 66 | } 67 | 68 | /** 69 | * 新增 support 方法 {@link org.fastlight.aop.handler.FastAspectHandler#support(MetaMethod)} 70 | * @formatter:off 71 | * 72 | * public boolean support(MetaMethod metaMethod){ 73 | * return metaMethod.isAnnotatedWithOwner(CustomerAnnotation.class) 74 | * } 75 | * 76 | * @formatter:on 77 | */ 78 | public void addSupportMethod(JCClassDecl jcClassDecl, Type supportType) { 79 | if (isOverrideSupport(jcClassDecl)) { 80 | logWarn(String.format("[FastAop] class %s is contain support method", jcClassDecl.name.toString())); 81 | return; 82 | } 83 | JCVariableDecl metaMethodParam = treeMaker.VarDef( 84 | treeMaker.Modifiers(Flags.PARAMETER), 85 | names.fromString(META_METHOD_PARAM), 86 | memberAccess("org.fastlight.apt.model.MetaMethod"), 87 | null 88 | ); 89 | // 这句必不可少,否者会报错 90 | // java.lang.AssertionError: Value of x -1 91 | metaMethodParam.pos = jcClassDecl.pos; 92 | JCExpression supportExpression = treeMaker.Apply( 93 | List.nil(), 94 | memberAccess(META_METHOD_PARAM + ".isAnnotatedWithOwner"), 95 | List.of(classLiteral(supportType)) 96 | ); 97 | JCBlock methodBlock = treeMaker.Block(0, List.of( 98 | treeMaker.Return(supportExpression) 99 | )); 100 | JCTree.JCAnnotation override = treeMaker.Annotation(memberAccess("java.lang.Override"), List.nil()); 101 | JCMethodDecl supportMethod = treeMaker.MethodDef( 102 | treeMaker.Modifiers(Flags.PUBLIC, List.of(override)), 103 | getNameFromString(SUPPORT_METHOD), 104 | treeMaker.TypeIdent(TypeTag.BOOLEAN), 105 | List.nil(), 106 | List.of(metaMethodParam), 107 | List.nil(), 108 | methodBlock, 109 | null 110 | ); 111 | jcClassDecl.defs = jcClassDecl.defs.append(supportMethod); 112 | } 113 | 114 | /** 115 | * 新增 getOrder 方法 {@link FastAspectHandler#getOrder()} 116 | * 117 | * @formatter:off 118 | * 119 | * public int getOrder(){ 120 | * return 3; 121 | * } 122 | * 123 | * @formatter:on 124 | */ 125 | public void addGetOrder(JCClassDecl jcClassDecl, Integer order) { 126 | if (isOverrideGetOrder(jcClassDecl)) { 127 | logWarn(String.format("[FastAop] class %s is contain getOrder method", jcClassDecl.name.toString())); 128 | return; 129 | } 130 | JCReturn jcReturn = treeMaker.Return( 131 | treeMaker.Literal(TypeTag.INT, order) 132 | ); 133 | JCBlock methodBlock = treeMaker.Block(0, List.of(jcReturn)); 134 | JCTree.JCAnnotation override = treeMaker.Annotation(memberAccess("java.lang.Override"), List.nil()); 135 | JCMethodDecl getOrderMethod = treeMaker.MethodDef( 136 | treeMaker.Modifiers(Flags.PUBLIC, List.of(override)), 137 | getNameFromString(GET_ORDER_METHOD), 138 | treeMaker.TypeIdent(TypeTag.INT), 139 | List.nil(), 140 | List.nil(), 141 | List.nil(), 142 | methodBlock, 143 | null 144 | ); 145 | jcClassDecl.defs = jcClassDecl.defs.append(getOrderMethod); 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /fastaop/src/main/java/org/fastlight/aop/translator/FastAspectTranslator.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.aop.translator; 2 | 3 | import java.util.Optional; 4 | 5 | import javax.annotation.processing.Messager; 6 | 7 | import com.sun.tools.javac.code.Type; 8 | import com.sun.tools.javac.code.TypeTag; 9 | import com.sun.tools.javac.tree.JCTree.JCAnnotation; 10 | import com.sun.tools.javac.tree.JCTree.JCBlock; 11 | import com.sun.tools.javac.tree.JCTree.JCClassDecl; 12 | import com.sun.tools.javac.tree.JCTree.JCExpression; 13 | import com.sun.tools.javac.tree.JCTree.JCMethodDecl; 14 | import com.sun.tools.javac.tree.JCTree.JCNewArray; 15 | import com.sun.tools.javac.tree.JCTree.JCReturn; 16 | import com.sun.tools.javac.tree.JCTree.JCStatement; 17 | import com.sun.tools.javac.tree.JCTree.JCVariableDecl; 18 | import com.sun.tools.javac.tree.TreeMaker; 19 | import com.sun.tools.javac.util.List; 20 | import com.sun.tools.javac.util.ListBuffer; 21 | import com.sun.tools.javac.util.Name.Table; 22 | import org.fastlight.aop.annotation.FastAspectVar; 23 | import org.fastlight.aop.handler.FastAspectContext; 24 | import org.fastlight.apt.model.MetaMethod; 25 | import org.fastlight.apt.translator.BaseFastTranslator; 26 | 27 | /** 28 | * @author ychost 29 | * @date 2021-02-24 30 | **/ 31 | @SuppressWarnings("unchecked") 32 | public class FastAspectTranslator extends BaseFastTranslator { 33 | public static final String CONTEXT_VAR = "__fast_context"; 34 | 35 | public static final String META_METHOD_VAR = "__fast_meta_method"; 36 | 37 | /** 38 | * 当前 visit 的是否为内部类,可避免对方法内部匿名类的切入 39 | */ 40 | private boolean isInnerClass = false; 41 | 42 | /** 43 | * 父元素下面的静态缓存变量 44 | */ 45 | private JCVariableDecl metaMethodVar = null; 46 | 47 | /** 48 | * 初始化注入相关元素 49 | */ 50 | public FastAspectTranslator(TreeMaker treeMaker, 51 | Table names, Messager messager) { 52 | super(treeMaker, names, messager); 53 | } 54 | 55 | @Override 56 | public void visitAnnotation(JCAnnotation jcAnnotation) { 57 | super.visitAnnotation(jcAnnotation); 58 | } 59 | 60 | /** 61 | * 将切面代码织入方法 62 | */ 63 | public void weaveMethod() { 64 | JCMethodDecl jcMethodDecl = ctxCompile.getMethodDecl(); 65 | if (jcMethodDecl.body == null) { 66 | return; 67 | } 68 | // 对于匿名函数类不切 69 | if (!Optional.ofNullable(jcMethodDecl.sym).map(v -> v.owner).map(v -> v.type).isPresent()) { 70 | return; 71 | } 72 | if (!Optional.ofNullable(jcMethodDecl.name).isPresent()) { 73 | return; 74 | } 75 | if (isMarkedMethod()) { 76 | return; 77 | } 78 | Integer methodIndex = addMetaMethod(); 79 | markMetaMethodAnnotation(methodIndex); 80 | JCVariableDecl ctxVar = newContextVar(methodIndex); 81 | ListBuffer ctxStatements = new ListBuffer<>(); 82 | ctxStatements.add(ctxVar); 83 | ctxStatements.add(invokeAopStatement()); 84 | changeMethodDefine(jcMethodDecl, statements -> { 85 | ctxStatements.addAll(statements); 86 | return ctxStatements.toList(); 87 | } 88 | ); 89 | } 90 | 91 | /** 92 | * 生成切面方法调用代码 93 | * @formatter:off 94 | * 95 | * public void func(Object... args){ 96 | * FastAspectContext __fast_context = ... 97 | * if(__fast_context.support()){ 98 | * return __fast_context.invoke() 99 | * } 100 | * } 101 | * 102 | * @formatter:on 103 | * @see FastAspectContext#support() 104 | */ 105 | protected JCStatement invokeAopStatement() { 106 | JCExpression hasNextHandler = treeMaker.Apply( 107 | List.nil(), 108 | memberAccess(CONTEXT_VAR + ".support"), 109 | List.nil() 110 | ); 111 | 112 | JCExpression invoke = treeMaker.Apply( 113 | List.nil(), 114 | memberAccess(CONTEXT_VAR + ".invoke"), 115 | List.nil() 116 | ); 117 | JCBlock invokeBlock; 118 | if (ctxCompile.canReturn()) { 119 | JCReturn jcReturn = treeMaker.Return( 120 | treeMaker.TypeCast( 121 | ctxCompile.getReturnType(), 122 | invoke 123 | ) 124 | ); 125 | invokeBlock = treeMaker.Block(0, List.of(jcReturn)); 126 | } else { 127 | invokeBlock = treeMaker.Block(0, List.of( 128 | treeMaker.Exec(invoke), 129 | treeMaker.Return(null) 130 | )); 131 | } 132 | return treeMaker.If( 133 | hasNextHandler, 134 | invokeBlock, 135 | null 136 | ); 137 | } 138 | 139 | /** 140 | * 添加 __fast_meta_method 变量 141 | */ 142 | public void addMetaMethodVar(JCClassDecl jcClassDecl) { 143 | metaMethodVar = getVar(jcClassDecl.defs, META_METHOD_VAR); 144 | if (metaMethodVar != null) { 145 | return; 146 | } 147 | JCExpression newArray = treeMaker.NewArray( 148 | memberAccess(MetaMethod.class.getName()), 149 | List.nil(), 150 | List.nil() 151 | ); 152 | // 添加 变量定义 153 | metaMethodVar = treeMaker.VarDef( 154 | treeMaker.Modifiers(getClassFinalModifiers()), 155 | getNameFromString(META_METHOD_VAR), 156 | treeMaker.TypeArray(memberAccess(MetaMethod.class.getName())), 157 | newArray 158 | ); 159 | addClassVar(jcClassDecl, metaMethodVar); 160 | } 161 | 162 | /** 163 | * 用户可直接在方法体内部拿到 __fast_context 164 | * 165 | * @see FastAspectContext#currentContext() 166 | */ 167 | @Override 168 | public void visitVarDef(JCVariableDecl jcVariableDecl) { 169 | super.visitVarDef(jcVariableDecl); 170 | if (isInnerClass) { 171 | return; 172 | } 173 | // 对于用了 FastAspectContext.currentContext() 174 | // 或者 @FastAspectVar 的变量统统进行替换 175 | if (jcVariableDecl.toString().contains("FastAspectContext") 176 | && ((jcVariableDecl.init != null 177 | && jcVariableDecl.init.toString().contains("FastAspectContext.currentContext()")) 178 | || jcVariableDecl.toString().contains(FastAspectVar.class.getSimpleName()) 179 | )) { 180 | jcVariableDecl.init = memberAccess(CONTEXT_VAR); 181 | } 182 | } 183 | 184 | @Override 185 | public void visitClassDef(JCClassDecl jcClassDecl) { 186 | isInnerClass = true; 187 | super.visitClassDef(jcClassDecl); 188 | isInnerClass = false; 189 | } 190 | 191 | /** 192 | * 将当前 method 的元元数据进行缓存 193 | */ 194 | protected Integer addMetaMethod() { 195 | JCNewArray originInit = (JCNewArray)metaMethodVar.init; 196 | List elements = originInit.elems; 197 | ListBuffer newElements = new ListBuffer<>(); 198 | newElements.addAll(elements); 199 | newElements.add(newMetaExpression(elements.size())); 200 | originInit.elems = newElements.toList(); 201 | return newElements.size() - 1; 202 | } 203 | 204 | /** 205 | * @see FastAspectContext#create(MetaMethod, Object, Object[]) 206 | */ 207 | protected JCVariableDecl newContextVar(Integer methodIndex) { 208 | JCExpression metaExpression = treeMaker.Indexed(memberAccess(META_METHOD_VAR), treeMaker.Literal(methodIndex)); 209 | return treeMaker.VarDef( 210 | treeMaker.Modifiers(0), 211 | getNameFromString(CONTEXT_VAR), 212 | memberAccess(FastAspectContext.class.getName()), 213 | treeMaker.Apply( 214 | List.nil(), 215 | memberAccess(getCreateMethod(FastAspectContext.class)), 216 | List.of(metaExpression, ownerExpression(), argsExpression(ctxCompile.getMethodDecl())) 217 | ) 218 | ); 219 | } 220 | 221 | /** 222 | * 将 builder class 作为 metaExtension 传入 223 | */ 224 | @Override 225 | protected JCExpression metaExtensionExpression() { 226 | return treeMaker.Apply( 227 | List.nil(), 228 | newMapMethod, 229 | List.of(treeMaker.Literal(FastAspectContext.EXT_META_BUILDER_CLASS), builderExpression()) 230 | ); 231 | } 232 | 233 | /** 234 | * @see MetaMethod#getMetaExtension(String) 235 | */ 236 | protected JCExpression builderExpression() { 237 | Type builder = ctxCompile.getExtension("builder"); 238 | if (builder != null) { 239 | return treeMaker.ClassLiteral(builder); 240 | } 241 | return treeMaker.Literal(TypeTag.BOT, null); 242 | } 243 | 244 | } 245 | -------------------------------------------------------------------------------- /fastaop/src/main/java/org/fastlight/aop/translator/FastAspectVarTranslator.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.aop.translator; 2 | 3 | import java.util.Set; 4 | import java.util.stream.Collectors; 5 | 6 | import com.sun.tools.javac.tree.JCTree; 7 | import com.sun.tools.javac.tree.JCTree.JCAnnotation; 8 | import com.sun.tools.javac.tree.TreeMaker; 9 | import com.sun.tools.javac.util.Name; 10 | import org.apache.commons.lang3.StringUtils; 11 | import org.fastlight.aop.annotation.FastAspect; 12 | import org.fastlight.aop.annotation.FastAspectVar; 13 | import org.fastlight.aop.processor.AspectSupportTypes; 14 | import org.fastlight.apt.translator.BaseFastTranslator; 15 | import org.fastlight.apt.util.FastCollections; 16 | 17 | import javax.annotation.processing.Messager; 18 | 19 | /** 20 | * @author ychost@outlook.com 21 | * @date 2021-03-28 22 | */ 23 | public class FastAspectVarTranslator extends BaseFastTranslator { 24 | private boolean isAtCtxVar = false; 25 | private boolean isAtAspect = false; 26 | 27 | static Set AT_SIMPLE_TYPES = AspectSupportTypes.getSupportTypes() 28 | .stream() 29 | .map(v -> { 30 | String[] array = v.split("\\."); 31 | if (array.length > 0) { 32 | return StringUtils.trim(array[array.length - 1]); 33 | } 34 | return null; 35 | }).filter(StringUtils::isNotBlank) 36 | .collect(Collectors.toSet()); 37 | 38 | public FastAspectVarTranslator(TreeMaker treeMaker, Name.Table names, Messager messager) { 39 | super(treeMaker, names, messager); 40 | } 41 | 42 | /** 43 | * 检查局部变量是否有标注 @FastAspectVar 44 | */ 45 | @Override 46 | public void visitAnnotation(JCTree.JCAnnotation jcAnnotation) { 47 | super.visitAnnotation(jcAnnotation); 48 | if (jcAnnotation.toString().contains(FastAspectVar.class.getSimpleName() + "(")) { 49 | isAtCtxVar = true; 50 | } 51 | // method 层面注解 52 | // 标注了 @FastAspect 或者用户自定义注解 53 | for (String type : AT_SIMPLE_TYPES) { 54 | if (jcAnnotation.toString().contains(type + "(")) { 55 | isAtAspect = true; 56 | return; 57 | } 58 | } 59 | } 60 | 61 | /** 62 | * 检查类上面是否有标注 @FastAspect 63 | */ 64 | public void checkClass(JCTree.JCClassDecl jcClassDecl) { 65 | if (jcClassDecl.mods == null || FastCollections.isEmpty(jcClassDecl.mods.annotations)) { 66 | return; 67 | } 68 | // class 层面注解 69 | // 标注了 @FastAspect 或者用户自定义注解 70 | for (JCAnnotation jcAnnotation : jcClassDecl.mods.annotations) { 71 | for (String type : AT_SIMPLE_TYPES) { 72 | if (jcAnnotation.toString().contains(type + "(")) { 73 | isAtAspect = true; 74 | return; 75 | } 76 | } 77 | } 78 | } 79 | 80 | public boolean isAtCtxVar() { 81 | return isAtCtxVar; 82 | } 83 | 84 | public boolean isAtAspect() { 85 | return isAtAspect; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /fastaop/src/main/java/org/fastlight/aop/util/BannerLogger.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.aop.util; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.InputStreamReader; 5 | import java.net.URL; 6 | import java.util.concurrent.atomic.AtomicBoolean; 7 | 8 | import com.google.common.base.Charsets; 9 | import org.apache.commons.lang3.StringUtils; 10 | 11 | /** 12 | * @author ychost 13 | * @date 2021-04-13 14 | **/ 15 | public class BannerLogger { 16 | /** 17 | * @formatter:off 18 | * 当 BANNER 文件没找到的时候,用这个默认的 19 | * @see Banner 生成器 20 | */ 21 | private static final String DEFAULT_BANNER = 22 | " ████████ ██ ██ \n" 23 | + "░██░░░░░ ░██ ████ ██████ \n" 24 | + "░██ ██████ ██████ ██████ ██░░██ ██████ ░██░░░██\n" 25 | + "░███████ ░░░░░░██ ██░░░░ ░░░██░ ██ ░░██ ██░░░░██░██ ░██\n" 26 | + "░██░░░░ ███████ ░░█████ ░██ ██████████░██ ░██░██████ \n" 27 | + "░██ ██░░░░██ ░░░░░██ ░██ ░██░░░░░░██░██ ░██░██░░░ \n" 28 | + "░██ ░░████████ ██████ ░░██ ░██ ░██░░██████ ░██ \n" 29 | + "░░ ░░░░░░░░ ░░░░░░ ░░ ░░ ░░ ░░░░░░ ░░ ${version}"; 30 | 31 | /** 32 | * @formatter:on 33 | * 默认的 BANNER 文件 34 | */ 35 | private static final String BANNER_FILE = "META-INF/aspect/banner.txt"; 36 | 37 | /** 38 | * 生成的 Banner 缓存 39 | */ 40 | private static final String BANNER; 41 | 42 | // 初始化 Banner 数据 43 | static { 44 | URL url = BannerLogger.class.getClassLoader().getResource(BANNER_FILE); 45 | String banner = DEFAULT_BANNER; 46 | if (url != null) { 47 | try (BufferedReader reader = new BufferedReader( 48 | new InputStreamReader(url.openStream(), Charsets.UTF_8))) { 49 | String line; 50 | StringBuilder sb = new StringBuilder(); 51 | while ((line = reader.readLine()) != null) { 52 | sb.append(line); 53 | } 54 | if (sb.length() > 0) { 55 | banner = sb.toString(); 56 | } 57 | } catch (Exception e) { 58 | throw new RuntimeException(e); 59 | } 60 | } 61 | // 填充 version 变量 62 | String version = FastAspectProperties.getProperty("fast.version"); 63 | BANNER = banner.replaceAll("\\$\\{version}","v"+ version); 64 | } 65 | 66 | /** 67 | * 打印标识 68 | */ 69 | private static final AtomicBoolean IS_PRINTED_BANNER = new AtomicBoolean(false); 70 | 71 | /** 72 | * 输出 Banner 到控制台,仅会打印一次 73 | */ 74 | public static void printBanner() { 75 | if (IS_PRINTED_BANNER.get()) { 76 | return; 77 | } 78 | System.out.println(BANNER); 79 | IS_PRINTED_BANNER.set(true); 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /fastaop/src/main/java/org/fastlight/aop/util/FastAspectProperties.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.aop.util; 2 | 3 | import java.util.Properties; 4 | 5 | /** 6 | * @author ychost 7 | * @date 2021-04-13 8 | **/ 9 | public class FastAspectProperties { 10 | /** 11 | * 配置文件 12 | */ 13 | private static final String PROPERTIES_FILE = "META-INF/aspect/aspect.config.properties"; 14 | /** 15 | * 加载的配置结果 16 | */ 17 | private static final Properties PROPERTIES; 18 | 19 | /** 20 | * 初始化配置 21 | */ 22 | static { 23 | PROPERTIES = new Properties(); 24 | try { 25 | PROPERTIES.load(FastAspectProperties.class.getClassLoader().getResourceAsStream(PROPERTIES_FILE)); 26 | } catch (Exception e) { 27 | throw new RuntimeException(e); 28 | } 29 | } 30 | 31 | /** 32 | * 获取配置属性 33 | */ 34 | public static String getProperty(String name) { 35 | return PROPERTIES.getProperty(name); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /fastaop/src/main/resources/META-INF/aspect/aspect.config.properties: -------------------------------------------------------------------------------- 1 | fast.version=${fast.version} -------------------------------------------------------------------------------- /fastapt/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | fastaop-parent 7 | org.fastlight 8 | 1.0.2-SNAPSHOT 9 | ../pom.xml 10 | 11 | 4.0.0 12 | 13 | fastapt 14 | ${fast.version} 15 | 16 | fastapt 17 | java fast annotation processor tool 18 | https://github.com/fast-light/fastaop 19 | 20 | jar 21 | 22 | 23 | 8 24 | 8 25 | 26 | 27 | 28 | com.google.auto.service 29 | auto-service 30 | 31 | 32 | org.apache.commons 33 | commons-lang3 34 | 35 | 36 | com.sun 37 | tools 38 | 1.8 39 | system 40 | ${java.home}/../lib/tools.jar 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /fastapt/src/main/java/org/fastlight/apt/annotation/FastMarkedMethod.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.apt.annotation; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * 被切的方法上面自动标注的,禁止手工使用 7 | * 8 | * @author ychost@outlook.com 9 | * @date 2021-03-28 10 | */ 11 | @Retention(RetentionPolicy.RUNTIME) 12 | @Target({ElementType.METHOD}) 13 | @Documented 14 | public @interface FastMarkedMethod { 15 | /** 16 | * 静态元数据索引 17 | */ 18 | int value(); 19 | } 20 | -------------------------------------------------------------------------------- /fastapt/src/main/java/org/fastlight/apt/model/InvokeMethodType.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.apt.model; 2 | 3 | /** 4 | * 调用原始方法 or 切面方法 5 | * 6 | * @author ychost@outlook.com 7 | * @date 2021-04-06 8 | */ 9 | public enum InvokeMethodType { 10 | /** 11 | * 调用原始方法 12 | */ 13 | ORIGIN, 14 | /** 15 | * 调用切面方法 16 | */ 17 | AOP 18 | } 19 | -------------------------------------------------------------------------------- /fastapt/src/main/java/org/fastlight/apt/model/MetaAnnotation.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.apt.model; 2 | 3 | import com.google.common.collect.Maps; 4 | import com.google.common.collect.Sets; 5 | import org.fastlight.apt.util.ReflectUtils; 6 | 7 | import java.lang.annotation.Annotation; 8 | import java.util.Map; 9 | import java.util.Set; 10 | 11 | /** 12 | * 注解元数据 13 | * 14 | * @author ychost@outlook.com 15 | * @date 2021-03-27 16 | */ 17 | @SuppressWarnings("unchecked") 18 | public class MetaAnnotation { 19 | /** 20 | * 注解类型 21 | */ 22 | public Class type; 23 | 24 | /** 25 | * 注解值,含 default 26 | */ 27 | public Map args; 28 | 29 | /** 30 | * 构造一个 MetaAnnotation 31 | * 32 | * @param type 注解类型 33 | * @param args 注解值,含 default,对于 "xxx.class" 的会直接转换成 class 34 | * @return 注解元数据 35 | */ 36 | public static MetaAnnotation create(Class type, Map args) { 37 | MetaAnnotation annotation = new MetaAnnotation(); 38 | annotation.type = type; 39 | Set keys = Sets.newHashSet(args.keySet()); 40 | Map atArgs = Maps.newHashMap(); 41 | for (String key : keys) { 42 | Object data = args.get(key); 43 | if (data instanceof String && data.toString().endsWith(".class")) { 44 | data = ReflectUtils.forNameCache(data.toString().replaceAll("\\.class", "")); 45 | } 46 | atArgs.put(key, data); 47 | } 48 | annotation.args = atArgs; 49 | return annotation; 50 | } 51 | 52 | /** 53 | * 获取注解的某个属性的值 54 | * 55 | * @param prop 属性 56 | * @param 属性值的类型 57 | * @return 属性的值 58 | */ 59 | public T getValue(String prop) { 60 | if (args == null) { 61 | return null; 62 | } 63 | return (T) args.get(prop); 64 | } 65 | 66 | public Class getType() { 67 | return type; 68 | } 69 | 70 | public Map getArgs() { 71 | return args; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /fastapt/src/main/java/org/fastlight/apt/model/MetaMethod.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.apt.model; 2 | 3 | import java.lang.annotation.Annotation; 4 | import java.lang.reflect.Method; 5 | import java.lang.reflect.Modifier; 6 | import java.util.Arrays; 7 | import java.util.Map; 8 | 9 | import com.google.common.collect.Maps; 10 | import org.fastlight.apt.annotation.FastMarkedMethod; 11 | 12 | /** 13 | * 方法元数据 14 | * 15 | * @author ychost@outlook.com 16 | * @date 2021-03-27 17 | */ 18 | public class MetaMethod { 19 | /** 20 | * 是否继续调用下一个切面,MetaMethod 是全局的,所以不存在内存泄漏 21 | */ 22 | private final ThreadLocal invokeMethodType = ThreadLocal.withInitial(() -> InvokeMethodType.AOP); 23 | 24 | /** 25 | * 该元素在静态 __fast_meta_method 的缓存索引 26 | */ 27 | private int cacheIndex; 28 | 29 | /** 30 | * 是否为静态方法 31 | */ 32 | private boolean isStatic; 33 | 34 | /** 35 | * 方法名 36 | */ 37 | private String name; 38 | 39 | /** 40 | * 方法返回类型 41 | */ 42 | private Class returnType; 43 | 44 | /** 45 | * 方法所在类的元数据 46 | */ 47 | private MetaType metaOwner; 48 | 49 | /** 50 | * 方法参数 51 | */ 52 | private MetaParameter[] parameters; 53 | 54 | /** 55 | * 注解 56 | */ 57 | private MetaAnnotation[] annotations; 58 | 59 | /** 60 | * 返回获取当前方法对象,懒汉模式 61 | */ 62 | private transient Method method; 63 | 64 | /** 65 | * 是否方法上面包含某个注解 66 | */ 67 | public boolean isAnnotated(Class cls) { 68 | return Arrays.stream(annotations).anyMatch(v -> cls.equals(v.getType())); 69 | } 70 | 71 | /** 72 | * 是否方法/类上面含某个注解 73 | */ 74 | public boolean isAnnotatedWithOwner(Class cls) { 75 | if (isAnnotated(cls)) { 76 | return true; 77 | } 78 | return metaOwner.isAnnotated(cls); 79 | } 80 | 81 | /** 82 | * 获取注解元数据,如果不存在就返回 null 83 | */ 84 | public MetaAnnotation getAnnotation(Class cls) { 85 | return Arrays.stream(annotations).filter(v -> cls.equals(v.getType())) 86 | .findFirst().orElse(null); 87 | } 88 | 89 | /** 90 | * 构造一个方法元数据 91 | */ 92 | public static MetaMethod create(Integer cacheIndex, MetaType metaOwner, MetaParameter[] parameters, 93 | MetaAnnotation[] annotations, Map metaExtension) { 94 | MetaMethod metaMethod = new MetaMethod(); 95 | metaMethod.cacheIndex = cacheIndex; 96 | metaMethod.metaOwner = metaOwner; 97 | metaMethod.parameters = parameters; 98 | metaMethod.annotations = annotations; 99 | if (metaExtension != null && metaExtension.size() > 0) { 100 | metaMethod.metaExtensions.putAll(metaExtension); 101 | } 102 | // 赋值 returnType,parameter.type,isStatic,name 103 | metaMethod.initMethod(); 104 | return metaMethod; 105 | } 106 | 107 | /** 108 | * 全局元数据缓存 109 | */ 110 | private final Map metaExtensions = Maps.newHashMap(); 111 | 112 | public boolean isStatic() { 113 | return isStatic; 114 | } 115 | 116 | public String getName() { 117 | return name; 118 | } 119 | 120 | public Class getReturnType() { 121 | return returnType; 122 | } 123 | 124 | public MetaType getMetaOwner() { 125 | return metaOwner; 126 | } 127 | 128 | public MetaParameter[] getParameters() { 129 | return parameters; 130 | } 131 | 132 | public MetaAnnotation[] getAnnotations() { 133 | return annotations; 134 | } 135 | 136 | /** 137 | * @return 当前 Method 138 | */ 139 | public Method getMethod() { 140 | if (method != null) { 141 | return method; 142 | } 143 | //https://stackoverflow.com/questions/48113697/getdeclaredmethods-in-class-class 144 | // isBridge() 是为了防止泛型 Override,JVM 生成多个 method 的情况 145 | method = Arrays.stream(metaOwner.getType().getDeclaredMethods()) 146 | .filter(v -> !v.isBridge()) 147 | .filter( 148 | v -> Arrays.stream(v.getAnnotations()).anyMatch(m -> m.annotationType().equals(FastMarkedMethod.class))) 149 | .filter(v -> v.getAnnotation(FastMarkedMethod.class).value() == cacheIndex) 150 | .limit(1) 151 | .findFirst() 152 | .orElseThrow(() -> new RuntimeException( 153 | String.format("[FastAop] %s.%s mark index %s match failed", 154 | metaOwner.getType().getName(), 155 | name, 156 | cacheIndex 157 | ) 158 | )); 159 | method.setAccessible(true); 160 | return method; 161 | } 162 | 163 | /** 164 | * 通过反射获取方法将 paramType 和 returnType 进行打补丁 因为这些TYPE 是 T[][][] 这种多维泛型数组的时候,在语法树处理上面不太好搞,这里直接捕获运行时状态,让其更加的准确 165 | */ 166 | protected void initMethod() { 167 | Method method = getMethod(); 168 | for (int i = 0; i < method.getParameters().length; i++) { 169 | parameters[i].setType(method.getParameters()[i].getType()); 170 | } 171 | returnType = method.getReturnType(); 172 | isStatic = Modifier.isStatic(method.getModifiers()); 173 | name = method.getName(); 174 | } 175 | 176 | public void addMetaExtension(String key, Object value) { 177 | metaExtensions.put(key, value); 178 | } 179 | 180 | public T getMetaExtension(String key) { 181 | // noinspection unchecked 182 | return (T)metaExtensions.get(key); 183 | } 184 | 185 | /** 186 | * 配置是否继续调用下一个切面 Handler,否者直接返回 187 | */ 188 | public void setInvokeMethodType(InvokeMethodType invokeMethodTyp) { 189 | invokeMethodType.set(invokeMethodTyp); 190 | } 191 | 192 | /** 193 | * 是否继续调用下一个 Handler,如果当前 Handler 没有调用 ctx.proceed() 那么返回为 false 194 | */ 195 | public InvokeMethodType getInvokeMethodType() { 196 | return invokeMethodType.get(); 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /fastapt/src/main/java/org/fastlight/apt/model/MetaParameter.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.apt.model; 2 | 3 | /** 4 | * @author ychost@outlook.com 5 | * @date 2021-03-27 6 | */ 7 | public class MetaParameter { 8 | /** 9 | * 参数类型 10 | */ 11 | private Class type; 12 | 13 | /** 14 | * 参数名 15 | */ 16 | private String name; 17 | 18 | /** 19 | * 参数上面的注解信息 20 | */ 21 | private MetaAnnotation[] annotations; 22 | 23 | /** 24 | * 构造一个参数元数据 25 | * 26 | * @param type 参数类型 27 | * @param name 参数名字 28 | * @param annotations 参数上面的注解 29 | * @return 参数元数据 30 | */ 31 | public static MetaParameter create(String name, Object type, MetaAnnotation[] annotations) { 32 | MetaParameter parameter = new MetaParameter(); 33 | if (type instanceof Class) { 34 | parameter.type = (Class)type; 35 | } 36 | parameter.name = name; 37 | parameter.annotations = annotations; 38 | return parameter; 39 | } 40 | 41 | public Class getType() { 42 | return type; 43 | } 44 | 45 | public String getName() { 46 | return name; 47 | } 48 | 49 | // 由于注入的 type 不是很准确,所以在 method 里面通过反射来赋值 50 | void setType(Class type) { 51 | this.type = type; 52 | } 53 | 54 | public MetaAnnotation[] getAnnotations() { 55 | return annotations; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /fastapt/src/main/java/org/fastlight/apt/model/MetaType.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.apt.model; 2 | 3 | import java.lang.annotation.Annotation; 4 | import java.util.Arrays; 5 | 6 | /** 7 | * @author ychost@outlook.com 8 | * @date 2021-03-27 9 | */ 10 | public class MetaType { 11 | /** 12 | * class 的类型 13 | */ 14 | private Class type; 15 | 16 | /** 17 | * 类的注解元素 18 | */ 19 | private MetaAnnotation[] annotations; 20 | 21 | /** 22 | * 构造一个类的元数据 23 | */ 24 | public static MetaType create( 25 | Class type, 26 | MetaAnnotation[] annotations 27 | ) { 28 | MetaType metaType = new MetaType(); 29 | metaType.type = type; 30 | metaType.annotations = annotations; 31 | return metaType; 32 | } 33 | 34 | public Class getType() { 35 | return type; 36 | } 37 | 38 | public MetaAnnotation[] getAnnotations() { 39 | return annotations; 40 | } 41 | 42 | /** 43 | * 是否类上面包含某个注解 44 | */ 45 | public boolean isAnnotated(Class cls) { 46 | return Arrays.stream(annotations).anyMatch(v -> cls.equals(v.getType())); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /fastapt/src/main/java/org/fastlight/apt/model/compile/AnnotationCompile.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.apt.model.compile; 2 | 3 | import com.sun.tools.javac.code.Type; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * 保存编译过程中的注解信息 9 | * 10 | * @author ychost@outlook.com 11 | * @date 2021-03-27 12 | */ 13 | public class AnnotationCompile { 14 | /** 15 | * 注解数据 16 | */ 17 | List infos; 18 | 19 | /** 20 | * 注解类型 21 | */ 22 | private Type type; 23 | 24 | public List getInfos() { 25 | return infos; 26 | } 27 | 28 | public void setInfos(List infos) { 29 | this.infos = infos; 30 | } 31 | 32 | public Type getType() { 33 | return type; 34 | } 35 | 36 | public void setType(Type type) { 37 | this.type = type; 38 | } 39 | 40 | public static class AnnotationInfo { 41 | /** 42 | * 属性名 43 | */ 44 | private String name; 45 | 46 | /** 47 | * 属性值 48 | */ 49 | private Object value; 50 | 51 | /** 52 | * 注解值类型 53 | */ 54 | private Type valueType; 55 | 56 | public String getName() { 57 | return name; 58 | } 59 | 60 | public void setName(String name) { 61 | this.name = name; 62 | } 63 | 64 | public Object getValue() { 65 | return value; 66 | } 67 | 68 | public void setValue(Object value) { 69 | this.value = value; 70 | } 71 | 72 | public Type getValueType() { 73 | return valueType; 74 | } 75 | 76 | public void setValueType(Type valueType) { 77 | this.valueType = valueType; 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /fastapt/src/main/java/org/fastlight/apt/model/compile/ClassCompile.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.apt.model.compile; 2 | 3 | /** 4 | * 保存编译过程中的类信息 5 | * 6 | * @author ychost@outlook.com 7 | * @date 2021-03-27 8 | */ 9 | public class ClassCompile { 10 | } 11 | -------------------------------------------------------------------------------- /fastapt/src/main/java/org/fastlight/apt/model/compile/MethodCompile.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.apt.model.compile; 2 | 3 | import com.google.common.collect.Maps; 4 | import com.sun.tools.javac.code.Symbol; 5 | import com.sun.tools.javac.code.Type; 6 | import com.sun.tools.javac.tree.JCTree.JCMethodDecl; 7 | 8 | import javax.lang.model.element.ExecutableElement; 9 | 10 | import java.util.Map; 11 | 12 | /** 13 | * 保存编译过程中的方法信息 14 | * 15 | * @author ychost@outlook.com 16 | * @date 2021-03-27 17 | */ 18 | public class MethodCompile { 19 | /** 20 | * 父元素 21 | */ 22 | private Symbol.ClassSymbol ownerElement; 23 | 24 | /** 25 | * 方法语法树 26 | */ 27 | private JCMethodDecl methodDecl; 28 | 29 | /** 30 | * 方法元素 31 | */ 32 | private ExecutableElement methodElement; 33 | 34 | /** 35 | * 扩展元素 36 | */ 37 | private Map extensions = Maps.newHashMap(); 38 | 39 | public Type getReturnType() { 40 | return methodDecl.getReturnType().type; 41 | } 42 | 43 | public Symbol.ClassSymbol getOwnerElement() { 44 | return ownerElement; 45 | } 46 | 47 | public void setOwnerElement(Symbol.ClassSymbol ownerElement) { 48 | this.ownerElement = ownerElement; 49 | } 50 | 51 | public JCMethodDecl getMethodDecl() { 52 | return methodDecl; 53 | } 54 | 55 | public void setMethodDecl(JCMethodDecl methodDecl) { 56 | this.methodDecl = methodDecl; 57 | } 58 | 59 | public ExecutableElement getMethodElement() { 60 | return methodElement; 61 | } 62 | 63 | public void setMethodElement(ExecutableElement methodElement) { 64 | this.methodElement = methodElement; 65 | } 66 | 67 | public void addExtension(String key, Object value) { 68 | extensions.put(key, value); 69 | } 70 | 71 | @SuppressWarnings("unchecked") 72 | public T getExtension(String key) { 73 | return (T)extensions.get(key); 74 | } 75 | 76 | public boolean canReturn() { 77 | if (methodDecl.getReturnType() == null || methodDecl.getReturnType().type == null) { 78 | return false; 79 | } 80 | return !"void".equals(methodDecl.getReturnType().type.toString()); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /fastapt/src/main/java/org/fastlight/apt/model/compile/ParameterCompile.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.apt.model.compile; 2 | 3 | import com.sun.tools.javac.code.Type; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * 保存编译过程中的参数信息 9 | * 10 | * @author ychost@outlook.com 11 | * @date 2021-03-27 12 | */ 13 | public class ParameterCompile { 14 | /** 15 | * 参数名 16 | */ 17 | private String name; 18 | 19 | /** 20 | * 参数类型 21 | */ 22 | private Type type; 23 | 24 | /** 25 | * 参数注解 26 | */ 27 | private List annotations; 28 | 29 | public String getName() { 30 | return name; 31 | } 32 | 33 | public void setName(String name) { 34 | this.name = name; 35 | } 36 | 37 | public Type getType() { 38 | return type; 39 | } 40 | 41 | public void setType(Type type) { 42 | this.type = type; 43 | } 44 | 45 | public List getAnnotations() { 46 | return annotations; 47 | } 48 | 49 | public void setAnnotations(List annotations) { 50 | this.annotations = annotations; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /fastapt/src/main/java/org/fastlight/apt/processor/BaseAnnotationProcessor.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.apt.processor; 2 | 3 | import java.util.List; 4 | import java.util.Set; 5 | 6 | import javax.annotation.processing.AbstractProcessor; 7 | import javax.annotation.processing.ProcessingEnvironment; 8 | import javax.annotation.processing.RoundEnvironment; 9 | import javax.lang.model.element.TypeElement; 10 | 11 | /** 12 | * 注解处理的总入口,java 编译器有个优化,同一个元素只会经过一个 processor,所以这里遍历所有元素并给所有处理器执行 13 | * 14 | * @author ychost@outlook.com 15 | * @date 2021-03-27 16 | */ 17 | public abstract class BaseAnnotationProcessor extends AbstractProcessor { 18 | 19 | protected abstract List> getProcessors(); 20 | 21 | @Override 22 | public boolean process(Set ats, RoundEnvironment env) { 23 | if (!env.processingOver()) { 24 | processAnnotations(ats, env); 25 | } else { 26 | processOver(); 27 | } 28 | // 注意由于是处理了 * 所有需要返回 false,否则其它 APT 无法执行 29 | return false; 30 | } 31 | 32 | /** 33 | * roud 完成 34 | */ 35 | protected void processOver() { 36 | getProcessors().forEach(BaseFastProcessor::processOver); 37 | } 38 | 39 | /** 40 | * 处理注解 41 | */ 42 | protected void processAnnotations(Set ats, RoundEnvironment env) { 43 | getProcessors().forEach(v -> v.processAnnotations(ats, env)); 44 | } 45 | 46 | /** 47 | * 初始化注入工具 48 | */ 49 | @Override 50 | public synchronized void init(ProcessingEnvironment environment) { 51 | getProcessors().forEach(v -> v.init(environment)); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /fastapt/src/main/java/org/fastlight/apt/processor/BaseFastProcessor.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.apt.processor; 2 | 3 | import com.google.auto.common.AnnotationMirrors; 4 | import com.google.auto.common.MoreElements; 5 | import com.google.common.collect.Sets; 6 | import com.sun.tools.javac.api.JavacTrees; 7 | import com.sun.tools.javac.processing.JavacProcessingEnvironment; 8 | import com.sun.tools.javac.tree.TreeMaker; 9 | import com.sun.tools.javac.util.Context; 10 | import com.sun.tools.javac.util.Names; 11 | import org.fastlight.apt.util.FastCollections; 12 | import org.fastlight.apt.util.ReflectUtils; 13 | 14 | import javax.annotation.processing.Messager; 15 | import javax.annotation.processing.ProcessingEnvironment; 16 | import javax.annotation.processing.RoundEnvironment; 17 | import javax.annotation.processing.SupportedAnnotationTypes; 18 | import javax.lang.model.element.*; 19 | import javax.tools.Diagnostic; 20 | import java.lang.annotation.Annotation; 21 | import java.util.List; 22 | import java.util.Optional; 23 | import java.util.Set; 24 | 25 | /** 26 | * 提供一些注解处理的基础方法 27 | * 28 | * @author ychost@outlook.com 29 | * @date 2021-03-27 30 | */ 31 | @SuppressWarnings({"unchecked", "UnstableApiUsage", "SameParameterValue"}) 32 | public abstract class BaseFastProcessor { 33 | /** 34 | * 编译时输出日志 35 | */ 36 | public Messager messager; 37 | 38 | /** 39 | * 提取处理元素的语法树 40 | */ 41 | public JavacTrees javacTrees; 42 | 43 | /** 44 | * 语法树处理工具,能够快速生成语法树节点 45 | */ 46 | public TreeMaker treeMaker; 47 | 48 | /** 49 | * 用于构建一些标识符,treeMaker 会用到 50 | */ 51 | public Names names; 52 | 53 | /** 54 | * 处理的全局上下文,可存储一些标志位 55 | */ 56 | public Context context; 57 | 58 | /** 59 | * 可以用来输出文件等等 60 | */ 61 | public ProcessingEnvironment environment; 62 | 63 | /** 64 | * 子类继承的泛型 65 | */ 66 | protected Class atClass; 67 | 68 | /** 69 | * 初始化,注入所需要的所有元素 70 | * 71 | * @param environment 所需要的元素都是通过 env 生成的 72 | */ 73 | public synchronized void init(ProcessingEnvironment environment) { 74 | if (!(environment instanceof JavacProcessingEnvironment)) { 75 | return; 76 | } 77 | this.environment = environment; 78 | this.context = ((JavacProcessingEnvironment) environment).getContext(); 79 | this.names = Names.instance(this.context); 80 | this.messager = environment.getMessager(); 81 | this.treeMaker = TreeMaker.instance(this.context); 82 | this.javacTrees = JavacTrees.instance(environment); 83 | this.atClass = (Class) ReflectUtils.getGenericTypes(getClass())[0]; 84 | } 85 | 86 | /** 87 | * env round 处理完毕回调,一般可用于注解处理完成统一生成文件等功能 88 | */ 89 | public void processOver() { 90 | 91 | } 92 | 93 | /** 94 | * 注解处理入口,这里仅处理 Method 和 Class,要处理其他的元素请 Override 95 | * 96 | * @param ats 元素的注解信息,可能为空 97 | * @param roundEnv 处理工具,能感知到注解相关的元素信息 98 | */ 99 | public void processAnnotations(Set ats, RoundEnvironment roundEnv) { 100 | // 默认情况下仅取出 atClass 相关的元素 101 | Set elements = roundEnv.getElementsAnnotatedWith(atClass); 102 | Set supports = getSupportedAnnotationTypes(); 103 | // 支持任何元素 104 | if (supports.contains("*")) { 105 | elements = roundEnv.getRootElements(); 106 | } 107 | if (FastCollections.isEmpty(elements)) { 108 | return; 109 | } 110 | for (Element element : elements) { 111 | AnnotationMirror atm = getAtMirror(element, atClass); 112 | // 要么注解存在与该元素,要么支持处理任意元素 113 | if (!supports.contains("*") && atm == null) { 114 | continue; 115 | } 116 | if (element instanceof ExecutableElement) { 117 | processExecutableElement((ExecutableElement) element, atm); 118 | } else if (element instanceof TypeElement) { 119 | processTypeElement((TypeElement) element, atm); 120 | } 121 | } 122 | } 123 | 124 | /** 125 | * 方法,构造函数,初始化语句都会进行到这里进行处理 126 | * 127 | * @param executableElement method,constructor,initializer etc.. 128 | * @param atm 注解元素 129 | */ 130 | public abstract void processExecutableElement(ExecutableElement executableElement, AnnotationMirror atm); 131 | 132 | /** 133 | * 处理标注在类/接口上面的元素 134 | * 135 | * @param typeElement class,interface 元素 136 | * @param atm 注解元素 137 | */ 138 | public abstract void processTypeElement(TypeElement typeElement, AnnotationMirror atm); 139 | 140 | /** 141 | * 处理 TypeElement 下面的 ExecutableElement,支持递归,常用语仅对 Method 进行改造,不对 Field 改造 142 | * 143 | * @param typeElement class 或者 interface 元素 144 | * @param atm 注解元素 145 | * @param recursive 是否递归处理,及对子类进行一样的处理 146 | */ 147 | public void processExecutableOfTypeElement(TypeElement typeElement, AnnotationMirror atm, boolean recursive) { 148 | List elements = typeElement.getEnclosedElements(); 149 | for (Element element : elements) { 150 | if (element instanceof ExecutableElement) { 151 | // 防止重复处理,即 class 和 method 同时标注了某个注解 152 | // method 的注解会执行的,所以在 class 的处理上就不处理了 153 | if (element.getAnnotation(atClass) == null) { 154 | processExecutableElement((ExecutableElement) element, atm); 155 | } 156 | // 递归处理,这里一般是处理子类 157 | } else if (recursive && element instanceof TypeElement) { 158 | processTypeElement((TypeElement) element, atm); 159 | } 160 | } 161 | } 162 | 163 | /** 164 | * 获取 element 上面的注解信息,注解的类型是 atClass 165 | * 166 | * @param element 被注解的元素 167 | * @param atClass 注解类型 168 | * @return 注解元素,如果没找到就返回 null 169 | */ 170 | public AnnotationMirror getAtMirror(Element element, Class atClass) { 171 | return MoreElements.getAnnotationMirror(element, atClass).orNull(); 172 | } 173 | 174 | /** 175 | * 获取当前处理器支持的注解,优先走 {@link SupportedAnnotationTypes},然后走继承的注解泛型 176 | */ 177 | public Set getSupportedAnnotationTypes() { 178 | SupportedAnnotationTypes sat = this.getClass().getAnnotation(SupportedAnnotationTypes.class); 179 | if (Optional.ofNullable(sat).map(SupportedAnnotationTypes::value).filter(v -> v.length > 0).isPresent()) { 180 | return Sets.newHashSet(sat.value()); 181 | } 182 | if (atClass == null) { 183 | atClass = (Class) ReflectUtils.getGenericTypes(getClass())[0]; 184 | } 185 | return Sets.newHashSet(atClass.getName()); 186 | } 187 | 188 | /** 189 | * 获取父元素,即包装它的元素,这里仅仅做了强转的判空 190 | */ 191 | public M getOwnerElement(Element element, Class ownerClass) { 192 | if (element == null) { 193 | return null; 194 | } 195 | Element ownerElement = element.getEnclosingElement(); 196 | if (ownerElement == null) { 197 | return null; 198 | } 199 | if (ownerClass.isAssignableFrom(ownerElement.getClass())) { 200 | return (M) ownerElement; 201 | } 202 | return null; 203 | } 204 | 205 | /** 206 | * 获取注解元素的某个属性的值 207 | * 208 | * @param atm 注解元素 209 | * @param field 注解里面的字段名字 210 | * @param 字段类型 211 | * @return 字段的值 212 | */ 213 | public M getAtValueData(AnnotationMirror atm, String field) { 214 | if (atm == null) { 215 | return null; 216 | } 217 | AnnotationValue atv = AnnotationMirrors.getAnnotationValue(atm, field); 218 | return (M) Optional.ofNullable(atv).map(AnnotationValue::getValue).orElse(null); 219 | } 220 | 221 | /** 222 | * 打印 error 信息,同时终止编译 223 | * 224 | * @param message 待打印信息 225 | */ 226 | protected void logError(String message) { 227 | messager.printMessage(Diagnostic.Kind.ERROR, message); 228 | } 229 | 230 | } 231 | -------------------------------------------------------------------------------- /fastapt/src/main/java/org/fastlight/apt/processor/BaseFastSpiProcessor.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.apt.processor; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.File; 5 | import java.io.FileInputStream; 6 | import java.io.IOException; 7 | import java.io.InputStream; 8 | import java.io.InputStreamReader; 9 | import java.lang.annotation.Annotation; 10 | import java.net.URI; 11 | import java.nio.file.Files; 12 | import java.nio.file.Path; 13 | import java.nio.file.Paths; 14 | import java.nio.file.StandardOpenOption; 15 | import java.util.HashSet; 16 | import java.util.Set; 17 | 18 | import javax.annotation.processing.Filer; 19 | import javax.lang.model.element.AnnotationMirror; 20 | import javax.lang.model.element.Element; 21 | import javax.lang.model.element.ExecutableElement; 22 | import javax.lang.model.element.Modifier; 23 | import javax.lang.model.element.PackageElement; 24 | import javax.lang.model.element.TypeElement; 25 | import javax.tools.StandardLocation; 26 | 27 | import com.google.common.base.Joiner; 28 | import com.google.common.collect.HashMultimap; 29 | import com.google.common.collect.Multimap; 30 | import com.google.common.collect.Sets; 31 | import com.sun.tools.javac.code.Symbol.ClassSymbol; 32 | import org.apache.commons.lang3.StringUtils; 33 | 34 | import static com.google.common.base.Charsets.UTF_8; 35 | 36 | /** 37 | * 从 google auto 里面 copy 过来的 38 | * 39 | * @param 40 | * @author ychost 41 | * @see com.google.auto.service.processor.AutoServiceProcessor 42 | */ 43 | public abstract class BaseFastSpiProcessor extends BaseFastProcessor { 44 | 45 | protected Multimap providers = HashMultimap.create(); 46 | 47 | protected Class spiType; 48 | 49 | protected Class spiAnnotationTypes; 50 | 51 | /** 52 | * 注入要生成 SPI 的接口类型 53 | */ 54 | protected abstract Class supportSpiTypes(); 55 | 56 | protected Class supportSpiAnnotationTypes() { 57 | return atClass; 58 | } 59 | 60 | @Override 61 | public void processExecutableElement(ExecutableElement executableElement, AnnotationMirror atm) { 62 | 63 | } 64 | 65 | @Override 66 | public void processTypeElement(TypeElement typeElement, AnnotationMirror atm) { 67 | if (!(typeElement instanceof ClassSymbol)) { 68 | logError("[FastAop] spi only support class symbol"); 69 | return; 70 | } 71 | ClassSymbol classSymbol = (ClassSymbol)typeElement; 72 | if (classSymbol.isInterface()) { 73 | logError( 74 | String.format("[FastAop] %s not support interface to spi %s", atClass, classSymbol.name.toString()) 75 | ); 76 | return; 77 | } 78 | if (!(classSymbol.getEnclosingElement() instanceof PackageElement)) { 79 | if (!classSymbol.getModifiers().contains(Modifier.STATIC)) { 80 | logError(String.format("[FastAop] %s not support inner dynamic class to spi %s", 81 | atClass, 82 | classSymbol.name.toString() 83 | )); 84 | return; 85 | } 86 | } 87 | providers.put(spiType.getName(), getBinaryName(typeElement)); 88 | } 89 | 90 | public BaseFastSpiProcessor() { 91 | spiType = supportSpiTypes(); 92 | spiAnnotationTypes = supportSpiAnnotationTypes(); 93 | } 94 | 95 | @Override 96 | public void processOver() { 97 | try { 98 | generateConfigFiles(); 99 | } catch (Exception e) { 100 | logError("[FastAop] Generate SPI files error"); 101 | throw new RuntimeException(e); 102 | } 103 | } 104 | 105 | /** 106 | * 写入的文件路径,默认是 spi 的路径 107 | */ 108 | protected String getFilePath(String type) { 109 | return getFolderPath() + "/" + type; 110 | } 111 | 112 | protected String getFolderPath() { 113 | return "META-INF/services"; 114 | } 115 | 116 | protected synchronized void generateConfigFiles() throws IOException { 117 | for (String type : providers.keySet()) { 118 | Filer filer = environment.getFiler(); 119 | URI fileUri = filer.getResource(StandardLocation.CLASS_OUTPUT, StringUtils.EMPTY, 120 | getFilePath(type)).toUri(); 121 | File serviceFile = new File(fileUri); 122 | serviceFile.getParentFile().mkdirs(); 123 | Set services = Sets.newTreeSet(); 124 | // 如果文件存在才去读取 125 | if (!serviceFile.createNewFile()) { 126 | // 保障顺序 127 | services = ServicesFiles.readServiceFile(new FileInputStream(serviceFile)); 128 | } 129 | Set newServices = new HashSet<>(providers.get(type)); 130 | if (services.containsAll(newServices)) { 131 | return; 132 | } 133 | services.addAll(newServices); 134 | Path path = Paths.get(fileUri); 135 | Files.write(path, Joiner.on("\n").join(services).getBytes(), StandardOpenOption.APPEND); 136 | } 137 | 138 | } 139 | 140 | protected String getBinaryName(TypeElement element) { 141 | return getBinaryNameImpl(element, element.getSimpleName().toString()); 142 | } 143 | 144 | protected String getBinaryNameImpl(TypeElement element, String className) { 145 | Element enclosingElement = element.getEnclosingElement(); 146 | 147 | if (enclosingElement instanceof PackageElement) { 148 | PackageElement pkg = (PackageElement)enclosingElement; 149 | if (pkg.isUnnamed()) { 150 | return className; 151 | } 152 | return pkg.getQualifiedName() + "." + className; 153 | } 154 | TypeElement typeElement = (TypeElement)enclosingElement; 155 | return getBinaryNameImpl(typeElement, typeElement.getSimpleName() + "$" + className); 156 | } 157 | 158 | static final class ServicesFiles { 159 | static Set readServiceFile(InputStream input) throws IOException { 160 | HashSet serviceClasses = new HashSet(); 161 | try (BufferedReader reader = new BufferedReader(new InputStreamReader(input, UTF_8))) { 162 | String line; 163 | while ((line = reader.readLine()) != null) { 164 | int commentStart = line.indexOf('#'); 165 | if (commentStart >= 0) { 166 | line = line.substring(0, commentStart); 167 | } 168 | line = line.trim(); 169 | if (!line.isEmpty()) { 170 | serviceClasses.add(line); 171 | } 172 | } 173 | return serviceClasses; 174 | } 175 | } 176 | 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /fastapt/src/main/java/org/fastlight/apt/translator/BaseFastTranslator.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.apt.translator; 2 | 3 | import java.util.Locale; 4 | import java.util.Map; 5 | import java.util.Objects; 6 | import java.util.function.Function; 7 | 8 | import javax.annotation.processing.Messager; 9 | import javax.lang.model.element.AnnotationMirror; 10 | import javax.lang.model.element.Modifier; 11 | import javax.lang.model.element.PackageElement; 12 | import javax.tools.Diagnostic; 13 | import javax.tools.Diagnostic.Kind; 14 | 15 | import com.google.auto.common.AnnotationMirrors; 16 | import com.google.common.collect.Lists; 17 | import com.sun.tools.javac.code.Attribute; 18 | import com.sun.tools.javac.code.Attribute.Class; 19 | import com.sun.tools.javac.code.Attribute.Enum; 20 | import com.sun.tools.javac.code.Flags; 21 | import com.sun.tools.javac.code.Symbol; 22 | import com.sun.tools.javac.code.Symbol.MethodSymbol; 23 | import com.sun.tools.javac.code.Symbol.VarSymbol; 24 | import com.sun.tools.javac.code.Type; 25 | import com.sun.tools.javac.code.Type.ArrayType; 26 | import com.sun.tools.javac.code.Type.TypeVar; 27 | import com.sun.tools.javac.code.TypeTag; 28 | import com.sun.tools.javac.comp.Flow.AssignAnalyzer; 29 | import com.sun.tools.javac.tree.JCTree; 30 | import com.sun.tools.javac.tree.JCTree.JCAnnotation; 31 | import com.sun.tools.javac.tree.JCTree.JCCatch; 32 | import com.sun.tools.javac.tree.JCTree.JCClassDecl; 33 | import com.sun.tools.javac.tree.JCTree.JCExpression; 34 | import com.sun.tools.javac.tree.JCTree.JCExpressionStatement; 35 | import com.sun.tools.javac.tree.JCTree.JCFieldAccess; 36 | import com.sun.tools.javac.tree.JCTree.JCIdent; 37 | import com.sun.tools.javac.tree.JCTree.JCMethodDecl; 38 | import com.sun.tools.javac.tree.JCTree.JCMethodInvocation; 39 | import com.sun.tools.javac.tree.JCTree.JCModifiers; 40 | import com.sun.tools.javac.tree.JCTree.JCNewClass; 41 | import com.sun.tools.javac.tree.JCTree.JCStatement; 42 | import com.sun.tools.javac.tree.JCTree.JCThrow; 43 | import com.sun.tools.javac.tree.JCTree.JCVariableDecl; 44 | import com.sun.tools.javac.tree.TreeMaker; 45 | import com.sun.tools.javac.tree.TreeTranslator; 46 | import com.sun.tools.javac.util.List; 47 | import com.sun.tools.javac.util.ListBuffer; 48 | import com.sun.tools.javac.util.Name; 49 | import com.sun.tools.javac.util.Pair; 50 | import org.apache.commons.lang3.StringUtils; 51 | import org.fastlight.apt.annotation.FastMarkedMethod; 52 | import org.fastlight.apt.model.MetaAnnotation; 53 | import org.fastlight.apt.model.MetaMethod; 54 | import org.fastlight.apt.model.MetaParameter; 55 | import org.fastlight.apt.model.MetaType; 56 | import org.fastlight.apt.model.compile.AnnotationCompile; 57 | import org.fastlight.apt.model.compile.MethodCompile; 58 | import org.fastlight.apt.model.compile.ParameterCompile; 59 | import org.fastlight.apt.util.FastCollections; 60 | import org.fastlight.apt.util.FastMaps; 61 | 62 | /** 63 | * 基础的语法树的一些操作方法 64 | * 65 | * @author ychost 66 | * @date 2020-12-03 67 | **/ 68 | @SuppressWarnings("ALL") 69 | public abstract class BaseFastTranslator extends TreeTranslator { 70 | protected final TreeMaker treeMaker; 71 | protected final Name.Table names; 72 | protected final Messager messager; 73 | 74 | protected final JCExpression newMapMethod; 75 | protected final JCExpression createAnnotationMethod; 76 | protected final JCExpression createParamMethod; 77 | 78 | protected MethodCompile ctxCompile; 79 | 80 | public static final String META_OWNER_VAR = "__fast_meta_owner"; 81 | 82 | public void init(MethodCompile ctxCompile) { 83 | this.ctxCompile = ctxCompile; 84 | } 85 | 86 | public static final Map PRIMITIVE_MAP = FastMaps 87 | .newHashMapWithPair( 88 | "int", "java.lang.Integer", 89 | "double", "java.lang.Double", 90 | "boolean", "java.lang.Boolean", 91 | "short", "java.lang.Short", 92 | "byte", "java.lang.Byte", 93 | "char", "java.lang.Character", 94 | "float", "java.lang.Float", 95 | "long", "java.lang.Long" 96 | ); 97 | 98 | public BaseFastTranslator(TreeMaker treeMaker, Name.Table names, Messager messager) { 99 | this.treeMaker = treeMaker; 100 | this.names = names; 101 | this.messager = messager; 102 | newMapMethod = memberAccess("org.fastlight.apt.util.FastMaps.newHashMapWithPair"); 103 | createAnnotationMethod = memberAccess("org.fastlight.apt.model.MetaAnnotation.create"); 104 | createParamMethod = memberAccess("org.fastlight.apt.model.MetaParameter.create"); 105 | } 106 | 107 | /** 108 | * system.out.print 这样可以直接转换成语法树 109 | * 110 | * @param components system.out.print 这种表达式 111 | * @return 表达式语法树 112 | */ 113 | protected JCTree.JCExpression memberAccess(String components) { 114 | // 必须要包装类型才有效 115 | String boxType = PRIMITIVE_MAP.get(components.toLowerCase(Locale.ROOT)); 116 | if (boxType != null) { 117 | components = boxType; 118 | } 119 | String[] componentArray = components.split("\\."); 120 | JCTree.JCExpression expr = treeMaker.Ident(getNameFromString(componentArray[0])); 121 | for (int i = 1; i < componentArray.length; i++) { 122 | expr = treeMaker.Select(expr, getNameFromString(componentArray[i])); 123 | } 124 | return expr; 125 | } 126 | 127 | /** 128 | * 方法上面添加 @FastAspectMethod 方便在运行的时候精确获取 Method 129 | * 130 | * @param methodIndex 方法在 __fast_meta_method 中的索引 131 | */ 132 | protected void markMetaMethodAnnotation(Integer methodIndex) { 133 | if (isMarkedMethod()) { 134 | return; 135 | } 136 | JCAnnotation annotation = treeMaker.Annotation(memberAccess(FastMarkedMethod.class.getName()), 137 | List.of(treeMaker.Assign(memberAccess("value"), treeMaker.Literal(methodIndex))) 138 | ); 139 | ListBuffer annotations = new ListBuffer<>(); 140 | annotations.addAll(ctxCompile.getMethodDecl().mods.annotations); 141 | annotations.add(annotation); 142 | ctxCompile.getMethodDecl().mods.annotations = annotations.toList(); 143 | } 144 | 145 | /** 146 | * 判断方法是否已经被织入过,通过是否添加了特定注解来判断 147 | */ 148 | public boolean isMarkedMethod() { 149 | return ctxCompile.getMethodDecl().mods.annotations.stream().filter(v -> v.type != null) 150 | .anyMatch(v -> v.type.toString().equals(FastMarkedMethod.class.getName())); 151 | } 152 | 153 | /** 154 | * 把 injectStatement 注入到方法的 try catch finally,同时会给方法注入 try catch finally 155 | * 156 | * @param bodyStatements 原有方法体语句 157 | * @param tryStatement 添加 try 的一行语句 158 | * @param catchStatement 添加 catch 的一行语句 159 | * @param finallyStatement 添加 finally 一行语句 160 | * @param catchExceptionClass catch 的 Exception 类名 161 | * @param catchVarName catch 的变量名 162 | * @param startPos {@link AssignAnalyzer#visitVarDef(com.sun.tools.javac.tree.JCTree.JCVariableDecl)} 里面的 163 | * trackback 会判断大于 164 | * startPos 才会对 jcvariable 初始化生效,主要fix catch 变量 165 | * @param throwError catch 住了异常之后是否继续往上面抛,默认 true 166 | */ 167 | protected JCStatement injectTryCatchFinally(List bodyStatements, JCStatement tryStatement, 168 | JCStatement catchStatement, JCStatement finallyStatement, String catchExceptionClass, String catchVarName, 169 | Boolean throwError, int startPos) { 170 | // 注入 try 里面的语句 171 | if (tryStatement != null) { 172 | bodyStatements = injectStart(bodyStatements, tryStatement); 173 | } 174 | List jcCatches = List.nil(); 175 | if (catchStatement != null && catchExceptionClass != null && catchVarName != null) { 176 | // 默认继续抛异常 177 | List catchStatements = List.of(catchStatement); 178 | if (!Boolean.FALSE.equals(throwError)) { 179 | JCThrow jcThrow = treeMaker.Throw(treeMaker.Ident(getNameFromString(catchVarName))); 180 | catchStatements = catchStatements.append(jcThrow); 181 | } 182 | JCVariableDecl catchVar = treeMaker 183 | .VarDef(treeMaker.Modifiers(0), getNameFromString(catchVarName), memberAccess(catchExceptionClass), 184 | null); 185 | // 很重要!,坑了整整两天,找遍全网,最后 debug 源码才发现 186 | // @see com.sun.tools.javac.comp.Flow.AssignAnalyzer.visitVarDef 187 | catchVar.pos = startPos + 1; 188 | JCCatch jcCatch = treeMaker.Catch(catchVar, treeMaker.Block(0, catchStatements)); 189 | jcCatches = List.of(jcCatch); 190 | } 191 | List finallyStatements = List.nil(); 192 | if (finallyStatement != null) { 193 | finallyStatements = List.of(finallyStatement); 194 | } 195 | return treeMaker.Try(treeMaker.Block(0, bodyStatements), jcCatches, treeMaker.Block(0, finallyStatements)); 196 | } 197 | 198 | /** 199 | * 把 injectStatement 注入到方法体第一行,构造函数里面有 super 就只能加入到第二行 200 | * 201 | * @param bodyStatements 方法体原有的所有语句 202 | * @param injectStatement 待注入语句 203 | * @return 插入 statement 之后的所有语句 204 | */ 205 | protected List injectStart(List bodyStatements, JCStatement injectStatement) { 206 | return injectStart(bodyStatements, List.of(injectStatement)); 207 | } 208 | 209 | /** 210 | * 把 injectStatement 注入到方法体第一行,构造函数里面有 super 就只能加入到第二行 211 | * 212 | * @param bodyStatements 方法体原有的所有语句 213 | * @param injectStatements 待注入语句 214 | * @return 插入 statement 之后的所有语句 215 | */ 216 | protected List injectStart(List bodyStatements, List injectStatements) { 217 | JCStatement callSuper = getCallSuperStatement(bodyStatements); 218 | // 新方法体 219 | ListBuffer statements = new ListBuffer<>(); 220 | int start = 0; 221 | if (callSuper != null) { 222 | statements.append(callSuper); 223 | statements.appendList(injectStatements); 224 | start = 1; 225 | } else { 226 | statements.appendList(injectStatements); 227 | } 228 | for (int i = start; i < bodyStatements.size(); i++) { 229 | statements.append(bodyStatements.get(i)); 230 | } 231 | return statements.toList(); 232 | } 233 | 234 | /** 235 | * 把 injectStatement 注入到方法体的最后一行,为了处理 return,try 等情况,这里直接用 try/finally 来实现最后一行 236 | * 237 | * @param bodyStatements 原有方法体语句 238 | * @param injectStatement 待注入语句 239 | * @return 注入之后的方法体语句 240 | */ 241 | protected List injectFinally(List bodyStatements, JCStatement injectStatement) { 242 | JCStatement statement = 243 | injectTryCatchFinally(bodyStatements, null, null, injectStatement, null, null, true, -1); 244 | return List.of(statement); 245 | } 246 | 247 | /** 248 | * 获取方法体中 super() 这一行 249 | * 250 | * @param statements 方法体语句 251 | * @return super() 这一行语句,可能为空,只有构造函数才可能有,因为 super() 必须放到第一行 252 | */ 253 | protected JCStatement getCallSuperStatement(List statements) { 254 | JCStatement callSuper = null; 255 | if (statements.size() > 0) { 256 | if (isConstructorCall(statements.get(0))) { 257 | callSuper = statements.get(0); 258 | } 259 | } 260 | return callSuper; 261 | } 262 | 263 | /** 264 | * 是否是构造函数 265 | */ 266 | protected boolean isConstructorCall(final JCStatement statement) { 267 | if (!(statement instanceof JCExpressionStatement)) { 268 | return false; 269 | } 270 | JCExpression expr = ((JCExpressionStatement)statement).expr; 271 | if (!(expr instanceof JCMethodInvocation)) { 272 | return false; 273 | } 274 | JCExpression invocation = ((JCMethodInvocation)expr).meth; 275 | String name; 276 | if (invocation instanceof JCFieldAccess) { 277 | name = ((JCFieldAccess)invocation).name.toString(); 278 | } else if (invocation instanceof JCIdent) { 279 | name = ((JCIdent)invocation).name.toString(); 280 | } else { 281 | name = ""; 282 | } 283 | 284 | return "super".equals(name) || "this".equals(name); 285 | } 286 | 287 | /** 288 | * 改变方法定义,不用考虑 super() 等特殊情况 289 | * 290 | * @param jcMethodDecl 方法描述 291 | * @param define 定义语句 292 | */ 293 | protected void changeMethodDefine(JCMethodDecl jcMethodDecl, 294 | Function, List> define) { 295 | super.visitMethodDef(jcMethodDecl); 296 | // abstract 或者 interface 不支持切入 297 | if (jcMethodDecl.body == null) { 298 | return; 299 | } 300 | List statements = jcMethodDecl.body.getStatements(); 301 | // 不修改 302 | for (JCStatement statement : statements) { 303 | if (statement.toString().contains("") || jcMethodDecl.name.toString().contains("")) { 304 | return; 305 | } 306 | } 307 | JCStatement callSuper = getCallSuperStatement(statements); 308 | // super() 必须第一行 309 | if (callSuper != null) { 310 | statements = List.from(statements.subList(1, statements.length())); 311 | } 312 | statements = define.apply(statements); 313 | if (callSuper != null) { 314 | statements = List.of(callSuper).appendList(statements); 315 | } 316 | 317 | jcMethodDecl.body = treeMaker.Block(0, statements); 318 | } 319 | 320 | /** 321 | * 调用 String.valueOf(exp) 322 | */ 323 | protected JCExpressionStatement stringValueOf(JCExpression expression) { 324 | return treeMaker 325 | .Exec(treeMaker.Apply(List.nil(), memberAccess("java.lang.String.valueOf"), List.of(expression))); 326 | } 327 | 328 | /** 329 | * @see MetaAnnotation#create(java.lang.Class, Map) 330 | */ 331 | protected JCExpression createAnnotationExpression(AnnotationCompile annotation) { 332 | ListBuffer argsExpressions = new ListBuffer<>(); 333 | for (AnnotationCompile.AnnotationInfo info : annotation.getInfos()) { 334 | argsExpressions.add(treeMaker.Literal(info.getName())); 335 | argsExpressions.add(literalExpression(info.getValue(), info.getValueType().toString())); 336 | } 337 | JCMethodInvocation args = treeMaker.Apply(List.nil(), newMapMethod, argsExpressions.toList()); 338 | return treeMaker 339 | .Apply(List.nil(), createAnnotationMethod, List.of(treeMaker.ClassLiteral(annotation.getType()), args)); 340 | } 341 | 342 | /** 343 | * annotationMirrors -> MetaAnnotation[] expression,支持 defaultValue 344 | */ 345 | protected JCExpression createAnnotationArrayExpression( 346 | java.util.List annotationMirrors) { 347 | if (FastCollections.isEmpty(annotationMirrors)) { 348 | return treeMaker.NewArray(memberAccess(MetaAnnotation.class.getName()), List.nil(), List.nil()); 349 | } 350 | 351 | ListBuffer atCreates = new ListBuffer<>(); 352 | for (AnnotationMirror annotation : annotationMirrors) { 353 | AnnotationCompile annotationCompile = new AnnotationCompile(); 354 | annotationCompile.setInfos(Lists.newArrayList()); 355 | annotationCompile.setType((Type)annotation.getAnnotationType()); 356 | AnnotationMirrors.getAnnotationValuesWithDefaults(annotation).forEach((k, v) -> { 357 | MethodSymbol symbol = (MethodSymbol)k; 358 | AnnotationCompile.AnnotationInfo info = new AnnotationCompile.AnnotationInfo(); 359 | info.setName(k.getSimpleName().toString()); 360 | info.setValue(v.getValue()); 361 | info.setValueType(symbol.type); 362 | annotationCompile.getInfos().add(info); 363 | }); 364 | atCreates.add(createAnnotationExpression(annotationCompile)); 365 | } 366 | return treeMaker.NewArray(memberAccess(MetaAnnotation.class.getName()), List.nil(), atCreates.toList()); 367 | } 368 | 369 | /** 370 | * 修复掉泛型影响 371 | */ 372 | protected JCExpression classLiteral(Type type) { 373 | if (type instanceof ArrayType) { 374 | ArrayType arrayType = (ArrayType)type; 375 | if (arrayType.elemtype.tsym.erasure_field != null) { 376 | return treeMaker.ClassLiteral(type); 377 | } 378 | return treeMaker.Literal(Object.class.getName()); 379 | } 380 | // 处理有上下边界的泛型 381 | if (type instanceof TypeVar) { 382 | type = getTypeFromVar((TypeVar)type); 383 | } 384 | if (type == null) { 385 | return treeMaker.Literal(Object.class.getName()); 386 | } 387 | if (type.tsym.erasure_field == null) { 388 | // 处理原生类型 389 | if (PRIMITIVE_MAP.containsKey(type.toString()) || "void".equals(type.toString())) { 390 | return treeMaker.ClassLiteral(type); 391 | } 392 | // 处理 这种泛型 393 | if (type.toString().contains("<")) { 394 | return treeMaker.Literal(((Symbol.ClassSymbol)type.tsym).flatname.toString()); 395 | } 396 | // 无 package 的类 397 | if (type instanceof Type.ClassType && type.tsym instanceof Symbol.ClassSymbol) { 398 | return treeMaker.ClassLiteral(type); 399 | } 400 | // 实在解析不了就返回 Object 401 | return treeMaker.Literal(Object.class.getName()); 402 | } 403 | return treeMaker.ClassLiteral(type.tsym.erasure_field); 404 | } 405 | 406 | protected Type getTypeFromVar(TypeVar typeVar) { 407 | if (typeVar.bound == null) { 408 | return null; 409 | } 410 | if (typeVar.bound instanceof TypeVar) { 411 | return getTypeFromVar((TypeVar)typeVar.bound); 412 | } 413 | return typeVar.bound; 414 | } 415 | 416 | /** 417 | * 提取注解的编译信息 418 | */ 419 | protected List getAnnotationCompiles(List annotations) { 420 | if (FastCollections.isEmpty(annotations)) { 421 | return List.nil(); 422 | } 423 | ListBuffer metaAnnotations = new ListBuffer<>(); 424 | for (JCAnnotation annotation : annotations) { 425 | AnnotationCompile metaAnnotation = new AnnotationCompile(); 426 | metaAnnotations.add(metaAnnotation); 427 | metaAnnotation.setType(annotation.attribute.type); 428 | metaAnnotation.setInfos(List.nil()); 429 | ListBuffer annotationInfos = new ListBuffer<>(); 430 | if (FastCollections.isEmpty(annotation.attribute.values)) { 431 | continue; 432 | } 433 | for (Pair pair : annotation.attribute.values) { 434 | AnnotationCompile.AnnotationInfo info = new AnnotationCompile.AnnotationInfo(); 435 | info.setName(pair.fst.name.toString()); 436 | info.setValue(pair.snd.getValue()); 437 | info.setValueType(pair.fst.type); 438 | annotationInfos.add(info); 439 | } 440 | metaAnnotation.setInfos(annotationInfos.toList()); 441 | } 442 | return metaAnnotations.toList(); 443 | } 444 | 445 | /** 446 | * @see MetaMethod#getParameters() 447 | */ 448 | protected JCExpression paramsExpression(List params) { 449 | ListBuffer paramsExpression = new ListBuffer<>(); 450 | for (VarSymbol param : params) { 451 | JCExpression atCreate = createAnnotationArrayExpression(param.getAnnotationMirrors()); 452 | JCExpression clsExpression = classLiteral(param.type); 453 | JCExpression paramExpression = treeMaker.Apply(List.nil(), createParamMethod, 454 | List.of(treeMaker.Literal(param.getSimpleName().toString()), clsExpression, atCreate)); 455 | paramsExpression.add(paramExpression); 456 | } 457 | return treeMaker.NewArray(memberAccess(MetaParameter.class.getName()), List.nil(), paramsExpression.toList()); 458 | } 459 | 460 | /** 461 | * @param methodDecl 462 | * @return 463 | * @see FastAspectContext#getArgs() 464 | */ 465 | protected JCExpression argsExpression(JCMethodDecl methodDecl) { 466 | ListBuffer argsExpressions = new ListBuffer<>(); 467 | for (JCVariableDecl param : methodDecl.getParameters()) { 468 | argsExpressions.add(treeMaker.Ident(param.name)); 469 | } 470 | return treeMaker.NewArray(memberAccess(Object.class.getName()), List.nil(), argsExpressions.toList()); 471 | } 472 | 473 | /** 474 | * @see MetaAnnotation#create(java.lang.Class, Map) 475 | * @see FastMaps#newHashMapWithPair(Object...) 476 | */ 477 | protected JCExpression paramCreateExpression(ParameterCompile metaParam) { 478 | ListBuffer atCreates = new ListBuffer<>(); 479 | for (AnnotationCompile annotation : metaParam.getAnnotations()) { 480 | atCreates.add(createAnnotationExpression(annotation)); 481 | } 482 | JCExpression atsCreatedExpression = 483 | treeMaker.NewArray(memberAccess(MetaAnnotation.class.getName()), List.nil(), atCreates.toList()); 484 | return treeMaker.Apply(List.nil(), createParamMethod, 485 | List.of(treeMaker.Literal(metaParam.getName()), treeMaker.Ident(getNameFromString(metaParam.getName())), 486 | treeMaker.ClassLiteral(metaParam.getType()), atsCreatedExpression)); 487 | } 488 | 489 | /** 490 | * 根据 value 和 type 生成表达式 491 | */ 492 | protected JCExpression literalExpression(Object obj, String type) { 493 | String value = obj.toString(); 494 | value = value.replaceAll("^\"", "").replaceAll("\"$", ""); 495 | String lowerType = type.toLowerCase(Locale.ROOT).replaceAll("\\(\\)", ""); 496 | // 数组特殊处理 497 | if (lowerType.contains("[]")) { 498 | ListBuffer expressions = new ListBuffer<>(); 499 | type = type.replaceAll("<.*>", "").replace("[]", ""); 500 | if (obj instanceof java.util.List) { 501 | java.util.List list = (java.util.List)obj; 502 | for (Object data : list) { 503 | expressions.add(literalExpression(data, type)); 504 | } 505 | } else { 506 | expressions.add(literalExpression(obj, type)); 507 | } 508 | type = type.replaceAll("<.*>", "").replaceAll("\\[\\]", "").replaceAll("\\(\\)", ""); 509 | return treeMaker.NewArray( 510 | // Class[] -> Class 511 | memberAccess(type), List.nil(), expressions.toList()); 512 | } else if ("java.lang.string".equals(lowerType)) { 513 | return treeMaker.Literal(value); 514 | } else if ("int".equals(lowerType)) { 515 | return treeMaker.Literal(Integer.valueOf(value)); 516 | } else if ("long".equals(lowerType)) { 517 | value = value.replaceAll("(?i)l", ""); 518 | return treeMaker.Literal(Long.valueOf(value)); 519 | } else if ("double".equals(lowerType)) { 520 | value = value.replaceAll("(?i)d", ""); 521 | return treeMaker.Literal(Double.valueOf(value)); 522 | } else if ("float".equals(lowerType)) { 523 | value = value.replaceAll("(?i)f", ""); 524 | return treeMaker.Literal(Float.valueOf(value)); 525 | } else if ("short".equals(lowerType)) { 526 | return treeMaker.Literal(Short.valueOf(value)); 527 | } else if ("byte".equals(lowerType)) { 528 | return treeMaker.Literal(Byte.valueOf(value)); 529 | } else if ("boolean".equals(lowerType)) { 530 | return treeMaker.Literal(Boolean.valueOf(value)); 531 | } else if (lowerType.contains("java.lang.class")) { 532 | if (obj instanceof Type) { 533 | return classLiteral((Type)obj); 534 | } 535 | if (obj instanceof Class) { 536 | return classLiteral(((Class)obj).classType); 537 | } 538 | return treeMaker.Literal(value + ".class"); 539 | } else if (obj instanceof Enum) { 540 | return treeMaker.QualIdent(((Enum)obj).value); 541 | } 542 | return treeMaker.Literal(value); 543 | } 544 | 545 | /** 546 | * @see MetaMethod#create(Integer, MetaType, MetaParameter[], MetaAnnotation[], Map) 547 | */ 548 | protected JCExpression newMetaExpression(Integer metaIndex) { 549 | return treeMaker.Apply( 550 | List.nil(), 551 | memberAccess(getCreateMethod(MetaMethod.class)), 552 | List.of(treeMaker.Literal(metaIndex), 553 | metaOwnerExpression(), 554 | paramsExpression(), 555 | methodAnnotationsExpression(), 556 | metaExtensionExpression()) 557 | ); 558 | } 559 | 560 | /** 561 | * 扩展元素 562 | */ 563 | protected JCExpression metaExtensionExpression() { 564 | return treeMaker.Apply(List.nil(), newMapMethod, List.nil()); 565 | } 566 | 567 | /** 568 | * @see FastAspectContext#getOwner() 569 | */ 570 | protected JCExpression ownerExpression() { 571 | if (ctxCompile.getMethodElement().getModifiers().contains(Modifier.STATIC)) { 572 | return treeMaker.Literal(TypeTag.BOT, null); 573 | } 574 | return treeMaker.Ident(getNameFromString("this")); 575 | } 576 | 577 | /** 578 | * @see MetaType#create(java.lang.Class, MetaAnnotation[]) 579 | */ 580 | protected JCExpression metaOwnerExpression() { 581 | return memberAccess(META_OWNER_VAR); 582 | } 583 | 584 | /** 585 | * @see MetaMethod#getReturnType() 586 | */ 587 | protected JCExpression returnTypeExpression() { 588 | return classLiteral(ctxCompile.getReturnType()); 589 | } 590 | 591 | /** 592 | * @see MetaMethod#getAnnotations() 593 | */ 594 | protected JCExpression methodAnnotationsExpression() { 595 | return createAnnotationArrayExpression(ctxCompile.getMethodElement().getAnnotationMirrors()); 596 | } 597 | 598 | /** 599 | * @see MetaMethod#getParameters() 600 | */ 601 | protected JCExpression paramsExpression() { 602 | return paramsExpression((List)ctxCompile.getMethodElement().getParameters()); 603 | } 604 | 605 | /** 606 | * @see MetaMethod#isStatic() 607 | */ 608 | protected JCExpression isStaticExpression() { 609 | if (ctxCompile.getMethodElement().getModifiers().contains(Modifier.STATIC)) { 610 | return treeMaker.Literal(true); 611 | } 612 | return treeMaker.Literal(false); 613 | } 614 | 615 | /** 616 | * @see MetaMethod#getName() 617 | */ 618 | protected JCExpression methodNameExpression() { 619 | return treeMaker.Literal(ctxCompile.getMethodDecl().name.toString()); 620 | } 621 | 622 | /** 623 | * 获取 defs 中类型为 JcVariableDecl 且名字为 name 的变量 624 | */ 625 | protected JCVariableDecl getVar(List defs, String name) { 626 | if (FastCollections.isEmpty(defs)) { 627 | return null; 628 | } 629 | return defs.stream().filter( 630 | v -> v instanceof JCVariableDecl && Objects.equals(name, ((JCVariableDecl)v).name.toString())) 631 | .findFirst() 632 | .map(v -> (JCVariableDecl)v) 633 | .orElse(null); 634 | } 635 | 636 | /** 637 | * 添加一个 metwOwner 静态变量,类型为 {@link MetaType} 638 | */ 639 | public void addMetaOwnerVar(JCClassDecl jcClassDecl) { 640 | if (getVar(jcClassDecl.defs, META_OWNER_VAR) != null) { 641 | return; 642 | } 643 | // new Object(){} 644 | JCNewClass anonymousClass = treeMaker.NewClass( 645 | null, 646 | List.nil(), 647 | memberAccess(Object.class.getName()), 648 | List.nil(), 649 | treeMaker.ClassDef( 650 | treeMaker.Modifiers(0), 651 | getNameFromString(StringUtils.EMPTY), 652 | List.nil(), 653 | null, 654 | List.nil(), 655 | List.nil() 656 | )); 657 | 658 | // new Object(){}.getClass().getEnclosingClass() 659 | JCExpression getClass = treeMaker.Apply( 660 | List.nil(), 661 | treeMaker.Select(anonymousClass, getNameFromString("getClass")), 662 | List.nil() 663 | ); 664 | // new Object(){}.getClass().get 665 | JCExpression ownerTypeExpression = treeMaker.Apply( 666 | List.nil(), 667 | treeMaker.Select(getClass, getNameFromString("getEnclosingClass")), 668 | List.nil() 669 | ); 670 | JCModifiers modifiers = treeMaker.Modifiers(getClassFinalModifiers()); 671 | JCExpression annotations = createAnnotationArrayExpression(ctxCompile.getOwnerElement().getAnnotationMirrors()); 672 | // 添加变量定义 673 | JCVariableDecl ownerTypeVar = treeMaker.VarDef( 674 | modifiers, 675 | getNameFromString(META_OWNER_VAR), 676 | memberAccess(MetaType.class.getName()), 677 | treeMaker.Apply( 678 | List.nil(), 679 | memberAccess(getCreateMethod(MetaType.class)), 680 | List.of(ownerTypeExpression, annotations) 681 | ) 682 | ); 683 | addClassVar(jcClassDecl, ownerTypeVar); 684 | } 685 | 686 | /** 687 | * 给一个类增加一个变量 688 | */ 689 | protected void addClassVar(JCClassDecl jcClassDecl, JCVariableDecl jcVariableDecl) { 690 | if (getVar(jcClassDecl.defs, jcClassDecl.name.toString()) != null) { 691 | logError(String.format("duplicate var %s for lcass %s", jcVariableDecl.name.toString(), 692 | jcClassDecl.name.toString()) 693 | ); 694 | return; 695 | } 696 | jcClassDecl.defs = jcClassDecl.defs.append(jcVariableDecl); 697 | } 698 | 699 | /** 700 | * 根据当前类元素的状态生成不同的访问权限 701 | * 1. 普通类生成是 private static final 702 | * 2. 动态内部类生成的是 private final 703 | * 3. 接口生成的是 static final 704 | */ 705 | protected long getClassFinalModifiers() { 706 | long modifiers = Flags.PRIVATE; 707 | if (ctxCompile.getOwnerElement().isInterface()) { 708 | modifiers = 0; 709 | } 710 | boolean isInnerClass = !(ctxCompile.getOwnerElement().getEnclosingElement() instanceof PackageElement); 711 | boolean isStaticClass = ctxCompile.getOwnerElement().getModifiers().contains(Modifier.STATIC); 712 | if (!isInnerClass || isStaticClass) { 713 | modifiers = modifiers | Flags.STATIC; 714 | } 715 | modifiers = modifiers | Flags.FINAL; 716 | return modifiers; 717 | } 718 | 719 | /** 720 | * 是否包含某个方法,可注入 checker 判断重载 721 | */ 722 | public boolean containMethod(JCClassDecl jcClassDecl, String method, Function checker) { 723 | for (JCTree def : jcClassDecl.defs) { 724 | if (def instanceof JCMethodDecl && method.equals(((JCMethodDecl)def).name.toString())) { 725 | if (checker != null && Boolean.TRUE.equals(checker.apply((JCMethodDecl)def))) { 726 | return true; 727 | } 728 | } 729 | } 730 | return false; 731 | } 732 | 733 | /** 734 | * String -> Name 735 | * 736 | * @param str 常规的字符串 737 | */ 738 | protected Name getNameFromString(String str) { 739 | return names.fromString(str); 740 | } 741 | 742 | /** 743 | * 打印 debug 信息,方便调试 744 | * 745 | * @param message 待打印信息 746 | */ 747 | protected void logDebug(String message) { 748 | messager.printMessage(Diagnostic.Kind.NOTE, message); 749 | } 750 | 751 | /** 752 | * 打印 warn 消息 753 | * 754 | * @param message 755 | */ 756 | protected void logWarn(String message) { 757 | messager.printMessage(Kind.WARNING, message); 758 | } 759 | 760 | /** 761 | * 打印 error 信息,同时终止编译 762 | * 763 | * @param message 待打印信息 764 | */ 765 | protected void logError(String message) { 766 | messager.printMessage(Kind.ERROR, message); 767 | } 768 | 769 | /** 770 | * 获取 xxx.create 方法 771 | */ 772 | protected String getCreateMethod(java.lang.Class cls) { 773 | return cls.getName() + ".create"; 774 | } 775 | 776 | } 777 | -------------------------------------------------------------------------------- /fastapt/src/main/java/org/fastlight/apt/util/FastCollections.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.apt.util; 2 | 3 | import java.util.Collection; 4 | 5 | /** 6 | * @author ychost@outlook.com 7 | * @date 2021-03-28 8 | */ 9 | public class FastCollections { 10 | public static boolean isEmpty(Collection collection) { 11 | return collection == null || collection.isEmpty(); 12 | } 13 | 14 | public static int size(Collection collection) { 15 | if (isEmpty(collection)) { 16 | return 0; 17 | } 18 | return collection.size(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /fastapt/src/main/java/org/fastlight/apt/util/FastMaps.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.apt.util; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | /** 7 | * 提供一些便捷的 Map 工具方法 8 | * 9 | * @author ychost@outlook.com 10 | * @date 2021-03-27 11 | */ 12 | @SuppressWarnings({"unchecked", "rawtypes"}) 13 | public class FastMaps { 14 | /** 15 | * 将数组转成 map,k1,v2,k2,v2 16 | * 17 | * @param kvPairs kv 数组 18 | * @return map 结果 19 | */ 20 | public static HashMap newHashMapWithPair(Object... kvPairs) { 21 | HashMap map = new HashMap<>(); 22 | if (kvPairs.length % 2 != 0) { 23 | throw new RuntimeException("[newHashMapWithPair] kvPairs.length error"); 24 | } 25 | for (int i = 0; i < kvPairs.length; i += 2) { 26 | map.put(kvPairs[i], kvPairs[i + 1]); 27 | } 28 | return map; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /fastapt/src/main/java/org/fastlight/apt/util/ReflectUtils.java: -------------------------------------------------------------------------------- 1 | package org.fastlight.apt.util; 2 | 3 | import com.google.common.collect.Maps; 4 | import org.apache.commons.lang3.ClassUtils; 5 | import org.apache.commons.lang3.StringUtils; 6 | 7 | import java.lang.reflect.Array; 8 | import java.lang.reflect.Field; 9 | import java.lang.reflect.ParameterizedType; 10 | import java.lang.reflect.Type; 11 | import java.util.Arrays; 12 | import java.util.Collections; 13 | import java.util.Map; 14 | 15 | /** 16 | * @author ychost 17 | * @date 2020-03-20 18 | **/ 19 | public class ReflectUtils { 20 | /** 21 | * 原生类型解析,比如 V,Z,B 这些都是字节码的东西 22 | */ 23 | public static final Map> PRIMITIVE_CLASS; 24 | 25 | public static final Map> CLASS_CACHE = Maps.newConcurrentMap(); 26 | 27 | /** 28 | * int/double 等映射 I/D 字节码东西 29 | */ 30 | public static final Map PRIMITIVE_CLASS_NAME; 31 | 32 | static { 33 | Map> primitiveClass = Maps.newHashMap(); 34 | primitiveClass.put("V", Void.TYPE); 35 | primitiveClass.put("Z", Boolean.TYPE); 36 | primitiveClass.put("B", Byte.TYPE); 37 | primitiveClass.put("C", Character.TYPE); 38 | primitiveClass.put("S", Short.TYPE); 39 | primitiveClass.put("I", Integer.TYPE); 40 | primitiveClass.put("L", Long.TYPE); 41 | primitiveClass.put("F", Float.TYPE); 42 | primitiveClass.put("D", Double.TYPE); 43 | PRIMITIVE_CLASS = Collections.unmodifiableMap(primitiveClass); 44 | } 45 | 46 | static { 47 | Map map = Maps.newHashMap(); 48 | map.put("void", "V"); 49 | map.put("boolean", "Z"); 50 | map.put("byte", "B"); 51 | map.put("char", "C"); 52 | map.put("short", "S"); 53 | map.put("int", "I"); 54 | map.put("long", "L"); 55 | map.put("float", "F"); 56 | map.put("double", "D"); 57 | PRIMITIVE_CLASS_NAME = map; 58 | } 59 | 60 | /** 61 | * 获取 Class 里面的 A,B,C 62 | */ 63 | public static Type[] getGenericTypes(Class cls) { 64 | Type type = cls.getGenericSuperclass(); 65 | ParameterizedType pt = (ParameterizedType) type; 66 | return pt.getActualTypeArguments(); 67 | } 68 | 69 | /** 70 | * 代理 {@link Class#forName(String, boolean, ClassLoader)},支持原生类型 71 | * 72 | * @param clsName 73 | * @param initialize 74 | * @param classLoader 75 | * @return 76 | */ 77 | public static Class forName(String clsName, boolean initialize, ClassLoader classLoader) 78 | throws ClassNotFoundException { 79 | clsName = resolveClassName(clsName); 80 | Class primitiveType = PRIMITIVE_CLASS.get(clsName); 81 | if (primitiveType != null) { 82 | return primitiveType; 83 | } 84 | return Class.forName(clsName, initialize, classLoader); 85 | } 86 | 87 | /** 88 | * 兼容编译过程中的类名 89 | */ 90 | public static String resolveClassName(String className) { 91 | String name = PRIMITIVE_CLASS_NAME.get(className); 92 | if (StringUtils.isNotBlank(name)) { 93 | return name; 94 | } 95 | if (PRIMITIVE_CLASS.containsKey(className)) { 96 | return className; 97 | } 98 | // 去除泛型,比如 Map<> -> Map 99 | int grStart = StringUtils.indexOf(className, "<"); 100 | if (grStart > 0) { 101 | className = className.substring(0, grStart); 102 | } 103 | // 数组处理比较特殊 104 | // java.lang.String[] -> [Ljava.lang.String; 105 | // int[] -> [I; 106 | if (className.endsWith("[]")) { 107 | int dim = StringUtils.countMatches(className, "["); 108 | String prefix = StringUtils.repeat("[", dim); 109 | String midName = className.replaceAll("\\[\\]", ""); 110 | if (PRIMITIVE_CLASS_NAME.containsKey(midName)) { 111 | midName = PRIMITIVE_CLASS_NAME.get(midName); 112 | return prefix + midName; 113 | } 114 | return prefix + "L" + midName + ";"; 115 | } 116 | return className; 117 | } 118 | 119 | /** 120 | * 带缓存,可提升性能,注意用的默认的 classLoader 121 | */ 122 | public static Class forNameCache(String clsName) { 123 | try { 124 | Class cls = CLASS_CACHE.get(clsName); 125 | if (cls != null) { 126 | return cls; 127 | } 128 | cls = forName(clsName, true, ReflectUtils.class.getClassLoader()); 129 | CLASS_CACHE.put(clsName, cls); 130 | return cls; 131 | } catch (ClassNotFoundException e) { 132 | return null; 133 | } 134 | } 135 | 136 | /** 137 | * 给 obj 里面的某种类型的字段赋默认值 138 | * 139 | * @param recursive 是否递归给 obj 的对象属性遍历复制,只能当 filedType 是 primaryType 才支持!! 140 | * 因为不加这个限制极有可能死循环 141 | */ 142 | public static void assignDefault( 143 | Object obj, 144 | Class assignType, 145 | T assignValue, 146 | boolean recursive) throws IllegalAccessException { 147 | if (obj == null || (!ClassUtils.isPrimitiveOrWrapper(assignType) && recursive)) { 148 | return; 149 | } 150 | Field[] fields = obj.getClass().getDeclaredFields(); 151 | for (Field field : fields) { 152 | Class type = field.getType(); 153 | field.setAccessible(true); 154 | Object val = field.get(obj); 155 | if (type == assignType && val == null) { 156 | field.set(obj, assignValue); 157 | } else if (recursive && !ClassUtils.isPrimitiveOrWrapper(type)) { 158 | assignDefault(val, assignType, assignValue, recursive); 159 | } 160 | } 161 | } 162 | 163 | /** 164 | * new 一个数组类,支持多维数组,比如 int[][][].class 165 | * 166 | * @param cls int[][][].class 167 | * @param length 每一维的长度 168 | * @param 169 | * @return 170 | */ 171 | @SuppressWarnings("unchecked") 172 | 173 | public static T newArrayInstance(Class cls, int length) { 174 | if (!cls.isArray()) { 175 | return null; 176 | } 177 | int cnt = 1; 178 | Class cmptType = cls.getComponentType(); 179 | while (!cmptType.isArray()) { 180 | cmptType = cmptType.getComponentType(); 181 | cnt += 1; 182 | } 183 | int[] dimensions = new int[cnt]; 184 | Arrays.fill(dimensions, length); 185 | return (T) Array.newInstance(cmptType, dimensions); 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.fastlight 8 | fastaop-parent 9 | pom 10 | 1.0.2-SNAPSHOT 11 | 12 | fastapt 13 | fastaop 14 | example 15 | 16 | 17 | 18 | 8 19 | 8 20 | 1.0.2-SNAPSHOT 21 | UTF-8 22 | 23 | fastaop-parent 24 | java fastaop parent dependencies 25 | https://github.com/fast-light/fastaop 26 | 27 | 28 | scm:git:https://github.com/fast-light/fastaop.git 29 | 30 | 31 | scm:git:https://github.com/fast-light/fastaop.git 32 | 33 | https://github.com/fast-light/fastaop 34 | 1.0.0 35 | 36 | 37 | 38 | MIT License 39 | http://www.opensource.org/licenses/mit-license.php 40 | 41 | 42 | 43 | 44 | ychost 45 | ychost@outlook.com 46 | fastlight 47 | https://fastlight.org 48 | 49 | 50 | 51 | 52 | 53 | org.fastlight 54 | fastaop 55 | ${fast.version} 56 | 57 | 58 | org.fastlight 59 | fastapt 60 | ${fast.version} 61 | 62 | 63 | org.projectlombok 64 | lombok 65 | 1.18.16 66 | 67 | 68 | 69 | org.apache.commons 70 | commons-collections4 71 | 4.4 72 | 73 | 74 | org.apache.commons 75 | commons-lang3 76 | 3.9 77 | 78 | 79 | 80 | com.google.code.findbugs 81 | jsr305 82 | 3.0.2 83 | 84 | 85 | com.google.auto.service 86 | auto-service 87 | 1.0-rc7 88 | 89 | 90 | com.google.guava 91 | guava 92 | 21.0 93 | 94 | 95 | junit 96 | junit 97 | 4.13 98 | test 99 | 100 | 101 | 102 | 103 | 104 | 105 | ossrh 106 | https://s01.oss.sonatype.org/content/repositories/snapshots 107 | 108 | 109 | ossrh 110 | https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/ 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | src/main/resources 124 | true 125 | 126 | 127 | 128 | 129 | 130 | org.sonatype.plugins 131 | nexus-staging-maven-plugin 132 | 1.6.8 133 | true 134 | 135 | ossrh 136 | https://s01.oss.sonatype.org/ 137 | true 138 | 139 | 140 | 141 | 142 | org.apache.maven.plugins 143 | maven-source-plugin 144 | 2.2.1 145 | 146 | 147 | compile 148 | 149 | jar 150 | 151 | 152 | 153 | 154 | 155 | org.apache.maven.plugins 156 | maven-surefire-plugin 157 | 2.22.0 158 | 159 | 160 | 161 | org.apache.maven.plugins 162 | maven-javadoc-plugin 163 | 3.2.0 164 | 165 | 166 | 167 | -Xdoclint:none 168 | 169 | 170 | 171 | 172 | attach-javadocs 173 | 174 | jar 175 | 176 | 177 | 178 | 179 | 180 | org.apache.maven.plugins 181 | maven-gpg-plugin 182 | 1.6 183 | 184 | 185 | sign-artifacts 186 | verify 187 | 188 | sign 189 | 190 | 191 | 192 | 193 | 194 | 195 | -------------------------------------------------------------------------------- /readme-zh.md: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 | 6 |
7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 |
15 | Java 轻量级 AOP 框架 16 |
17 | 18 |
19 | 中文文档    English 20 |
21 | 22 | 23 | ## 简介 24 | 25 | FastAop 是一款基于 Java Annotation Processing 的轻量级 AOP 框架,其原理和 Lombok 类似 26 | 27 | ## 特性 28 | 29 | - 📦 开箱即用,适用于任意项目 30 | - 🚀 基于 Java Annotation Processing,运行时无性能损耗 31 | - ⚡️ 兼容 private/protected/static 等各种修饰符的方法 32 | 33 | ## 使用 34 | 35 | [FastAop 使用教程](https://fast-light.github.io/zh-CN). 36 | 37 | ## 编译项目 38 | 39 | ``` 40 | $ mvn clean install 41 | ``` 42 | 43 | IDEA 配置 44 | 45 | ``` 46 | setting->build->compiler->Shared build process VM options: -Djps.track.ap.dependencies=false 47 | ``` 48 | 49 | ## 说明 50 | 51 | FastAop 目前仅支持 Java8,暂不支持其它版本,后面会逐步对 Java9+ 进行支持适配 52 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 |
6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 | Java lightweight AOP framework 16 |
17 |
18 | 中文文档    English 19 |
20 | 21 | ## Intro 22 | 23 | A lightweight AOP framework based on Java Annotation Processing, Its principle is similar to that of Lombok 24 | 25 | ## Features 26 | 27 | - 📦 Out of the box, compatible with any project 28 | - 🚀 Based on Java Annotation Processing, high-performance 29 | - ⚡️ Suitable for arbitrary modifiers methods, like private,protected,static etc.. 30 | 31 | ## Guide 32 | 33 | please visit [FastAop Guide](https://fast-light.github.io/). 34 | 35 | ## Development 36 | 37 | ``` 38 | $ mvn clean install 39 | ``` 40 | 41 | IDEA setting 42 | 43 | ``` 44 | setting->build->compiler->Shared build process VM options: -Djps.track.ap.dependencies=false 45 | ``` 46 | 47 | ## Note 48 | 49 | FastAop currently only supports Java 8, and does not support other versions at the moment. Later, it will gradually support and adapt to Java 9+ 50 | -------------------------------------------------------------------------------- /resource/Alibaba-CodeStyle.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | -------------------------------------------------------------------------------- /resource/aop-debug.sh: -------------------------------------------------------------------------------- 1 | alias debug="mvnDebug clean install -Dmaven.test.skip=true" 2 | alias install="mvn clean install -Dmaven.test.skip=true" 3 | install && \ 4 | cd ../example && debug -------------------------------------------------------------------------------- /resource/aop-dev.sh: -------------------------------------------------------------------------------- 1 | alias install="mvn clean install -Dmaven.test.skip=true" 2 | install && \ 3 | cd ../example && install -------------------------------------------------------------------------------- /resource/install.sh: -------------------------------------------------------------------------------- 1 | alias install="mvn clean install -Dmaven.test.skip=true" 2 | cd ../fastapt && install && \ 3 | cd ../fastaop && install -------------------------------------------------------------------------------- /resource/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fast-light/fastaop/b4c9e3bf339a0bd8927e95e812f387355e28c4a7/resource/logo.png --------------------------------------------------------------------------------