├── .codacy.yml ├── docs └── dreamlu-weixin.jpg ├── .github ├── renovate.json ├── PULL_REQUEST_TEMPLATE ├── ISSUE_TEMPLATE │ └── issue.yml └── workflows │ ├── test-and-build.yml │ └── publish-snapshot.yml ├── src ├── test │ ├── resources │ │ └── test │ │ │ ├── spring.factories │ │ │ └── MyProcessor.java │ └── java │ │ └── net │ │ └── dreamlu │ │ └── mica │ │ └── auto │ │ └── service │ │ └── AutoServiceProcessorTest.java └── main │ └── java │ └── net │ └── dreamlu │ └── mica │ └── auto │ ├── annotation │ ├── AutoIgnore.java │ ├── AutoListener.java │ ├── AutoFailureAnalyzer.java │ ├── AutoConfigDataLoader.java │ ├── AutoRunListener.java │ ├── AutoEnvPostProcessor.java │ ├── AutoLoggingSystemFactory.java │ ├── AutoTemplateProvider.java │ ├── AutoConfigImportFilter.java │ ├── AutoContextInitializer.java │ ├── AutoEnableCircuitBreaker.java │ ├── AutoConfigDataLocationResolver.java │ ├── AutoDatabaseInitializerDetector.java │ ├── AotBeanRegistration.java │ ├── AotRuntimeHintsRegistrar.java │ ├── AotBeanFactoryInitialization.java │ ├── AutoDependsOnDatabaseInitializationDetector.java │ └── AutoService.java │ ├── common │ ├── AotAutoType.java │ ├── MultiSetMap.java │ ├── BootAutoType.java │ └── AbstractMicaProcessor.java │ ├── service │ ├── ServicesFiles.java │ └── AutoServiceProcessor.java │ ├── aot │ ├── FactoriesFiles.java │ └── AotFactoriesProcessor.java │ └── factories │ ├── FactoriesFiles.java │ └── AutoFactoriesProcessor.java ├── deploy.sh ├── .editorconfig ├── .idea └── icon.svg ├── .gitignore ├── README.md ├── CHANGELOG.md ├── README_EN.md ├── LICENSE └── pom.xml /.codacy.yml: -------------------------------------------------------------------------------- 1 | --- 2 | exclude_paths: 3 | - 'gradle/**' 4 | - '**.md' 5 | - '**/test/**' 6 | -------------------------------------------------------------------------------- /docs/dreamlu-weixin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lets-mica/mica-auto/HEAD/docs/dreamlu-weixin.jpg -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:recommended" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /src/test/resources/test/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 2 | net.dreamlu.mica.metrics.druid.DruidMetricsConfiguration,\ 3 | net.dreamlu.mica.metrics.undertow.UndertowMetricsConfiguration 4 | 5 | org.springframework.context.ApplicationListener= 6 | -------------------------------------------------------------------------------- /deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ## 1. java version 4 | export JAVA_HOME=`/usr/libexec/java_home -v 17` 5 | java -version 6 | printf "\n" 7 | 8 | ## 2. gradle version 9 | mvn -version 10 | printf "\n" 11 | 12 | ## 3. 环境 13 | if [ -z $1 ]; then 14 | profile="release" 15 | else 16 | profile="$1" 17 | fi 18 | 19 | ## 4. deploy 发布正式版 20 | mvn clean deploy -P$profile -DskipTests 21 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | # 空格替代Tab缩进在各种编辑工具下效果一致 5 | [*] 6 | indent_style = space 7 | indent_size = 4 8 | charset = utf-8 9 | end_of_line = lf 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | 13 | [*.java] 14 | indent_style = tab 15 | 16 | [*.{json,yml}] 17 | indent_size = 2 18 | 19 | [*.md] 20 | insert_final_newline = false 21 | trim_trailing_whitespace = false 22 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE: -------------------------------------------------------------------------------- 1 | **注意:github 上的少,可能响应不够及时,建议优先 gitee 上发起** 2 | 3 | **What kind of change does this PR introduce?** (check at least one) 4 | 5 | - [ ] Bugfix(bug修复) 6 | - [ ] Feature(新功能) 7 | - [ ] Code style update(代码格式调整) 8 | - [ ] Refactor(重构) 9 | - [ ] Build-related changes(与构建相关的更改) 10 | - [ ] Other, please describe(其他,请说明): 11 | 12 | 13 | **The description of the PR(PR描述):** 14 | 15 | 16 | **Other information(其他信息):** 17 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/issue.yml: -------------------------------------------------------------------------------- 1 | name: "问题咨询|反馈" 2 | description: "请尽可能详细的描述问题,提供足够的上下文" 3 | labels: ["question"] 4 | body: 5 | - type: dropdown 6 | id: version 7 | attributes: 8 | label: 版本 9 | options: 10 | - "3.x" 11 | - "2.x" 12 | validations: 13 | required: true 14 | - type: textarea 15 | id: desired-solution 16 | attributes: 17 | label: 问题描述(具体版本号和使用场景,注意:描述不清一句话问题直接关闭) 18 | description: 详细问题,具体版本号和使用场景,提供相应截图和日志 19 | validations: 20 | required: true 21 | -------------------------------------------------------------------------------- /.github/workflows/test-and-build.yml: -------------------------------------------------------------------------------- 1 | name: Java CI 2 | permissions: 3 | contents: read 4 | on: [push, pull_request] 5 | 6 | jobs: 7 | build: 8 | runs-on: ubuntu-latest 9 | strategy: 10 | matrix: 11 | java: [ '17', '21' ] 12 | name: Java ${{ matrix.Java }} build 13 | steps: 14 | - uses: actions/checkout@v6 15 | - uses: actions/setup-java@v5 16 | with: 17 | distribution: 'zulu' 18 | java-version: ${{ matrix.java }} 19 | cache: 'maven' 20 | cache-dependency-path: 'pom.xml' 21 | - name: Build with Maven 22 | run: mvn package -P !develop 23 | -------------------------------------------------------------------------------- /.idea/icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### gradle ### 2 | .gradle 3 | !gradle/wrapper/gradle-wrapper.jar 4 | 5 | ### STS ### 6 | .settings/ 7 | .apt_generated 8 | .classpath 9 | .factorypath 10 | .project 11 | .settings 12 | .springBeans 13 | bin/ 14 | 15 | ### IntelliJ IDEA ### 16 | !.idea/icon.svg 17 | .idea 18 | out/ 19 | *.iws 20 | *.iml 21 | *.ipr 22 | 23 | ### NetBeans ### 24 | nbproject/private/ 25 | build/ 26 | nbbuild/ 27 | dist/ 28 | nbdist/ 29 | .nb-gradle/ 30 | 31 | ### maven ### 32 | target/ 33 | *.war 34 | *.ear 35 | *.zip 36 | *.tar 37 | *.tar.gz 38 | 39 | # logs # 40 | logs 41 | 42 | # temp ignore 43 | *.log 44 | *.cache 45 | *.diff 46 | *.patch 47 | *.tmp 48 | *.java~ 49 | *.properties~ 50 | *.xml~ 51 | 52 | # system ignore 53 | .DS_Store 54 | Thumbs.db 55 | Servers 56 | .metadata 57 | upload 58 | gen_code 59 | -------------------------------------------------------------------------------- /src/main/java/net/dreamlu/mica/auto/annotation/AutoIgnore.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net). 3 | *

4 | * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.gnu.org/licenses/lgpl.html 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.dreamlu.mica.auto.annotation; 18 | 19 | import java.lang.annotation.Documented; 20 | import java.lang.annotation.Retention; 21 | import java.lang.annotation.Target; 22 | 23 | import static java.lang.annotation.ElementType.TYPE; 24 | import static java.lang.annotation.RetentionPolicy.SOURCE; 25 | 26 | /** 27 | * AutoIgnore 处理 28 | * 29 | * @author L.cm 30 | */ 31 | @Documented 32 | @Retention(SOURCE) 33 | @Target(TYPE) 34 | public @interface AutoIgnore { 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/net/dreamlu/mica/auto/annotation/AutoListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net). 3 | *

4 | * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.gnu.org/licenses/lgpl.html 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.dreamlu.mica.auto.annotation; 18 | 19 | import java.lang.annotation.Documented; 20 | import java.lang.annotation.Retention; 21 | import java.lang.annotation.Target; 22 | 23 | import static java.lang.annotation.ElementType.TYPE; 24 | import static java.lang.annotation.RetentionPolicy.SOURCE; 25 | 26 | /** 27 | * ApplicationListener 处理 28 | * 29 | * @author L.cm 30 | */ 31 | @Documented 32 | @Retention(SOURCE) 33 | @Target(TYPE) 34 | public @interface AutoListener { 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/net/dreamlu/mica/auto/common/AotAutoType.java: -------------------------------------------------------------------------------- 1 | package net.dreamlu.mica.auto.common; 2 | 3 | import lombok.Getter; 4 | import lombok.RequiredArgsConstructor; 5 | import net.dreamlu.mica.auto.annotation.AotBeanFactoryInitialization; 6 | import net.dreamlu.mica.auto.annotation.AotBeanRegistration; 7 | import net.dreamlu.mica.auto.annotation.AotRuntimeHintsRegistrar; 8 | 9 | /** 10 | * aot 11 | * 12 | * @author L.cm 13 | */ 14 | @Getter 15 | @RequiredArgsConstructor 16 | public enum AotAutoType { 17 | 18 | /** 19 | * RuntimeHintsRegistrar 添加到 aot.factories 20 | */ 21 | RUNTIME_HINTS_REGISTRAR(AotRuntimeHintsRegistrar.class.getName(), "org.springframework.aot.hint.RuntimeHintsRegistrar"), 22 | /** 23 | * BeanRegistrationAotProcessor 添加到 aot.factories 24 | */ 25 | BEAN_REGISTRATION(AotBeanRegistration.class.getName(), "org.springframework.beans.factory.aot.BeanRegistrationAotProcessor"), 26 | /** 27 | * BeanFactoryInitializationAotProcessor 添加到 aot.factories 28 | */ 29 | BEAN_FACTORY_INITIALIZATION(AotBeanFactoryInitialization.class.getName(), "org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor"); 30 | 31 | private final String annotation; 32 | private final String configureKey; 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/net/dreamlu/mica/auto/annotation/AutoFailureAnalyzer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net). 3 | *

4 | * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.gnu.org/licenses/lgpl.html 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.dreamlu.mica.auto.annotation; 18 | 19 | import java.lang.annotation.Documented; 20 | import java.lang.annotation.Retention; 21 | import java.lang.annotation.Target; 22 | 23 | import static java.lang.annotation.ElementType.TYPE; 24 | import static java.lang.annotation.RetentionPolicy.SOURCE; 25 | 26 | /** 27 | * FailureAnalyzer 处理 28 | * 29 | * @author L.cm 30 | */ 31 | @Documented 32 | @Retention(SOURCE) 33 | @Target(TYPE) 34 | public @interface AutoFailureAnalyzer { 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/net/dreamlu/mica/auto/annotation/AutoConfigDataLoader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net). 3 | *

4 | * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.gnu.org/licenses/lgpl.html 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.dreamlu.mica.auto.annotation; 18 | 19 | import java.lang.annotation.Documented; 20 | import java.lang.annotation.Retention; 21 | import java.lang.annotation.Target; 22 | 23 | import static java.lang.annotation.ElementType.TYPE; 24 | import static java.lang.annotation.RetentionPolicy.SOURCE; 25 | 26 | /** 27 | * ConfigDataLoader 28 | * 29 | * @author L.cm 30 | */ 31 | @Documented 32 | @Retention(SOURCE) 33 | @Target(TYPE) 34 | public @interface AutoConfigDataLoader { 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/net/dreamlu/mica/auto/annotation/AutoRunListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net). 3 | *

4 | * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.gnu.org/licenses/lgpl.html 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.dreamlu.mica.auto.annotation; 18 | 19 | import java.lang.annotation.Documented; 20 | import java.lang.annotation.Retention; 21 | import java.lang.annotation.Target; 22 | 23 | import static java.lang.annotation.ElementType.TYPE; 24 | import static java.lang.annotation.RetentionPolicy.SOURCE; 25 | 26 | /** 27 | * SpringApplicationRunListener 处理 28 | * 29 | * @author L.cm 30 | */ 31 | @Documented 32 | @Retention(SOURCE) 33 | @Target(TYPE) 34 | public @interface AutoRunListener { 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/net/dreamlu/mica/auto/annotation/AutoEnvPostProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net). 3 | *

4 | * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.gnu.org/licenses/lgpl.html 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.dreamlu.mica.auto.annotation; 18 | 19 | import java.lang.annotation.Documented; 20 | import java.lang.annotation.Retention; 21 | import java.lang.annotation.Target; 22 | 23 | import static java.lang.annotation.ElementType.TYPE; 24 | import static java.lang.annotation.RetentionPolicy.SOURCE; 25 | 26 | /** 27 | * EnvironmentPostProcessor 处理 28 | * 29 | * @author L.cm 30 | */ 31 | @Documented 32 | @Retention(SOURCE) 33 | @Target(TYPE) 34 | public @interface AutoEnvPostProcessor { 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/net/dreamlu/mica/auto/annotation/AutoLoggingSystemFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net). 3 | *

4 | * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.gnu.org/licenses/lgpl.html 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.dreamlu.mica.auto.annotation; 18 | 19 | import java.lang.annotation.Documented; 20 | import java.lang.annotation.Retention; 21 | import java.lang.annotation.Target; 22 | 23 | import static java.lang.annotation.ElementType.TYPE; 24 | import static java.lang.annotation.RetentionPolicy.SOURCE; 25 | 26 | /** 27 | * LoggingSystemFactory 处理 28 | * 29 | * @author L.cm 30 | */ 31 | @Documented 32 | @Retention(SOURCE) 33 | @Target(TYPE) 34 | public @interface AutoLoggingSystemFactory { 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/net/dreamlu/mica/auto/annotation/AutoTemplateProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net). 3 | *

4 | * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.gnu.org/licenses/lgpl.html 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.dreamlu.mica.auto.annotation; 18 | 19 | import java.lang.annotation.Documented; 20 | import java.lang.annotation.Retention; 21 | import java.lang.annotation.Target; 22 | 23 | import static java.lang.annotation.ElementType.TYPE; 24 | import static java.lang.annotation.RetentionPolicy.SOURCE; 25 | 26 | /** 27 | * TemplateAvailabilityProvider 处理 28 | * 29 | * @author L.cm 30 | */ 31 | @Documented 32 | @Retention(SOURCE) 33 | @Target(TYPE) 34 | public @interface AutoTemplateProvider { 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/net/dreamlu/mica/auto/annotation/AutoConfigImportFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net). 3 | *

4 | * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.gnu.org/licenses/lgpl.html 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.dreamlu.mica.auto.annotation; 18 | 19 | import java.lang.annotation.Documented; 20 | import java.lang.annotation.Retention; 21 | import java.lang.annotation.Target; 22 | 23 | import static java.lang.annotation.ElementType.TYPE; 24 | import static java.lang.annotation.RetentionPolicy.SOURCE; 25 | 26 | /** 27 | * AutoConfigurationImportFilter 处理 28 | * 29 | * @author L.cm 30 | */ 31 | @Documented 32 | @Retention(SOURCE) 33 | @Target(TYPE) 34 | public @interface AutoConfigImportFilter { 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/net/dreamlu/mica/auto/annotation/AutoContextInitializer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net). 3 | *

4 | * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.gnu.org/licenses/lgpl.html 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.dreamlu.mica.auto.annotation; 18 | 19 | import java.lang.annotation.Documented; 20 | import java.lang.annotation.Retention; 21 | import java.lang.annotation.Target; 22 | 23 | import static java.lang.annotation.ElementType.TYPE; 24 | import static java.lang.annotation.RetentionPolicy.SOURCE; 25 | 26 | /** 27 | * ApplicationContextInitializer 处理 28 | * 29 | * @author L.cm 30 | */ 31 | @Documented 32 | @Retention(SOURCE) 33 | @Target(TYPE) 34 | public @interface AutoContextInitializer { 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/net/dreamlu/mica/auto/annotation/AutoEnableCircuitBreaker.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net). 3 | *

4 | * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.gnu.org/licenses/lgpl.html 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.dreamlu.mica.auto.annotation; 18 | 19 | import java.lang.annotation.Documented; 20 | import java.lang.annotation.Retention; 21 | import java.lang.annotation.Target; 22 | 23 | import static java.lang.annotation.ElementType.TYPE; 24 | import static java.lang.annotation.RetentionPolicy.SOURCE; 25 | 26 | /** 27 | * EnableCircuitBreaker 28 | * 29 | * @author L.cm 30 | */ 31 | @Documented 32 | @Retention(SOURCE) 33 | @Target(TYPE) 34 | public @interface AutoEnableCircuitBreaker { 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/net/dreamlu/mica/auto/annotation/AutoConfigDataLocationResolver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net). 3 | *

4 | * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.gnu.org/licenses/lgpl.html 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.dreamlu.mica.auto.annotation; 18 | 19 | import java.lang.annotation.Documented; 20 | import java.lang.annotation.Retention; 21 | import java.lang.annotation.Target; 22 | 23 | import static java.lang.annotation.ElementType.TYPE; 24 | import static java.lang.annotation.RetentionPolicy.SOURCE; 25 | 26 | /** 27 | * ConfigDataLocationResolver 28 | * 29 | * @author L.cm 30 | */ 31 | @Documented 32 | @Retention(SOURCE) 33 | @Target(TYPE) 34 | public @interface AutoConfigDataLocationResolver { 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/net/dreamlu/mica/auto/annotation/AutoDatabaseInitializerDetector.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net). 3 | *

4 | * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.gnu.org/licenses/lgpl.html 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.dreamlu.mica.auto.annotation; 18 | 19 | import java.lang.annotation.Documented; 20 | import java.lang.annotation.Retention; 21 | import java.lang.annotation.Target; 22 | 23 | import static java.lang.annotation.ElementType.TYPE; 24 | import static java.lang.annotation.RetentionPolicy.SOURCE; 25 | 26 | /** 27 | * DatabaseInitializerDetector 处理 28 | * 29 | * @author L.cm 30 | */ 31 | @Documented 32 | @Retention(SOURCE) 33 | @Target(TYPE) 34 | public @interface AutoDatabaseInitializerDetector { 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/net/dreamlu/mica/auto/annotation/AotBeanRegistration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net). 3 | *

4 | * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.gnu.org/licenses/lgpl.html 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.dreamlu.mica.auto.annotation; 18 | 19 | import java.lang.annotation.Documented; 20 | import java.lang.annotation.Retention; 21 | import java.lang.annotation.Target; 22 | 23 | import static java.lang.annotation.ElementType.TYPE; 24 | import static java.lang.annotation.RetentionPolicy.SOURCE; 25 | 26 | /** 27 | * org.springframework.beans.factory.aot.BeanRegistrationAotProcessor 28 | * 29 | * @author L.cm 30 | */ 31 | @Documented 32 | @Retention(SOURCE) 33 | @Target(TYPE) 34 | public @interface AotBeanRegistration { 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/net/dreamlu/mica/auto/annotation/AotRuntimeHintsRegistrar.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net). 3 | *

4 | * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.gnu.org/licenses/lgpl.html 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.dreamlu.mica.auto.annotation; 18 | 19 | import java.lang.annotation.Documented; 20 | import java.lang.annotation.Retention; 21 | import java.lang.annotation.Target; 22 | 23 | import static java.lang.annotation.ElementType.TYPE; 24 | import static java.lang.annotation.RetentionPolicy.SOURCE; 25 | 26 | /** 27 | * aot org.springframework.aot.hint.RuntimeHintsRegistrar 28 | * 29 | * @author L.cm 30 | */ 31 | @Documented 32 | @Retention(SOURCE) 33 | @Target(TYPE) 34 | public @interface AotRuntimeHintsRegistrar { 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/net/dreamlu/mica/auto/annotation/AotBeanFactoryInitialization.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net). 3 | *

4 | * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.gnu.org/licenses/lgpl.html 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.dreamlu.mica.auto.annotation; 18 | 19 | import java.lang.annotation.Documented; 20 | import java.lang.annotation.Retention; 21 | import java.lang.annotation.Target; 22 | 23 | import static java.lang.annotation.ElementType.TYPE; 24 | import static java.lang.annotation.RetentionPolicy.SOURCE; 25 | 26 | /** 27 | * aot org.springframework.beans.factory.aot.BeanRegistrationAotProcessor 28 | * 29 | * @author L.cm 30 | */ 31 | @Documented 32 | @Retention(SOURCE) 33 | @Target(TYPE) 34 | public @interface AotBeanFactoryInitialization { 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/net/dreamlu/mica/auto/annotation/AutoDependsOnDatabaseInitializationDetector.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net). 3 | *

4 | * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.gnu.org/licenses/lgpl.html 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.dreamlu.mica.auto.annotation; 18 | 19 | import java.lang.annotation.Documented; 20 | import java.lang.annotation.Retention; 21 | import java.lang.annotation.Target; 22 | 23 | import static java.lang.annotation.ElementType.TYPE; 24 | import static java.lang.annotation.RetentionPolicy.SOURCE; 25 | 26 | /** 27 | * DependsOnDatabaseInitializationDetector 处理 28 | * 29 | * @author L.cm 30 | */ 31 | @Documented 32 | @Retention(SOURCE) 33 | @Target(TYPE) 34 | public @interface AutoDependsOnDatabaseInitializationDetector { 35 | } 36 | -------------------------------------------------------------------------------- /src/test/resources/test/MyProcessor.java: -------------------------------------------------------------------------------- 1 | package test; 2 | 3 | import net.dreamlu.mica.auto.annotation.AutoService; 4 | 5 | import javax.annotation.processing.Completion; 6 | import javax.annotation.processing.ProcessingEnvironment; 7 | import javax.annotation.processing.Processor; 8 | import javax.annotation.processing.RoundEnvironment; 9 | import javax.lang.model.SourceVersion; 10 | import javax.lang.model.element.AnnotationMirror; 11 | import javax.lang.model.element.Element; 12 | import javax.lang.model.element.ExecutableElement; 13 | import javax.lang.model.element.TypeElement; 14 | import java.util.Set; 15 | 16 | @AutoService(Processor.class) 17 | public class MyProcessor implements Processor { 18 | 19 | @Override 20 | public Set getSupportedOptions() { 21 | return null; 22 | } 23 | 24 | @Override 25 | public Set getSupportedAnnotationTypes() { 26 | return null; 27 | } 28 | 29 | @Override 30 | public SourceVersion getSupportedSourceVersion() { 31 | return null; 32 | } 33 | 34 | @Override 35 | public void init(ProcessingEnvironment processingEnv) { 36 | 37 | } 38 | 39 | @Override 40 | public boolean process(Set annotations, RoundEnvironment roundEnv) { 41 | return false; 42 | } 43 | 44 | @Override 45 | public Iterable getCompletions(Element element, AnnotationMirror annotation, ExecutableElement member, String userText) { 46 | return null; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/test/java/net/dreamlu/mica/auto/service/AutoServiceProcessorTest.java: -------------------------------------------------------------------------------- 1 | package net.dreamlu.mica.auto.service; 2 | 3 | import com.google.testing.compile.Compilation; 4 | import com.google.testing.compile.Compiler; 5 | import com.google.testing.compile.JavaFileObjects; 6 | import org.junit.Test; 7 | import org.junit.runner.RunWith; 8 | import org.junit.runners.JUnit4; 9 | 10 | import javax.tools.StandardLocation; 11 | 12 | import static com.google.testing.compile.CompilationSubject.assertThat; 13 | 14 | /** 15 | * use google compile-testing Tests the {@link AutoServiceProcessor}. 16 | * 17 | * @author L.cm 18 | */ 19 | @RunWith(JUnit4.class) 20 | public class AutoServiceProcessorTest { 21 | 22 | @Test 23 | public void autoService() { 24 | Compilation compilation = 25 | Compiler.javac() 26 | // 选择注解处理器 27 | .withProcessors(new AutoServiceProcessor()) 28 | // 选择需要处理的代码 29 | .compile(JavaFileObjects.forResource("test/MyProcessor.java")); 30 | // 断言是否成功 31 | assertThat(compilation).succeededWithoutWarnings(); 32 | // 断言生成的内容, compile-testing 默认是生成到了内存中 33 | assertThat(compilation) 34 | // 选择生成的配置文件,如果是生成 java 文件可以使用 generatedSourceFile 方法 35 | .generatedFile(StandardLocation.CLASS_OUTPUT, "META-INF/services/javax.annotation.processing.Processor") 36 | // 转换成 utf-8 字符串然后进行比较 37 | .contentsAsUtf8String() 38 | // 由于生成的文件尾部有个 writer.newLine() 在各个平台不一样,所以采用 startsWith 39 | .contains("test.MyProcessor"); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/net/dreamlu/mica/auto/annotation/AutoService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2008 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.dreamlu.mica.auto.annotation; 18 | 19 | import java.lang.annotation.*; 20 | 21 | /** 22 | * An annotation for service providers as described in {@link java.util.ServiceLoader}. The {@link 23 | * net.dreamlu.mica.auto.service.AutoServiceProcessor} generates the configuration files which 24 | * allows service providers to be loaded with {@link java.util.ServiceLoader#load(Class)}. 25 | * 26 | *

Service providers assert that they conform to the service provider specification. 27 | * Specifically, they must: 28 | * 29 | *

34 | * 35 | * @author google 36 | */ 37 | @Documented 38 | @Retention(RetentionPolicy.SOURCE) 39 | @Target(ElementType.TYPE) 40 | public @interface AutoService { 41 | /** 42 | * Returns the interfaces implemented by this service provider. 43 | * 44 | * @return interface array 45 | */ 46 | Class[] value(); 47 | } 48 | -------------------------------------------------------------------------------- /.github/workflows/publish-snapshot.yml: -------------------------------------------------------------------------------- 1 | name: Publish Snapshot 2 | permissions: 3 | contents: read 4 | on: 5 | push: 6 | branches: [ master ] 7 | pull_request: 8 | branches: [ master ] 9 | 10 | jobs: 11 | publish: 12 | runs-on: ubuntu-latest 13 | outputs: 14 | should_continue: ${{ steps.check.outputs.is_snapshot }} 15 | steps: 16 | - uses: actions/checkout@v6 17 | - name: Extract Maven version 18 | id: check 19 | run: | 20 | # 提取项目 标签中的内容(在 mica-auto 之后的第一个 version) 21 | VERSION=$(sed -n '/mica-auto<\/artifactId>/,//{s/.*\(.*\)<\/version>.*/\1/p}' pom.xml | head -1 | tr -d ' ') 22 | echo "Extracted version: $VERSION" 23 | # 检查是否为 SNAPSHOT 24 | if [[ "$VERSION" == *"SNAPSHOT"* ]]; then 25 | echo "is_snapshot=true" >> $GITHUB_OUTPUT 26 | echo "SNAPSHOT version [$VERSION]" 27 | fi 28 | - uses: actions/setup-java@v5 29 | if: ${{ steps.check.outputs.is_snapshot }} 30 | with: 31 | distribution: 'zulu' 32 | java-version: 17 33 | cache: 'maven' 34 | cache-dependency-path: 'pom.xml' 35 | server-id: central 36 | server-username: MAVEN_USERNAME 37 | server-password: MAVEN_PASSWORD 38 | gpg-passphrase: MAVEN_GPG_PASSWORD 39 | gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} 40 | - name: Publish to the Maven Central Repository 41 | if: ${{ steps.check.outputs.is_snapshot }} 42 | run: chmod +x ./deploy.sh && ./deploy.sh snapshot 43 | env: 44 | MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }} 45 | MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }} 46 | MAVEN_GPG_PASSWORD: ${{ secrets.MAVEN_GPG_PASSWORD }} 47 | -------------------------------------------------------------------------------- /src/main/java/net/dreamlu/mica/auto/service/ServicesFiles.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net). 3 | *

4 | * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.gnu.org/licenses/lgpl.html 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.dreamlu.mica.auto.service; 18 | 19 | import lombok.experimental.UtilityClass; 20 | 21 | import javax.lang.model.util.Elements; 22 | import javax.tools.FileObject; 23 | import java.io.*; 24 | import java.nio.charset.Charset; 25 | import java.nio.charset.StandardCharsets; 26 | import java.util.*; 27 | 28 | /** 29 | * A helper class for reading and writing Services files. 30 | * 31 | * @author L.cm 32 | */ 33 | @UtilityClass 34 | class ServicesFiles { 35 | private static final Charset UTF_8 = StandardCharsets.UTF_8; 36 | 37 | /** 38 | * Reads the set of service classes from a service file. 39 | * 40 | * @param fileObject not {@code null}. Closed after use. 41 | * @return a not {@code null Set} of service class names. 42 | * @throws IOException 43 | */ 44 | protected static Set readServiceFile(FileObject fileObject, Elements elementUtils) throws IOException { 45 | HashSet serviceClasses = new HashSet<>(); 46 | try ( 47 | InputStream input = fileObject.openInputStream(); 48 | InputStreamReader isr = new InputStreamReader(input, UTF_8); 49 | BufferedReader r = new BufferedReader(isr) 50 | ) { 51 | String line; 52 | while ((line = r.readLine()) != null) { 53 | // 跳过注释行 54 | int commentStart = line.indexOf('#'); 55 | if (commentStart >= 0) { 56 | continue; 57 | } 58 | line = line.trim(); 59 | // 校验是否删除文件 60 | if (!line.isEmpty() && Objects.nonNull(elementUtils.getTypeElement(line))) { 61 | serviceClasses.add(line); 62 | } 63 | } 64 | return serviceClasses; 65 | } 66 | } 67 | 68 | /** 69 | * Writes the set of service class names to a service file. 70 | * 71 | * @param output not {@code null}. Not closed after use. 72 | * @param services a not {@code null Collection} of service class names. 73 | * @throws IOException 74 | */ 75 | protected static void writeServiceFile(Collection services, OutputStream output) throws IOException { 76 | BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(output, UTF_8)); 77 | List serviceList = new ArrayList<>(services); 78 | Collections.sort(serviceList); 79 | for (String service : serviceList) { 80 | writer.write(service); 81 | writer.newLine(); 82 | } 83 | writer.flush(); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/net/dreamlu/mica/auto/common/MultiSetMap.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net). 3 | *

4 | * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.gnu.org/licenses/lgpl.html 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.dreamlu.mica.auto.common; 18 | 19 | import java.util.*; 20 | 21 | /** 22 | * MultiSetMap 23 | * 24 | * @author L.cm 25 | */ 26 | public class MultiSetMap { 27 | private transient final Map> map; 28 | 29 | public MultiSetMap() { 30 | map = new HashMap<>(); 31 | } 32 | 33 | private Set createSet() { 34 | return new HashSet<>(); 35 | } 36 | 37 | /** 38 | * put to MultiSetMap 39 | * 40 | * @param key 键 41 | * @param value 值 42 | * @return boolean 43 | */ 44 | public boolean put(K key, V value) { 45 | Set set = map.get(key); 46 | if (set == null) { 47 | set = createSet(); 48 | if (set.add(value)) { 49 | map.put(key, set); 50 | return true; 51 | } else { 52 | throw new AssertionError("New set violated the set spec"); 53 | } 54 | } else { 55 | return set.add(value); 56 | } 57 | } 58 | 59 | /** 60 | * 是否包含某个key 61 | * 62 | * @param key key 63 | * @return 结果 64 | */ 65 | public boolean containsKey(K key) { 66 | return map.containsKey(key); 67 | } 68 | 69 | /** 70 | * 是否包含 value 中的某个值 71 | * 72 | * @param value value 73 | * @return 是否包含 74 | */ 75 | public boolean containsVal(V value) { 76 | Collection> values = map.values(); 77 | return values.stream().anyMatch(vs -> vs.contains(value)); 78 | } 79 | 80 | /** 81 | * key 集合 82 | * 83 | * @return keys 84 | */ 85 | public Set keySet() { 86 | return map.keySet(); 87 | } 88 | 89 | /** 90 | * put list to MultiSetMap 91 | * 92 | * @param key 键 93 | * @param set 值列表 94 | * @return boolean 95 | */ 96 | public boolean putAll(K key, Set set) { 97 | if (set == null) { 98 | return false; 99 | } 100 | Set vSet = map.computeIfAbsent(key, k -> createSet()); 101 | vSet.addAll(set); 102 | return true; 103 | } 104 | 105 | /** 106 | * put MultiSetMap to MultiSetMap 107 | * 108 | * @param data MultiSetMap 109 | * @return boolean 110 | */ 111 | public boolean putAll(MultiSetMap data) { 112 | if (data == null || data.isEmpty()) { 113 | return false; 114 | } else { 115 | for (K k : data.keySet()) { 116 | this.putAll(k, data.get(k)); 117 | } 118 | return true; 119 | } 120 | } 121 | 122 | /** 123 | * get List by key 124 | * 125 | * @param key 键 126 | * @return List 127 | */ 128 | public Set get(K key) { 129 | return map.get(key); 130 | } 131 | 132 | /** 133 | * clear MultiSetMap 134 | */ 135 | public void clear() { 136 | map.clear(); 137 | } 138 | 139 | /** 140 | * isEmpty 141 | * 142 | * @return isEmpty 143 | */ 144 | public boolean isEmpty() { 145 | return map.isEmpty(); 146 | } 147 | 148 | @Override 149 | public String toString() { 150 | return map.toString(); 151 | } 152 | 153 | } 154 | -------------------------------------------------------------------------------- /src/main/java/net/dreamlu/mica/auto/aot/FactoriesFiles.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net). 3 | *

4 | * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.gnu.org/licenses/lgpl.html 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.dreamlu.mica.auto.aot; 18 | 19 | import lombok.experimental.UtilityClass; 20 | import net.dreamlu.mica.auto.common.MultiSetMap; 21 | 22 | import javax.lang.model.util.Elements; 23 | import javax.tools.FileObject; 24 | import java.io.*; 25 | import java.nio.charset.Charset; 26 | import java.nio.charset.StandardCharsets; 27 | import java.util.*; 28 | import java.util.stream.Collectors; 29 | 30 | /** 31 | * spring boot 自动化配置工具类 32 | * 33 | * @author L.cm 34 | */ 35 | @UtilityClass 36 | class FactoriesFiles { 37 | private static final Charset UTF_8 = StandardCharsets.UTF_8; 38 | 39 | /** 40 | * 读取 spring.factories 文件 41 | * 42 | * @param fileObject FileObject 43 | * @return MultiSetMap 44 | * @throws IOException 异常信息 45 | */ 46 | protected static MultiSetMap readFactoriesFile(FileObject fileObject, Elements elementUtils) throws IOException { 47 | // 读取 spring.factories 内容 48 | Properties properties = new Properties(); 49 | try (InputStream input = fileObject.openInputStream()) { 50 | properties.load(input); 51 | } 52 | MultiSetMap multiSetMap = new MultiSetMap<>(); 53 | Set> entrySet = properties.entrySet(); 54 | for (Map.Entry objectEntry : entrySet) { 55 | String key = (String) objectEntry.getKey(); 56 | String value = (String) objectEntry.getValue(); 57 | if (value == null || value.trim().isEmpty()) { 58 | continue; 59 | } 60 | // 解析 spring.factories 61 | String[] values = value.split(","); 62 | Set valueSet = Arrays.stream(values) 63 | .filter(v -> !v.isEmpty()) 64 | .map(String::trim) 65 | // 校验是否删除文件 66 | .filter((v) -> Objects.nonNull(elementUtils.getTypeElement(v))) 67 | .collect(Collectors.toSet()); 68 | multiSetMap.putAll(key.trim(), valueSet); 69 | } 70 | return multiSetMap; 71 | } 72 | 73 | /** 74 | * 写出 spring.factories 文件 75 | * 76 | * @param factories factories 信息 77 | * @param output 输出流 78 | * @throws IOException 异常信息 79 | */ 80 | protected static void writeFactoriesFile(MultiSetMap factories, 81 | OutputStream output) throws IOException { 82 | BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(output, UTF_8)); 83 | writer.write("# Generated by mica-auto www.dreamlu.net\n"); 84 | Set keySet = factories.keySet(); 85 | for (String key : keySet) { 86 | Set values = factories.get(key); 87 | if (values == null || values.isEmpty()) { 88 | continue; 89 | } 90 | writer.write(key); 91 | writer.write("=\\\n "); 92 | StringJoiner joiner = new StringJoiner(",\\\n "); 93 | for (String value : values) { 94 | joiner.add(value); 95 | } 96 | writer.write(joiner.toString()); 97 | writer.newLine(); 98 | } 99 | writer.flush(); 100 | } 101 | 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/net/dreamlu/mica/auto/common/BootAutoType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net). 3 | *

4 | * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.gnu.org/licenses/lgpl.html 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.dreamlu.mica.auto.common; 18 | 19 | import lombok.Getter; 20 | import lombok.RequiredArgsConstructor; 21 | import net.dreamlu.mica.auto.annotation.*; 22 | 23 | /** 24 | * 注解类型 25 | * 26 | * @author L.cm 27 | */ 28 | @Getter 29 | @RequiredArgsConstructor 30 | public enum BootAutoType { 31 | 32 | /** 33 | * Component,组合注解,添加到 spring.factories 34 | */ 35 | COMPONENT(BootAutoType.COMPONENT_ANNOTATION, "org.springframework.boot.autoconfigure.EnableAutoConfiguration"), 36 | /** 37 | * ApplicationContextInitializer 添加到 spring.factories 38 | */ 39 | CONTEXT_INITIALIZER(AutoContextInitializer.class.getName(), "org.springframework.context.ApplicationContextInitializer"), 40 | /** 41 | * ApplicationListener 添加到 spring.factories 42 | */ 43 | LISTENER(AutoListener.class.getName(), "org.springframework.context.ApplicationListener"), 44 | /** 45 | * SpringApplicationRunListener 添加到 spring.factories 46 | */ 47 | RUN_LISTENER(AutoRunListener.class.getName(), "org.springframework.boot.SpringApplicationRunListener"), 48 | /** 49 | * EnvironmentPostProcessor 添加到 spring.factories 50 | */ 51 | ENV_POST_PROCESSOR(AutoEnvPostProcessor.class.getName(), "org.springframework.boot.EnvironmentPostProcessor"), 52 | /** 53 | * FailureAnalyzer 添加到 spring.factories 54 | */ 55 | FAILURE_ANALYZER(AutoFailureAnalyzer.class.getName(), "org.springframework.boot.diagnostics.FailureAnalyzer"), 56 | /** 57 | * AutoConfigurationImportFilter spring.factories 58 | */ 59 | AUTO_CONFIGURATION_IMPORT_FILTER(AutoConfigImportFilter.class.getName(), "org.springframework.boot.autoconfigure.AutoConfigurationImportFilter"), 60 | /** 61 | * TemplateAvailabilityProvider 添加到 spring.factories 62 | */ 63 | TEMPLATE_AVAILABILITY_PROVIDER(AutoTemplateProvider.class.getName(), "org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider"), 64 | /** 65 | * auto EnableCircuitBreaker 66 | */ 67 | AUTO_ENABLE_CIRCUIT_BREAKER(AutoEnableCircuitBreaker.class.getName(), "org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker"), 68 | /** 69 | * auto ConfigDataLocationResolver 70 | */ 71 | AUTO_CONFIG_DATA_LOCATION_RESOLVER(AutoConfigDataLocationResolver.class.getName(), "org.springframework.boot.context.config.ConfigDataLocationResolver"), 72 | /** 73 | * auto ConfigDataLoader 74 | */ 75 | AUTO_CONFIG_DATA_LOADER(AutoConfigDataLoader.class.getName(), "org.springframework.boot.context.config.ConfigDataLoader"), 76 | /** 77 | * auto DatabaseInitializerDetector 78 | */ 79 | AUTO_DATABASE_INITIALIZER_DETECTOR(AutoDatabaseInitializerDetector.class.getName(), "org.springframework.boot.sql.init.dependency.DatabaseInitializerDetector"), 80 | /** 81 | * auto DependsOnDatabaseInitializationDetector 82 | */ 83 | AUTO_DEPENDS_ON_DATABASE_INITIALIZATION_DETECTOR(AutoDependsOnDatabaseInitializationDetector.class.getName(), "org.springframework.boot.sql.init.dependency.DependsOnDatabaseInitializationDetector"), 84 | /** 85 | * auto LoggingSystemFactory 86 | */ 87 | AUTO_LOGGING_SYSTEM(AutoLoggingSystemFactory.class.getName(), "org.springframework.boot.logging.LoggingSystemFactory"), 88 | ; 89 | 90 | private final String annotation; 91 | private final String configureKey; 92 | 93 | public static final String COMPONENT_ANNOTATION = "org.springframework.stereotype.Component"; 94 | 95 | } 96 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mica-auto SPI、Spring boot starter 利器 2 | [![Java CI](https://github.com/lets-mica/mica-auto/workflows/Java%20CI/badge.svg)](https://github.com/lets-mica/mica-auto/actions) 3 | ![JAVA 8](https://img.shields.io/badge/JDK-1.8+-brightgreen.svg) 4 | [![mica-auto Maven](https://img.shields.io/maven-central/v/net.dreamlu/mica-auto.svg?style=flat-square)](https://central.sonatype.com/artifact/net.dreamlu/mica-auto/versions) 5 | [![Codacy Badge](https://app.codacy.com/project/badge/Grade/681f9f08bc3d4b799f843eb2ff8be287)](https://www.codacy.com/gh/lets-mica/mica-auto/dashboard?utm_source=github.com&utm_medium=referral&utm_content=lets-mica/mica-auto&utm_campaign=Badge_Grade) 6 | 7 | `mica-auto` 是 `Spring cloud` 微服务框架 `Mica` 中的一个基础组件,用来生成 `Spring boot starter` 的一些基础配置。 8 | 9 | [✨✨✨推广:**BladeX 物联网平台**✨✨✨iot.bladex.cn](https://iot.bladex.cn?from=mica-mqtt) 10 | 11 | ------ 12 | 13 | 简体中文 | [English](README_EN.md) | [版本更新记录](CHANGELOG.md) 14 | 15 | ## 版本说明 16 | | version | spring boot version | java version | 17 | |---------|-------------------|--------------| 18 | | 4.0.1 | 4.x | 17 | 19 | | 3.1.6 | 3.x | 17 | 20 | | 2.3.5 | 1.x ~ 3.x | 1.8 | 21 | 22 | ## 原理 23 | 24 | mica auto 采用 Annotation Processor,她不是什么新技术,在 jdk 1.6 就存在了。 Annotation Processor 是 javac 的一个工具,它用来在编译时扫描和处理注解。通过 Annotation Processor 可以获取到注解和被注解对象的相关信息,然后根据注解自动生成Java代码,省去了手动编写,提高了编码效率。大名鼎鼎的 Lombok 也是采用的该技术。 25 | 26 | ## 使用场景 27 | 主要是用来避免 Spring boot 主项目包同 `子项目`或者`子模块` 包不一致,避免包扫描不到的问题。 28 | 29 | - 自定义 `spring boot starter`。 30 | - 多模块项目中的`子项目`(不建议主项目添加 `mica-auto`)。 31 | 32 | ## 功能 33 | - 自动生成 spring.factories、spring-devtools.properties 配置(Spring boot starter 开发利器)。 34 | - 生成 FeignClient 到 spring.factories 中,供 mica-cloud 中完成 Feign 自动化配置。 35 | - 生成 java spi 配置,需要添加 `@AutoService` 注解。 36 | 37 | | 注解 | spring.factories 或 Spi key | 38 | | ------------------------------- | ------------------------------- | 39 | | @AutoContextInitializer | ApplicationContextInitializer | 40 | | @AutoListener | ApplicationListener | 41 | | @AutoRunListener | SpringApplicationRunListener | 42 | | @AutoEnvPostProcessor | EnvironmentPostProcessor | 43 | | @AutoFailureAnalyzer | FailureAnalyzer | 44 | | @AutoConfigImportFilter | AutoConfigurationImportFilter | 45 | | @AutoTemplateProvider | TemplateAvailabilityProvider | 46 | | @AutoEnableCircuitBreaker | EnableCircuitBreaker | 47 | | @AutoConfigDataLocationResolver | ConfigDataLocationResolver | 48 | | @AutoConfigDataLoader | ConfigDataLoader | 49 | | @AutoDatabaseInitializerDetector | DatabaseInitializerDetector | 50 | | @AutoDependsOnDatabaseInitializationDetector | DependsOnDatabaseInitializationDetector | 51 | | @Component | EnableAutoConfiguration | 52 | | @AutoIgnore | 忽略,不生成到 spring.factories | 53 | | @AutoService | java Spi 生成配置 | 54 | 55 | | 注解 | aot.factories | 56 | | ------------------------------- | ------------------------------- | 57 | | @AotRuntimeHintsRegistrar | RuntimeHintsRegistrar | 58 | | @AotBeanRegistration | BeanRegistrationAotProcessor | 59 | | @AotBeanFactoryInitialization | BeanFactoryInitializationAotProcessor | 60 | 61 | ## 使用 62 | `注意:` 如果你项目中使用了 `Lombok` 请将 `mica-auto` 的依赖放置到 `Lombok` 后面。 63 | 64 | ### maven 65 | ```xml 66 | 67 | net.dreamlu 68 | mica-auto 69 | ${mica-auto.version} 70 | provided 71 | 72 | ``` 73 | 74 | ### gradle >= 5.x 75 | ```groovy 76 | annotationProcessor("net.dreamlu:mica-auto:$micaAutoVersion}") 77 | ``` 78 | 79 | ### gradle < 5.x 80 | ```groovy 81 | compileOnly "net.dreamlu:mica-auto:$micaAutoVersion" 82 | ``` 83 | 84 | ## 原理 85 | 扫描 `@Component`,自动生成相应的配置,支持组合注解。 86 | 87 | ## mica 生态 88 | 89 | - mica (Spring cloud 微服务组件集): https://gitee.com/596392912/mica 90 | - mica-auto (Spring boot starter 利器): https://gitee.com/596392912/mica-auto 91 | - mica-weixin(jfinal weixin 的 spring boot starter):https://gitee.com/596392912/mica-weixin 92 | - mica-mqtt(基于 t-io 实现的 mqtt组件):https://gitee.com/596392912/mica-mqtt 93 | - Spring cloud 微服务 http2 方案(h2c): https://gitee.com/596392912/spring-cloud-java11 94 | 95 | ## 开源协议 96 | LGPL([GNU Lesser General Public License](http://www.gnu.org/licenses/lgpl.html)) 97 | 98 | LGPL是GPL的一个为主要为类库使用设计的开源协议。和GPL要求任何使用/修改/衍生之GPL类库的的软件必须采用GPL协议不同。LGPL允许商业软件通过类库引用(link)方式使用LGPL类库而不需要开源商业软件的代码。这使得采用LGPL协议的开源代码可以被商业软件作为类库引用并发布和销售。 99 | 100 | 但是如果修改LGPL协议的代码或者衍生,则所有修改的代码,涉及修改部分的额外代码和衍生的代码都必须采用LGPL协议。因此LGPL协议的开源代码很适合作为第三方类库被商业软件引用,但不适合希望以LGPL协议代码为基础,通过修改和衍生的方式做二次开发的商业软件采用。 101 | 102 | ## 用户权益 103 | * 允许以引入不改源码的形式免费用于学习、毕设、公司项目、私活等。 104 | * 特殊情况修改代码,但仍然想闭源需经过作者同意。 105 | * 参考请注明:参考 mica-auto: https://github.com/lets-mica/mica-auto 106 | 107 | ## 参考 108 | Google Auto: https://github.com/google/auto 109 | 110 | Spring 5 - spring-context-indexer: https://github.com/spring-projects/spring-framework/tree/main/spring-context-indexer 111 | 112 | ## 微信公众号 113 | 114 | ![如梦技术](docs/dreamlu-weixin.jpg) 115 | 116 | **JAVA架构日记**,精彩内容每日推荐! -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 变更记录 2 | 3 | ## 发行版本 4 | 5 | ## [4.0.1] - 2025-11-28 6 | - fix(deps): 移除 spring-boot-configuration-processor 和 spring-boot-autoconfigure-processor 依赖的 optional 标记 7 | 8 | ## [4.0.0] - 2025-11-27 9 | - :sparkles: 支持 Spring boot 4.0.0 10 | 11 | ## [3.1.6] - 2025-11-28 12 | - fix(deps): 移除 spring-boot-configuration-processor 和 spring-boot-autoconfigure-processor 依赖的 optional 标记 13 | 14 | ## [3.1.5] - 2024-01-16 15 | - :sparkles: 从 Gradle 构建迁移到 Maven 16 | - :arrow_up: 升级到 Spring boot 3.5.5 17 | 18 | ## [3.1.3] - 2024-01-16 19 | - :sparkles: 支持 Kotlin Spring boot starter。 20 | - :arrow_up: 升级到 Spring boot 3.2.1 21 | 22 | ## [3.1.2] - 2023-10-15 23 | - :sparkles: 支持 Kotlin 元注解,github #8 感谢 `@Sunrise66` 反馈 24 | - :arrow_up: 升级到 Spring boot 3.1.4 25 | 26 | ## [3.1.1] - 2023-01-02 27 | - :arrow_up: 升级到 Spring boot 3.1.1 28 | 29 | ## [3.0.1] - 2023-01-02 30 | - :sparkles: Spring boot 2.7.x+ spi 生成改为直接支持 `@Component` 31 | - :arrow_up: 升级到 Spring boot 3.0.1 32 | 33 | ## [3.0.0] - 2022-11-29 34 | - :sparkles: 支持 Spring boot 3.0.0 aot native 35 | - :arrow_up: 升级到 Spring boot 3.0.0 36 | - :arrow_up: 升级到 java17 37 | 38 | ## [2.3.4] - 2024-01-16 39 | - :sparkles: 支持 Kotlin Spring boot starter。 40 | - :arrow_up: 升级到 Spring boot 2.7.18 41 | 42 | ## [2.3.3] - 2023-10-15 43 | - :sparkles: 支持 Kotlin 元注解,github #8 感谢 `@Sunrise66` 反馈 44 | - :arrow_up: 升级到 Spring boot 2.7.16 45 | 46 | ## [2.3.2] - 2023-01-02 47 | - :sparkles: Spring boot 2.7.x+ spi 生成改为直接支持 `@Component` 48 | - :arrow_up: 升级到 Spring boot 2.7.7 49 | 50 | ## [2.3.1] - 2022-06-02 51 | - :sparkles: 支持生成的 Spring boot 2.7.0 向下兼容。感谢 `@冷冷` 提出的需求。 52 | 53 | ## [2.3.0] - 2022-05-30 54 | - :sparkles: 支持 Spring boot 2.7.0 新特性 `@AutoConfiguration`。 55 | - :arrow_up: 升级 Spring boot 到 2.7.0 56 | 57 | ## [2.2.2] - 2021-12-26 58 | - :sparkles: 支持合并用户手写的 `spring.factories` 配置 59 | - :arrow_up: 升级 Spring boot 到 2.6.2 60 | 61 | ## [2.2.1] - 2021-12-10 62 | - :arrow_up: 升级 Spring boot 到 2.6.1 63 | 64 | ## [2.2.0] - 2021-11-20 65 | - :arrow_up: 升级 gradle 到 7.3 66 | - :arrow_up: 升级 lombok 到 1.18.22 67 | - :arrow_up: 升级 google auto 到 1.0.1 68 | - :arrow_up: 升级 Spring boot 到 2.6.0 69 | 70 | ## [2.1.3] - 2021-08-05 71 | - :sparkles: 代码优化,优化流关闭。 72 | - :sparkles: 优化 github actions。 73 | - :bug: 修复 spi,去除注释。 74 | - :bug: 修复 gitee #I4193Q idea 增量编译 bug。 75 | - :bug: 修复 spring-devtools.properties 匹配 bug。 76 | 77 | ## [2.1.2] - 2021-07-26 78 | ### 新功能 79 | - :sparkles: `@AutoService` 支持 gradle 增量编译 80 | - :arrow_up: 升级 Spring boot 到 2.5.3 81 | 82 | ## [2.1.1] - 2021-07-02 83 | ### 新功能 84 | - :sparkles: 添加 DatabaseInitializer 相关支持 85 | - :sparkles: 优化 jar manifest 86 | - :white_check_mark: Adding google compile-testing. 87 | - :arrow_up: 升级 Spring boot 到 2.5.2 88 | 89 | ## [2.1.0] - 2021-05-21 90 | ### 新功能 91 | - :sparkles: 支持 gradle 增量编译 92 | - :sparkles: 优化 jar manifest 93 | - :arrow_up: 升级 Spring boot 到 2.5.0 94 | - :arrow_up: 升级 lombok 到 1.18.20 95 | - :arrow_up: 升级 google auto 到 1.0 96 | 97 | ## [2.0.4] - 2021-03-20 98 | ### 新功能 99 | - :arrow_up: 升级 Spring boot 到 2.4.4 100 | - :arrow_up: 升级 lombok 到 1.18.18 101 | 102 | ## [2.0.3] - 2020-12-28 103 | ### 新功能 104 | - 添加 AutoConfigDataLocationResolver。 105 | - 添加 AutoConfigDataLoader 106 | 107 | ## [2.0.1] - 2020-12-24 108 | ### 新功能 109 | - 添加 AutoEnableCircuitBreaker。 110 | 111 | ## [2.0.0] - 2020-11-15 112 | ### 依赖升级 113 | - :arrow_up: 升级 spring boot 到 2.4.1。 114 | 115 | ## [1.3.0] - 2020-11-15 116 | ### 依赖升级 117 | - :arrow_up: 升级 spring boot 到 2.4.0。 118 | - :arrow_up: gradle 版本和 mica 保持一致。 119 | - :arrow_up: 升级 lombok 到 1.18.16。 120 | 121 | ## [1.2.5] - 2020-07-25 122 | ### 修复 123 | - :bug: 修复编译的 jdk 版本,使用 jdk8. 124 | 125 | ## [1.2.4] - 2020-07-25 126 | ### 依赖升级 127 | - :arrow_up: 升级 spring boot 到 2.3.2.RELEASE。 128 | 129 | ## [1.2.3] - 2020-05-30 130 | ### 新功能 131 | - 添加 `AutoConfigurationImportFilter` 的 `@AutoConfigImportFilter`。 132 | - 添加 `TemplateAvailabilityProvider` 的 `@AutoTemplateProvider`。 133 | 134 | ### 依赖升级 135 | - :arrow_up: 升级 spring bootVersion 到 2.3.0.RELEASE。 136 | - :arrow_up: 升级 google auto 到 1.0-rc7。 137 | 138 | ## [1.2.2] - 2020-04-27 139 | ### 新功能 140 | - 添加可用于忽略生成到 spring.factories 的 `@AutoIgnore`。 141 | 142 | ### 依赖升级 143 | - lombok 升级到 `1.18.12`。 144 | 145 | ## [1.2.2] - 2020-04-27 146 | ### 添加 147 | - 添加可用于忽略生成到 spring.factories 的 `@AutoIgnore`。 148 | - lombok 升级到 `1.18.12`。 149 | 150 | ## [1.2.1] - 2020-04-09 151 | ### 添加 152 | - 添加对 spring boot SpringApplicationRunListener 的支持。 153 | - 添加对 spring boot EnvironmentPostProcessor 的支持。 154 | - Spring boot 升级到 `2.2.6.RELEASE`。 155 | 156 | ## [1.2.0] - 2019-12-06 157 | ### 添加 158 | - 添加对 java spi 的支持,并精简代码。 159 | - lombok、spring boot、google auto 依赖升级。 160 | 161 | ## [1.1.0] - 2019-05-24 162 | ### 添加 163 | - 添加 `@AutoContextInitializer` 支持 `org.springframework.context.ApplicationContextInitializer`。 164 | - 添加 `@AutoListener` 支持 `org.springframework.context.ApplicationListener`。 165 | - 添加 `@AutoFailureAnalyzer` 支持 `org.springframework.boot.diagnostics.FailureAnalyzer`。 166 | 167 | ### 依赖升级 168 | - 升级 `gradle` 到 `5.4.1`。 169 | - 升级 `google auto` 到 `1.0-rc5`。 170 | - 升级 `lombok` 到 `1.18.8`, 171 | - 升级 `Spring Boot` 到 `2.1.5.RELEASE`。 172 | 173 | ## [1.0.1] - 2019-01-27 174 | ### 调整 175 | - 扫描注解由 `@Configuration` 调整为 `@Component`,支持 `@Service`、`@Controller` 等组合有 `@Component` 的注解。 176 | 177 | ### 修复 178 | - ✅调整 process 返回 false,支持其他注解处理器。 179 | 180 | ## [1.0.0] - 2019-01-21 181 | ### 修复 182 | - ✅修复组合注解递归存在 `bug`。 183 | 184 | ## [0.0.3] - 2019-01-20 185 | ### 添加 186 | - 😘支持 `Spring` 组合注解。 187 | 188 | ## [0.0.2] - 2019-01-20 189 | ### 添加 190 | - 组合 `spring-boot-configuration-processor` 避免项目中引入过多依赖。 191 | - 组合 `spring-boot-autoconfigure-processor` 避免项目中引入过多依赖。 192 | - 添加对 `Feign` 自动配置的生成,`mica-cloud` autoconfigure 中完成初始化。不需要使用 `@EnableFeignClients` 开启和指定 feign 包目录。 193 | 194 | ## [0.0.1] - 2019-01-12 195 | ### 添加 196 | - 生成 `spring.factories` 197 | - 生成 `spring-devtools.properties` -------------------------------------------------------------------------------- /src/main/java/net/dreamlu/mica/auto/factories/FactoriesFiles.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net). 3 | *

4 | * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.gnu.org/licenses/lgpl.html 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.dreamlu.mica.auto.factories; 18 | 19 | import lombok.experimental.UtilityClass; 20 | import net.dreamlu.mica.auto.common.MultiSetMap; 21 | 22 | import javax.lang.model.util.Elements; 23 | import javax.tools.FileObject; 24 | import java.io.*; 25 | import java.nio.charset.Charset; 26 | import java.nio.charset.StandardCharsets; 27 | import java.util.*; 28 | import java.util.stream.Collectors; 29 | 30 | /** 31 | * spring boot 自动化配置工具类 32 | * 33 | * @author L.cm 34 | */ 35 | @UtilityClass 36 | class FactoriesFiles { 37 | private static final Charset UTF_8 = StandardCharsets.UTF_8; 38 | 39 | /** 40 | * 读取 spring.factories 文件 41 | * 42 | * @param fileObject FileObject 43 | * @return MultiSetMap 44 | * @throws IOException 异常信息 45 | */ 46 | protected static MultiSetMap readFactoriesFile(FileObject fileObject, Elements elementUtils) throws IOException { 47 | // 读取 spring.factories 内容 48 | Properties properties = new Properties(); 49 | try (InputStream input = fileObject.openInputStream()) { 50 | properties.load(input); 51 | } 52 | MultiSetMap multiSetMap = new MultiSetMap<>(); 53 | Set> entrySet = properties.entrySet(); 54 | for (Map.Entry objectEntry : entrySet) { 55 | String key = (String) objectEntry.getKey(); 56 | String value = (String) objectEntry.getValue(); 57 | if (value == null || value.trim().isEmpty()) { 58 | continue; 59 | } 60 | // 解析 spring.factories 61 | String[] values = value.split(","); 62 | Set valueSet = Arrays.stream(values) 63 | .filter(v -> !v.isEmpty()) 64 | .map(String::trim) 65 | // 校验是否删除文件 66 | .filter((v) -> Objects.nonNull(elementUtils.getTypeElement(v))) 67 | .collect(Collectors.toSet()); 68 | multiSetMap.putAll(key.trim(), valueSet); 69 | } 70 | return multiSetMap; 71 | } 72 | 73 | /** 74 | * 读取已经存在的 AutoConfiguration imports 75 | * 76 | * @param fileObject FileObject 77 | * @return Set 78 | * @throws IOException IOException 79 | */ 80 | protected static Set readAutoConfigurationImports(FileObject fileObject) throws IOException { 81 | Set set = new HashSet<>(); 82 | try ( 83 | InputStream input = fileObject.openInputStream(); 84 | BufferedReader reader = new BufferedReader(new InputStreamReader(input)) 85 | ) { 86 | reader.lines() 87 | .map(String::trim) 88 | .filter(line -> !line.startsWith("#")) 89 | .forEach(set::add); 90 | } 91 | return set; 92 | } 93 | 94 | /** 95 | * 写出 spring.factories 文件 96 | * 97 | * @param factories factories 信息 98 | * @param output 输出流 99 | * @throws IOException 异常信息 100 | */ 101 | protected static void writeFactoriesFile(MultiSetMap factories, 102 | OutputStream output) throws IOException { 103 | BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(output, UTF_8)); 104 | writer.write("# Generated by mica-auto www.dreamlu.net\n"); 105 | Set keySet = factories.keySet(); 106 | for (String key : keySet) { 107 | Set values = factories.get(key); 108 | if (values == null || values.isEmpty()) { 109 | continue; 110 | } 111 | writer.write(key); 112 | writer.write("=\\\n "); 113 | StringJoiner joiner = new StringJoiner(",\\\n "); 114 | List valueList = new ArrayList<>(values); 115 | Collections.sort(valueList); 116 | for (String value : valueList) { 117 | joiner.add(value); 118 | } 119 | writer.write(joiner.toString()); 120 | writer.newLine(); 121 | } 122 | writer.flush(); 123 | } 124 | 125 | /** 126 | * 写出 spring-devtools.properties 127 | * 128 | * @param projectName 项目名 129 | * @param output 输出流 130 | * @throws IOException 异常信息 131 | */ 132 | protected static void writeDevToolsFile(String projectName, 133 | OutputStream output) throws IOException { 134 | BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(output, UTF_8)); 135 | // restart.include.mica-cloud=/mica-cloud[\\w\\d-.]+\\.jar 136 | String format = "restart.include.%s=/%s[\\\\w\\\\d-.]+\\\\.jar"; 137 | writer.write("# Generated by mica-auto www.dreamlu.net\n"); 138 | writer.write(String.format(format, projectName, projectName)); 139 | writer.flush(); 140 | } 141 | 142 | /** 143 | * 写出 AutoConfiguration imports 144 | * 145 | * @param allAutoConfigurationImports allAutoConfigurationImports 146 | * @param output OutputStream 147 | * @throws IOException IOException 148 | */ 149 | protected static void writeAutoConfigurationImportsFile(Set allAutoConfigurationImports, OutputStream output) throws IOException { 150 | BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(output, UTF_8)); 151 | StringJoiner joiner = new StringJoiner("\n"); 152 | List configurationImportList = new ArrayList<>(allAutoConfigurationImports); 153 | Collections.sort(configurationImportList); 154 | for (String configurationImport : configurationImportList) { 155 | joiner.add(configurationImport); 156 | } 157 | writer.write(joiner.toString()); 158 | writer.flush(); 159 | } 160 | 161 | } 162 | -------------------------------------------------------------------------------- /README_EN.md: -------------------------------------------------------------------------------- 1 | # mica-auto SPI、Spring boot starter Development Tools 2 | [![Java CI](https://github.com/lets-mica/mica-auto/workflows/Java%20CI/badge.svg)](https://github.com/lets-mica/mica-auto/actions) 3 | ![JAVA 8](https://img.shields.io/badge/JDK-1.8+-brightgreen.svg) 4 | [![mica-auto Maven](https://img.shields.io/maven-central/v/net.dreamlu/mica-auto.svg?style=flat-square)](https://central.sonatype.com/artifact/net.dreamlu/mica-auto/versions) 5 | [![Codacy Badge](https://app.codacy.com/project/badge/Grade/681f9f08bc3d4b799f843eb2ff8be287)](https://www.codacy.com/gh/lets-mica/mica-auto/dashboard?utm_source=github.com&utm_medium=referral&utm_content=lets-mica/mica-auto&utm_campaign=Badge_Grade) 6 | 7 | Mica-auto is a basic component of the Spring Cloud microservices framework MICA, which is used to generate some basic configurations of the Spring Boot Starter. 8 | 9 | English | [简体中文](README.md) 10 | 11 | [Version Update Record](CHANGELOG.md) 12 | 13 | ## version 14 | | version | spring boot version | java version | 15 | |---------|---------------------|--------------| 16 | | 4.0.0 | 4.x | 17 | 17 | | 3.1.6 | 3.x | 17 | 18 | | 2.3.5 | 1.x ~ 3.x | 1.8 | 19 | 20 | ## Principle 21 | Mica Auto uses the Annotation Processor, which is not a new technology. It's been around since JDK 1.6. The Annotation Processor is a tool of javac that scans and processes annotations at compile time. Using the Annotation Processor, you can obtain information about annotations and annotated objects, and then automatically generate Java code based on annotations, eliminating manual writing and improving coding efficiency. Lombok is also famous for this technology. 22 | 23 | ## Usage Scenarios 24 | It is mainly used to avoid the inconsistency between the Spring Boot main project package and the subproject or submodule package, and avoid the problem that the package cannot be scanned. 25 | .Customize the Spring Boot starter. 26 | .Subprojects in a multi-module project (adding MICA-Auto to a master project is not recommended). 27 | 28 | ## Functions 29 | - Automatically generate `spring.factories`, `spring-devtools.properties` configuration (spring Boot starter development tools). 30 | - Generate the `FeignClient` in the spring.factories for automated Feign configuration in the **mica-cloud**. 31 | - Generate the `Java Spi` configuration, you need to add the `@AutoService` annotation. 32 | 33 | | Annotation | spring.factories or Spi key | 34 | | ------------------------------- | ------------------------------- | 35 | | @AutoContextInitializer | ApplicationContextInitializer | 36 | | @AutoListener | ApplicationListener | 37 | | @AutoRunListener | SpringApplicationRunListener | 38 | | @AutoEnvPostProcessor | EnvironmentPostProcessor | 39 | | @AutoFailureAnalyzer | FailureAnalyzer | 40 | | @AutoConfigImportFilter | AutoConfigurationImportFilter | 41 | | @AutoTemplateProvider | TemplateAvailabilityProvider | 42 | | @AutoEnableCircuitBreaker | EnableCircuitBreaker | 43 | | @AutoConfigDataLocationResolver | ConfigDataLocationResolver | 44 | | @AutoConfigDataLoader | ConfigDataLoader | 45 | | @AutoDatabaseInitializerDetector | DatabaseInitializerDetector | 46 | | @AutoDependsOnDatabaseInitializationDetector | DependsOnDatabaseInitializationDetector | 47 | | @Component | EnableAutoConfiguration | 48 | | @AutoIgnore | Ignore and do not generate to spring.factories | 49 | | @AutoService | java Spi generates the configuration | 50 | 51 | | Annotation | aot.factories | 52 | | ------------------------------- | ------------------------------- | 53 | | @AotRuntimeHintsRegistrar | RuntimeHintsRegistrar | 54 | | @AotBeanRegistration | BeanRegistrationAotProcessor | 55 | | @AotBeanFactoryInitialization | BeanFactoryInitializationAotProcessor | 56 | 57 | ## Usage 58 | **Note**: If you are using `Lombok` in your project, place the mica-Auto dependency behind `Lombok`。 59 | 60 | ### maven 61 | ```xml 62 | 63 | net.dreamlu 64 | mica-auto 65 | ${mica-auto.version} 66 | provided 67 | 68 | ``` 69 | 70 | ### gradle >= 5.x 71 | ```groovy 72 | annotationProcessor("net.dreamlu:mica-auto:$micaAutoVersion}") 73 | ``` 74 | 75 | ### gradle < 5.x 76 | ```gradle 77 | compileOnly "net.dreamlu:mica-auto:2.3.2" 78 | ``` 79 | 80 | ## Principle 81 | Scan `@component`, automatically generate the corresponding configuration, and support composite annotations. 82 | 83 | ## Mica Ecological 84 | 85 | - mica (Spring cloud micro service component): https://gitee.com/596392912/mica 86 | - mica-auto (Spring boot starter development tools): https://gitee.com/596392912/mica-auto 87 | - mica-weixin ( jfinal weixin’s spring boot starter ):https://gitee.com/596392912/mica-weixin 88 | - mica-mqtt (mqtt component based on t-io implementation):https://gitee.com/596392912/mica-mqtt 89 | - Spring cloud Microservice http2 solution( h2c ): https://gitee.com/596392912/spring-cloud-java11 90 | 91 | ## Open Source Licenses 92 | 93 | LGPL(GNU Lesser General Public License) 94 | 95 | ## The User’s Rights 96 | 97 | Allow to introduce the source code in the form of free for study, graduation, corporate projects, private work, etc. 98 | Modify the code in special cases, but still want to close the source must be approved by the author. 99 | For reference, please specify: refer to mica-auto: https://github.com/lets-mica/mica-auto 100 | 101 | ## References 102 | 103 | - Google Auto: https://github.com/google/auto 104 | - Spring 5 - spring-context-indexer:https://github.com/spring-projects/spring-framework/tree/master/spring-context-indexer 105 | 106 | ## WeChat Official Account 107 | 108 | ![dreamlu](docs/dreamlu-weixin.jpg) -------------------------------------------------------------------------------- /src/main/java/net/dreamlu/mica/auto/common/AbstractMicaProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net). 3 | *

4 | * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.gnu.org/licenses/lgpl.html 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.dreamlu.mica.auto.common; 18 | 19 | import javax.annotation.processing.AbstractProcessor; 20 | import javax.annotation.processing.RoundEnvironment; 21 | import javax.lang.model.SourceVersion; 22 | import javax.lang.model.element.*; 23 | import javax.lang.model.util.Elements; 24 | import javax.tools.Diagnostic.Kind; 25 | import java.io.PrintWriter; 26 | import java.io.StringWriter; 27 | import java.util.List; 28 | import java.util.Set; 29 | 30 | /** 31 | * 抽象 处理器 32 | * 33 | * @author L.cm 34 | */ 35 | public abstract class AbstractMicaProcessor extends AbstractProcessor { 36 | 37 | @Override 38 | public SourceVersion getSupportedSourceVersion() { 39 | return SourceVersion.latestSupported(); 40 | } 41 | 42 | /** 43 | * AutoService 注解处理器 44 | * 45 | * @param annotations 注解 getSupportedAnnotationTypes 46 | * @param roundEnv 扫描到的 注解新 47 | * @return 是否完成 48 | */ 49 | @Override 50 | public boolean process(Set annotations, RoundEnvironment roundEnv) { 51 | try { 52 | return processImpl(annotations, roundEnv); 53 | } catch (Exception e) { 54 | fatalError(e); 55 | return false; 56 | } 57 | } 58 | 59 | protected abstract boolean processImpl(Set annotations, RoundEnvironment roundEnv); 60 | 61 | /** 62 | * 判断为类 63 | * 64 | * @param e Element 65 | * @return {boolean} 66 | */ 67 | protected boolean isClass(Element e) { 68 | ElementKind kind = e.getKind(); 69 | return kind == ElementKind.CLASS; 70 | } 71 | 72 | /** 73 | * 判断为类或者接口 74 | * 75 | * @param e Element 76 | * @return {boolean} 77 | */ 78 | protected boolean isClassOrInterface(Element e) { 79 | ElementKind kind = e.getKind(); 80 | return kind == ElementKind.CLASS || kind == ElementKind.INTERFACE; 81 | } 82 | 83 | /** 84 | * 获取注解,支持组合注解 85 | * 86 | * @param elementUtils elementUtils 87 | * @param e Element 88 | * @param annotationFullName annotationFullName 89 | * @return {boolean} 90 | */ 91 | protected AnnotationMirror getAnnotation(Elements elementUtils, Element e, String annotationFullName) { 92 | List annotationList = elementUtils.getAllAnnotationMirrors(e); 93 | for (AnnotationMirror annotation : annotationList) { 94 | // 如果是对于的注解 95 | if (isAnnotation(annotationFullName, annotation)) { 96 | return annotation; 97 | } 98 | // 处理组合注解 99 | Element element = annotation.getAnnotationType().asElement(); 100 | String elementStr = element.toString(); 101 | // 如果是 java 或 kotlin 元注解,继续循环 102 | if (elementStr.startsWith("java.lang") || elementStr.startsWith("kotlin.")) { 103 | continue; 104 | } 105 | // 递归处理 组合注解 106 | return getAnnotation(elementUtils, element, annotationFullName); 107 | } 108 | return null; 109 | } 110 | 111 | /** 112 | * 判断是相同的注解,支持组合注解 113 | * 114 | * @param elementUtils elementUtils 115 | * @param e Element 116 | * @param annotationFullName annotationFullName 117 | * @return {boolean} 118 | */ 119 | protected boolean isAnnotation(Elements elementUtils, Element e, String annotationFullName) { 120 | List annotationList = elementUtils.getAllAnnotationMirrors(e); 121 | for (AnnotationMirror annotation : annotationList) { 122 | // 如果是对于的注解 123 | if (isAnnotation(annotationFullName, annotation)) { 124 | return true; 125 | } 126 | // 处理组合注解 127 | Element element = annotation.getAnnotationType().asElement(); 128 | String elementStr = element.toString(); 129 | // 如果是 java 元注解,继续循环 130 | if (elementStr.startsWith("java.lang") || elementStr.startsWith("kotlin.")) { 131 | continue; 132 | } 133 | // 递归处理 组合注解 134 | if (isAnnotation(elementUtils, element, annotationFullName)) { 135 | return true; 136 | } 137 | } 138 | return false; 139 | } 140 | 141 | /** 142 | * 判断是否同一个注解 143 | * 144 | * @param annotationFullName annotationFullName 145 | * @param annotation AnnotationMirror 146 | * @return {boolean} 147 | */ 148 | protected boolean isAnnotation(String annotationFullName, AnnotationMirror annotation) { 149 | return annotationFullName.equals(annotation.getAnnotationType().toString()); 150 | } 151 | 152 | /** 153 | * 获取属性的名称 154 | * 155 | * @param element Element 156 | * @return {String} 157 | */ 158 | protected String getQualifiedName(Element element) { 159 | if (element instanceof QualifiedNameable) { 160 | return ((QualifiedNameable) element).getQualifiedName().toString(); 161 | } 162 | return element.toString(); 163 | } 164 | 165 | protected void log(String msg) { 166 | if (processingEnv.getOptions().containsKey("debug")) { 167 | processingEnv.getMessager().printMessage(Kind.NOTE, msg); 168 | } 169 | } 170 | 171 | protected void error(String msg, Element element) { 172 | processingEnv.getMessager().printMessage(Kind.ERROR, msg, element); 173 | } 174 | 175 | protected void error(String msg, Element element, AnnotationMirror annotation) { 176 | processingEnv.getMessager().printMessage(Kind.ERROR, msg, element, annotation); 177 | } 178 | 179 | protected void fatalError(Exception e) { 180 | // We don't allow exceptions of any kind to propagate to the compiler 181 | StringWriter writer = new StringWriter(); 182 | e.printStackTrace(new PrintWriter(writer)); 183 | fatalError(writer.toString()); 184 | } 185 | 186 | protected void fatalError(String msg) { 187 | processingEnv.getMessager().printMessage(Kind.ERROR, "FATAL ERROR: " + msg); 188 | } 189 | 190 | } 191 | -------------------------------------------------------------------------------- /src/main/java/net/dreamlu/mica/auto/aot/AotFactoriesProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net). 3 | *

4 | * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.gnu.org/licenses/lgpl.html 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.dreamlu.mica.auto.aot; 18 | 19 | import com.google.auto.service.AutoService; 20 | import net.dreamlu.mica.auto.annotation.AotBeanFactoryInitialization; 21 | import net.dreamlu.mica.auto.annotation.AotBeanRegistration; 22 | import net.dreamlu.mica.auto.annotation.AotRuntimeHintsRegistrar; 23 | import net.dreamlu.mica.auto.common.AbstractMicaProcessor; 24 | import net.dreamlu.mica.auto.common.AotAutoType; 25 | import net.dreamlu.mica.auto.common.MultiSetMap; 26 | import net.ltgt.gradle.incap.IncrementalAnnotationProcessor; 27 | import net.ltgt.gradle.incap.IncrementalAnnotationProcessorType; 28 | 29 | import javax.annotation.processing.*; 30 | import javax.lang.model.element.Element; 31 | import javax.lang.model.element.TypeElement; 32 | import javax.lang.model.util.Elements; 33 | import javax.tools.FileObject; 34 | import javax.tools.StandardLocation; 35 | import java.io.IOException; 36 | import java.io.OutputStream; 37 | import java.util.Set; 38 | import java.util.stream.Collectors; 39 | import java.util.stream.Stream; 40 | 41 | /** 42 | * spring boot 自动配置处理器 43 | * 44 | * @author L.cm 45 | */ 46 | @AutoService(Processor.class) 47 | @SupportedOptions("debug") 48 | @IncrementalAnnotationProcessor(IncrementalAnnotationProcessorType.AGGREGATING) 49 | public class AotFactoriesProcessor extends AbstractMicaProcessor { 50 | /** 51 | * The location to look for factories. 52 | *

Can be present in multiple JAR files. 53 | */ 54 | private static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring/aot.factories"; 55 | /** 56 | * 数据承载 57 | */ 58 | private final MultiSetMap factories = new MultiSetMap<>(); 59 | 60 | /** 61 | * 元素辅助类 62 | */ 63 | private Elements elementUtils; 64 | 65 | @Override 66 | public synchronized void init(ProcessingEnvironment processingEnv) { 67 | super.init(processingEnv); 68 | elementUtils = processingEnv.getElementUtils(); 69 | } 70 | 71 | @Override 72 | public Set getSupportedAnnotationTypes() { 73 | return Stream.of( 74 | AotRuntimeHintsRegistrar.class.getName(), 75 | AotBeanRegistration.class.getName(), 76 | AotBeanFactoryInitialization.class.getName() 77 | ).collect(Collectors.toSet()); 78 | } 79 | 80 | @Override 81 | protected boolean processImpl(Set annotations, RoundEnvironment roundEnv) { 82 | if (roundEnv.processingOver()) { 83 | // 1. 生成 aot.factories 84 | generateFactoriesFiles(); 85 | } else { 86 | processAnnotations(annotations, roundEnv); 87 | } 88 | return false; 89 | } 90 | 91 | private void processAnnotations(Set annotations, RoundEnvironment roundEnv) { 92 | // 日志 打印信息 gradle build --debug 93 | log(annotations.toString()); 94 | Set elementSet = roundEnv.getRootElements(); 95 | log("All Element set: " + elementSet.toString()); 96 | 97 | // 过滤 TypeElement 98 | Set typeElementSet = elementSet.stream() 99 | .filter(this::isClassOrInterface) 100 | .filter(TypeElement.class::isInstance) 101 | .map(TypeElement.class::cast) 102 | .collect(Collectors.toSet()); 103 | // 如果为空直接跳出 104 | if (typeElementSet.isEmpty()) { 105 | log("Annotations elementSet is isEmpty"); 106 | return; 107 | } 108 | for (TypeElement typeElement : typeElementSet) { 109 | // 1. 生成 aot.factories 110 | for (AotAutoType autoType : AotAutoType.values()) { 111 | String annotation = autoType.getAnnotation(); 112 | if (isAnnotation(elementUtils, typeElement, annotation)) { 113 | log("Found @" + annotation + " Element: " + typeElement.toString()); 114 | 115 | String factoryName = typeElement.getQualifiedName().toString(); 116 | if (factories.containsVal(factoryName)) { 117 | continue; 118 | } 119 | 120 | log("读取到新配置 aot.factories factoryName:" + factoryName); 121 | factories.put(autoType.getConfigureKey(), factoryName); 122 | } 123 | } 124 | } 125 | } 126 | 127 | private void generateFactoriesFiles() { 128 | if (factories.isEmpty()) { 129 | return; 130 | } 131 | Filer filer = processingEnv.getFiler(); 132 | try { 133 | // aot.factories 配置 134 | MultiSetMap allFactories = new MultiSetMap<>(); 135 | // 1. 用户手动配置项目下的 aot.factories 文件 136 | try { 137 | FileObject existingFactoriesFile = filer.getResource(StandardLocation.SOURCE_OUTPUT, "", FACTORIES_RESOURCE_LOCATION); 138 | // 查找是否已经存在 aot.factories 139 | log("Looking for existing aot.factories file at " + existingFactoriesFile.toUri()); 140 | MultiSetMap existingFactories = FactoriesFiles.readFactoriesFile(existingFactoriesFile, elementUtils); 141 | log("Existing aot.factories entries: " + existingFactories); 142 | allFactories.putAll(existingFactories); 143 | } catch (IOException e) { 144 | log("aot.factories resource file not found."); 145 | } 146 | // 2. 增量编译,已经存在的 aot.factories 文件 147 | try { 148 | FileObject existingFactoriesFile = filer.getResource(StandardLocation.CLASS_OUTPUT, "", FACTORIES_RESOURCE_LOCATION); 149 | // 查找是否已经存在 aot.factories 150 | log("Looking for existing aot.factories file at " + existingFactoriesFile.toUri()); 151 | MultiSetMap existingFactories = FactoriesFiles.readFactoriesFile(existingFactoriesFile, elementUtils); 152 | log("Existing aot.factories entries: " + existingFactories); 153 | allFactories.putAll(existingFactories); 154 | } catch (IOException e) { 155 | log("aot.factories resource file did not already exist."); 156 | } 157 | // 3. 处理器扫描出来的新的配置 158 | allFactories.putAll(factories); 159 | log("New aot.factories file contents: " + allFactories); 160 | FileObject factoriesFile = filer.createResource(StandardLocation.CLASS_OUTPUT, "", FACTORIES_RESOURCE_LOCATION); 161 | try (OutputStream out = factoriesFile.openOutputStream()) { 162 | FactoriesFiles.writeFactoriesFile(allFactories, out); 163 | } 164 | } catch (IOException e) { 165 | fatalError(e); 166 | } 167 | } 168 | 169 | } 170 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | 3 | Version 3, 29 June 2007 4 | 5 | Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net). 6 | 7 | Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. 8 | 9 | This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 10 | 11 | 0. Additional Definitions. 12 | 13 | As used herein, “this License” refers to version 3 of the GNU Lesser General Public License, and the “GNU GPL” refers to version 3 of the GNU General Public License. 14 | 15 | “The Library” refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. 16 | 17 | An “Application” is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. 18 | 19 | A “Combined Work” is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the “Linked Version”. 20 | 21 | The “Minimal Corresponding Source” for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. 22 | 23 | The “Corresponding Application Code” for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 24 | 25 | 1. Exception to Section 3 of the GNU GPL. 26 | 27 | You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 28 | 29 | 2. Conveying Modified Versions. 30 | 31 | If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: 32 | 33 | a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or 34 | b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 35 | 3. Object Code Incorporating Material from Library Header Files. 36 | 37 | The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: 38 | 39 | a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. 40 | b) Accompany the object code with a copy of the GNU GPL and this license document. 41 | 4. Combined Works. 42 | 43 | You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: 44 | 45 | a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. 46 | b) Accompany the Combined Work with a copy of the GNU GPL and this license document. 47 | c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. 48 | d) Do one of the following: 49 | 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 50 | 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. 51 | e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 52 | 5. Combined Libraries. 53 | 54 | You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: 55 | 56 | a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. 57 | b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 58 | 6. Revised Versions of the GNU Lesser General Public License. 59 | 60 | The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. 61 | 62 | Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License “or any later version” applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. 63 | 64 | If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. 65 | -------------------------------------------------------------------------------- /src/main/java/net/dreamlu/mica/auto/service/AutoServiceProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net). 3 | *

4 | * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.gnu.org/licenses/lgpl.html 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.dreamlu.mica.auto.service; 18 | 19 | import com.google.auto.service.AutoService; 20 | import net.dreamlu.mica.auto.common.AbstractMicaProcessor; 21 | import net.dreamlu.mica.auto.common.MultiSetMap; 22 | import net.ltgt.gradle.incap.IncrementalAnnotationProcessor; 23 | import net.ltgt.gradle.incap.IncrementalAnnotationProcessorType; 24 | 25 | import javax.annotation.processing.*; 26 | import javax.lang.model.element.*; 27 | import javax.lang.model.type.DeclaredType; 28 | import javax.lang.model.type.TypeMirror; 29 | import javax.lang.model.util.Elements; 30 | import javax.lang.model.util.SimpleAnnotationValueVisitor8; 31 | import javax.lang.model.util.Types; 32 | import javax.tools.FileObject; 33 | import javax.tools.StandardLocation; 34 | import java.io.IOException; 35 | import java.io.OutputStream; 36 | import java.util.*; 37 | import java.util.stream.Collectors; 38 | 39 | /** 40 | * java spi 服务自动处理器 参考:google auto 41 | * 42 | * @author L.cm 43 | */ 44 | @SupportedOptions("debug") 45 | @AutoService(Processor.class) 46 | @IncrementalAnnotationProcessor(IncrementalAnnotationProcessorType.AGGREGATING) 47 | public class AutoServiceProcessor extends AbstractMicaProcessor { 48 | /** 49 | * AutoService 注解名 50 | */ 51 | private static final String AUTO_SERVICE_NAME = net.dreamlu.mica.auto.annotation.AutoService.class.getName(); 52 | /** 53 | * spi 服务集合,key 接口 -> value 实现列表 54 | */ 55 | private final MultiSetMap providers = new MultiSetMap<>(); 56 | /** 57 | * 元素辅助类 58 | */ 59 | private Elements elementUtils; 60 | 61 | @Override 62 | public synchronized void init(ProcessingEnvironment processingEnv) { 63 | super.init(processingEnv); 64 | elementUtils = processingEnv.getElementUtils(); 65 | } 66 | 67 | @Override 68 | public Set getSupportedAnnotationTypes() { 69 | return Collections.singleton(AUTO_SERVICE_NAME); 70 | } 71 | 72 | @Override 73 | protected boolean processImpl(Set annotations, RoundEnvironment roundEnv) { 74 | if (roundEnv.processingOver()) { 75 | generateConfigFiles(); 76 | } else { 77 | processAnnotations(annotations, roundEnv); 78 | } 79 | return false; 80 | } 81 | 82 | private void processAnnotations(Set annotations, RoundEnvironment roundEnv) { 83 | TypeElement autoService = elementUtils.getTypeElement(AUTO_SERVICE_NAME); 84 | Set elementSet = roundEnv.getElementsAnnotatedWith(autoService); 85 | // 过滤 TypeElement 86 | Set typeElementSet = elementSet.stream() 87 | .filter(this::isClass) 88 | .filter(e -> e instanceof TypeElement) 89 | .map(e -> (TypeElement) e) 90 | .collect(Collectors.toSet()); 91 | 92 | // 如果为空直接跳出 93 | if (typeElementSet.isEmpty()) { 94 | log("Annotations elementSet is isEmpty"); 95 | return; 96 | } 97 | 98 | log(annotations.toString()); 99 | log(typeElementSet.toString()); 100 | 101 | for (TypeElement typeElement : typeElementSet) { 102 | AnnotationMirror annotationMirror = getAnnotation(elementUtils, typeElement, AUTO_SERVICE_NAME); 103 | if (annotationMirror == null) { 104 | continue; 105 | } 106 | Set typeMirrors = getValueFieldOfClasses(annotationMirror); 107 | if (typeMirrors.isEmpty()) { 108 | error("No service interfaces provided for element!", typeElement, annotationMirror); 109 | continue; 110 | } 111 | // 接口的名称 112 | String providerImplementerName = getQualifiedName(typeElement); 113 | for (TypeMirror typeMirror : typeMirrors) { 114 | String providerInterfaceName = getType(typeMirror); 115 | log("provider interface: " + providerInterfaceName); 116 | log("provider implementer: " + providerImplementerName); 117 | 118 | if (checkImplementer(typeElement, typeMirror)) { 119 | providers.put(providerInterfaceName, getQualifiedName(typeElement)); 120 | } else { 121 | String message = "ServiceProviders must implement their service provider interface. " 122 | + providerImplementerName + " does not implement " + providerInterfaceName; 123 | error(message, typeElement, annotationMirror); 124 | } 125 | } 126 | } 127 | } 128 | 129 | private void generateConfigFiles() { 130 | Filer filer = processingEnv.getFiler(); 131 | for (String providerInterface : providers.keySet()) { 132 | String resourceFile = "META-INF/services/" + providerInterface; 133 | log("Working on resource file: " + resourceFile); 134 | try { 135 | SortedSet allServices = new TreeSet<>(); 136 | // 1. 存在用户手动编写的配置 137 | try { 138 | FileObject existingFile = filer.getResource(StandardLocation.SOURCE_OUTPUT, "", resourceFile); 139 | log("Looking for existing resource file at " + existingFile.toUri()); 140 | Set oldServices = ServicesFiles.readServiceFile(existingFile, elementUtils); 141 | log("Existing service entries: " + oldServices); 142 | allServices.addAll(oldServices); 143 | } catch (IOException e) { 144 | log("Resource file did not already exist."); 145 | } 146 | // 2. 增量编译 147 | try { 148 | FileObject existingFile = filer.getResource(StandardLocation.CLASS_OUTPUT, "", resourceFile); 149 | log("Looking for existing resource file at " + existingFile.toUri()); 150 | Set oldServices = ServicesFiles.readServiceFile(existingFile, elementUtils); 151 | log("Existing service entries: " + oldServices); 152 | allServices.addAll(oldServices); 153 | } catch (IOException e) { 154 | log("Resource file did not already exist."); 155 | } 156 | Set newServices = new HashSet<>(providers.get(providerInterface)); 157 | if (allServices.containsAll(newServices)) { 158 | log("No new service entries being added."); 159 | return; 160 | } 161 | // 3. 注解处理器新扫描出来的 162 | allServices.addAll(newServices); 163 | log("New service file contents: " + allServices); 164 | FileObject fileObject = filer.createResource(StandardLocation.CLASS_OUTPUT, "", resourceFile); 165 | try (OutputStream out = fileObject.openOutputStream()) { 166 | ServicesFiles.writeServiceFile(allServices, out); 167 | } 168 | log("Wrote to: " + fileObject.toUri()); 169 | } catch (IOException e) { 170 | fatalError("Unable to create " + resourceFile + ", " + e); 171 | return; 172 | } 173 | } 174 | } 175 | 176 | /** 177 | * Verifies {@link java.util.spi.LocaleServiceProvider} constraints on the concrete provider class. 178 | * Note that these constraints are enforced at runtime via the ServiceLoader, 179 | * we're just checking them at compile time to be extra nice to our users. 180 | */ 181 | private boolean checkImplementer(Element providerImplementer, TypeMirror providerType) { 182 | // TODO: We're currently only enforcing the subtype relationship 183 | // constraint. It would be nice to enforce them all. 184 | Types types = processingEnv.getTypeUtils(); 185 | return types.isSubtype(providerImplementer.asType(), providerType); 186 | } 187 | 188 | /** 189 | * 读取 AutoService 上的 value 值 190 | * 191 | * @param annotationMirror AnnotationMirror 192 | * @return value 集合 193 | */ 194 | private Set getValueFieldOfClasses(AnnotationMirror annotationMirror) { 195 | return getAnnotationValue(annotationMirror, "value") 196 | .accept(new SimpleAnnotationValueVisitor8, Void>() { 197 | @Override 198 | public Set visitType(TypeMirror typeMirror, Void v) { 199 | return Collections.singleton(typeMirror); 200 | } 201 | 202 | @Override 203 | public Set visitArray( 204 | List values, Void v) { 205 | return values.stream() 206 | .flatMap(value -> value.accept(this, null).stream()) 207 | .collect(Collectors.toSet()); 208 | } 209 | }, null); 210 | } 211 | 212 | 213 | public AnnotationValue getAnnotationValue(AnnotationMirror annotationMirror, String elementName) { 214 | Objects.requireNonNull(annotationMirror); 215 | Objects.requireNonNull(elementName); 216 | for (Map.Entry entry : elementUtils.getElementValuesWithDefaults(annotationMirror).entrySet()) { 217 | if (entry.getKey().getSimpleName().contentEquals(elementName)) { 218 | return entry.getValue(); 219 | } 220 | } 221 | String annotationName = annotationMirror.getAnnotationType().toString(); 222 | throw new IllegalArgumentException(String.format("@%s does not define an element %s()", annotationName, elementName)); 223 | } 224 | 225 | public String getType(TypeMirror type) { 226 | if (type == null) { 227 | return null; 228 | } 229 | if (type instanceof DeclaredType) { 230 | DeclaredType declaredType = (DeclaredType) type; 231 | Element enclosingElement = declaredType.asElement().getEnclosingElement(); 232 | if (enclosingElement instanceof TypeElement) { 233 | return getQualifiedName(enclosingElement) + "$" + declaredType.asElement().getSimpleName().toString(); 234 | } else { 235 | return getQualifiedName(declaredType.asElement()); 236 | } 237 | } 238 | return type.toString(); 239 | } 240 | 241 | } 242 | -------------------------------------------------------------------------------- /src/main/java/net/dreamlu/mica/auto/factories/AutoFactoriesProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2029, Dreamlu 卢春梦 (596392912@qq.com & www.dreamlu.net). 3 | *

4 | * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.gnu.org/licenses/lgpl.html 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package net.dreamlu.mica.auto.factories; 18 | 19 | import com.google.auto.service.AutoService; 20 | import net.dreamlu.mica.auto.annotation.AutoIgnore; 21 | import net.dreamlu.mica.auto.common.AbstractMicaProcessor; 22 | import net.dreamlu.mica.auto.common.BootAutoType; 23 | import net.dreamlu.mica.auto.common.MultiSetMap; 24 | import net.ltgt.gradle.incap.IncrementalAnnotationProcessor; 25 | import net.ltgt.gradle.incap.IncrementalAnnotationProcessorType; 26 | 27 | import javax.annotation.processing.*; 28 | import javax.lang.model.element.Element; 29 | import javax.lang.model.element.ElementKind; 30 | import javax.lang.model.element.TypeElement; 31 | import javax.lang.model.util.Elements; 32 | import javax.tools.FileObject; 33 | import javax.tools.StandardLocation; 34 | import java.io.IOException; 35 | import java.io.OutputStream; 36 | import java.net.URI; 37 | import java.net.URISyntaxException; 38 | import java.nio.file.Path; 39 | import java.nio.file.Paths; 40 | import java.util.LinkedHashSet; 41 | import java.util.Set; 42 | import java.util.stream.Collectors; 43 | 44 | /** 45 | * spring boot 自动配置处理器 46 | * 47 | * @author L.cm 48 | */ 49 | @AutoService(Processor.class) 50 | @SupportedAnnotationTypes("*") 51 | @SupportedOptions("debug") 52 | @IncrementalAnnotationProcessor(IncrementalAnnotationProcessorType.AGGREGATING) 53 | public class AutoFactoriesProcessor extends AbstractMicaProcessor { 54 | /** 55 | * 处理的注解 @FeignClient 56 | */ 57 | private static final String FEIGN_CLIENT_ANNOTATION = "org.springframework.cloud.openfeign.FeignClient"; 58 | /** 59 | * Feign 自动配置 60 | */ 61 | private static final String FEIGN_AUTO_CONFIGURE_KEY = "net.dreamlu.mica.feign.MicaFeignAutoConfiguration"; 62 | /** 63 | * The location to look for factories. 64 | *

Can be present in multiple JAR files. 65 | */ 66 | private static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories"; 67 | /** 68 | * devtools,有 Configuration 注解的 jar 一般需要 devtools 配置文件 69 | */ 70 | private static final String DEVTOOLS_RESOURCE_LOCATION = "META-INF/spring-devtools.properties"; 71 | /** 72 | * AutoConfiguration 注解 73 | */ 74 | private static final String AUTO_CONFIGURATION = "org.springframework.boot.autoconfigure.AutoConfiguration"; 75 | /** 76 | * AutoConfiguration imports out put 77 | */ 78 | private static final String AUTO_CONFIGURATION_IMPORTS_LOCATION = "META-INF/spring/" + AUTO_CONFIGURATION + ".imports"; 79 | /** 80 | * 数据承载 81 | */ 82 | private final MultiSetMap factories = new MultiSetMap<>(); 83 | /** 84 | * spring boot 2.7 @AutoConfiguration 85 | */ 86 | private final Set autoConfigurationImportsSet = new LinkedHashSet<>(); 87 | 88 | /** 89 | * 元素辅助类 90 | */ 91 | private Elements elementUtils; 92 | 93 | @Override 94 | public synchronized void init(ProcessingEnvironment processingEnv) { 95 | super.init(processingEnv); 96 | elementUtils = processingEnv.getElementUtils(); 97 | } 98 | 99 | @Override 100 | protected boolean processImpl(Set annotations, RoundEnvironment roundEnv) { 101 | if (roundEnv.processingOver()) { 102 | // 1. 生成 spring boot 2.7.x @AutoConfiguration 103 | generateAutoConfigurationImportsFiles(); 104 | // 2. 生成 spring.factories 105 | generateFactoriesFiles(); 106 | } else { 107 | processAnnotations(annotations, roundEnv); 108 | } 109 | return false; 110 | } 111 | 112 | private void processAnnotations(Set annotations, RoundEnvironment roundEnv) { 113 | // 日志 打印信息 gradle build --debug 114 | log(annotations.toString()); 115 | Set elementSet = roundEnv.getRootElements(); 116 | log("All Element set: " + elementSet.toString()); 117 | 118 | // 过滤 TypeElement 119 | Set typeElementSet = elementSet.stream() 120 | .filter(this::isClassOrInterface) 121 | .filter(e -> e instanceof TypeElement) 122 | .map(e -> (TypeElement) e) 123 | .collect(Collectors.toSet()); 124 | // 如果为空直接跳出 125 | if (typeElementSet.isEmpty()) { 126 | log("Annotations elementSet is isEmpty"); 127 | return; 128 | } 129 | for (TypeElement typeElement : typeElementSet) { 130 | // ignore @AutoIgnore Element 131 | if (isAnnotation(elementUtils, typeElement, AutoIgnore.class.getName())) { 132 | log("Found @AutoIgnore annotation,ignore Element: " + typeElement.toString()); 133 | } else if (isAnnotation(elementUtils, typeElement, FEIGN_CLIENT_ANNOTATION)) { 134 | log("Found @FeignClient Element: " + typeElement.toString()); 135 | 136 | ElementKind elementKind = typeElement.getKind(); 137 | // Feign Client 只处理 接口 138 | if (ElementKind.INTERFACE != elementKind) { 139 | fatalError("@FeignClient Element " + typeElement + " 不是接口。"); 140 | continue; 141 | } 142 | 143 | String factoryName = typeElement.getQualifiedName().toString(); 144 | if (factories.containsVal(factoryName)) { 145 | continue; 146 | } 147 | 148 | log("读取到新配置 spring.factories factoryName:" + factoryName); 149 | factories.put(FEIGN_AUTO_CONFIGURE_KEY, factoryName); 150 | } else { 151 | // 1. 生成 2.7.x 的 spi 152 | if (isAnnotation(elementUtils, typeElement, BootAutoType.COMPONENT_ANNOTATION)) { 153 | String autoConfigurationBeanName = typeElement.getQualifiedName().toString(); 154 | autoConfigurationImportsSet.add(autoConfigurationBeanName); 155 | log("读取到自动配置 @AutoConfiguration:" + autoConfigurationBeanName); 156 | } 157 | // 2. 老的 spring.factories 158 | for (BootAutoType autoType : BootAutoType.values()) { 159 | String annotation = autoType.getAnnotation(); 160 | if (isAnnotation(elementUtils, typeElement, annotation)) { 161 | log("Found @" + annotation + " Element: " + typeElement.toString()); 162 | 163 | String factoryName = typeElement.getQualifiedName().toString(); 164 | if (factories.containsVal(factoryName)) { 165 | continue; 166 | } 167 | 168 | log("读取到新配置 spring.factories factoryName:" + factoryName); 169 | factories.put(autoType.getConfigureKey(), factoryName); 170 | } 171 | } 172 | } 173 | } 174 | } 175 | 176 | private void generateFactoriesFiles() { 177 | if (factories.isEmpty()) { 178 | return; 179 | } 180 | Filer filer = processingEnv.getFiler(); 181 | try { 182 | // spring.factories 配置 183 | MultiSetMap allFactories = new MultiSetMap<>(); 184 | // 1. 用户手动配置项目下的 spring.factories 文件 185 | try { 186 | FileObject existingFactoriesFile = filer.getResource(StandardLocation.SOURCE_OUTPUT, "", FACTORIES_RESOURCE_LOCATION); 187 | // 查找是否已经存在 spring.factories 188 | log("Looking for existing spring.factories file at " + existingFactoriesFile.toUri()); 189 | MultiSetMap existingFactories = FactoriesFiles.readFactoriesFile(existingFactoriesFile, elementUtils); 190 | log("Existing spring.factories entries: " + existingFactories); 191 | allFactories.putAll(existingFactories); 192 | } catch (IOException e) { 193 | log("spring.factories resource file not found."); 194 | } 195 | // 2. 增量编译,已经存在的 spring.factories 文件 196 | try { 197 | FileObject existingFactoriesFile = filer.getResource(StandardLocation.CLASS_OUTPUT, "", FACTORIES_RESOURCE_LOCATION); 198 | // 查找是否已经存在 spring.factories 199 | log("Looking for existing spring.factories file at " + existingFactoriesFile.toUri()); 200 | MultiSetMap existingFactories = FactoriesFiles.readFactoriesFile(existingFactoriesFile, elementUtils); 201 | log("Existing spring.factories entries: " + existingFactories); 202 | allFactories.putAll(existingFactories); 203 | } catch (IOException e) { 204 | log("spring.factories resource file did not already exist."); 205 | } 206 | // 3. 处理器扫描出来的新的配置 207 | allFactories.putAll(factories); 208 | log("New spring.factories file contents: " + allFactories); 209 | FileObject factoriesFile = filer.createResource(StandardLocation.CLASS_OUTPUT, "", FACTORIES_RESOURCE_LOCATION); 210 | try (OutputStream out = factoriesFile.openOutputStream()) { 211 | FactoriesFiles.writeFactoriesFile(allFactories, out); 212 | } 213 | // 4. devtools 配置,因为有 @Configuration 注解的需要 devtools 214 | String classesPath = factoriesFile.toUri().toString().split("classes")[0]; 215 | Path projectPath = Paths.get(new URI(classesPath)).getParent(); 216 | String projectName = projectPath.getFileName().toString(); 217 | FileObject devToolsFile = filer.createResource(StandardLocation.CLASS_OUTPUT, "", DEVTOOLS_RESOURCE_LOCATION); 218 | try (OutputStream out = devToolsFile.openOutputStream()) { 219 | FactoriesFiles.writeDevToolsFile(projectName, out); 220 | } 221 | } catch (IOException | URISyntaxException e) { 222 | fatalError(e); 223 | } 224 | } 225 | 226 | private void generateAutoConfigurationImportsFiles() { 227 | if (autoConfigurationImportsSet.isEmpty()) { 228 | return; 229 | } 230 | Filer filer = processingEnv.getFiler(); 231 | try { 232 | // AutoConfiguration 配置 233 | Set allAutoConfigurationImports = new LinkedHashSet<>(); 234 | // 1. 用户手动配置项目下的 AutoConfiguration 文件 235 | try { 236 | FileObject existingFactoriesFile = filer.getResource(StandardLocation.SOURCE_OUTPUT, "", AUTO_CONFIGURATION_IMPORTS_LOCATION); 237 | // 查找是否已经存在 spring.factories 238 | log("Looking for existing AutoConfiguration imports file at " + existingFactoriesFile.toUri()); 239 | Set existingSet = FactoriesFiles.readAutoConfigurationImports(existingFactoriesFile); 240 | log("Existing AutoConfiguration imports entries: " + existingSet); 241 | allAutoConfigurationImports.addAll(existingSet); 242 | } catch (IOException e) { 243 | log("AutoConfiguration imports resource file not found."); 244 | } 245 | // 2. 增量编译,已经存在的配置文件 246 | try { 247 | FileObject existingFactoriesFile = filer.getResource(StandardLocation.CLASS_OUTPUT, "", AUTO_CONFIGURATION_IMPORTS_LOCATION); 248 | // 查找是否已经存在 spring.factories 249 | log("Looking for existing AutoConfiguration imports file at " + existingFactoriesFile.toUri()); 250 | Set existingSet = FactoriesFiles.readAutoConfigurationImports(existingFactoriesFile); 251 | log("Existing AutoConfiguration imports entries: " + existingSet); 252 | allAutoConfigurationImports.addAll(existingSet); 253 | } catch (IOException e) { 254 | log("AutoConfiguration imports resource file did not already exist."); 255 | } 256 | // 3. 处理器扫描出来的新的配置 257 | allAutoConfigurationImports.addAll(autoConfigurationImportsSet); 258 | log("New AutoConfiguration imports file contents: " + allAutoConfigurationImports); 259 | FileObject autoConfigurationImportsFile = filer.createResource(StandardLocation.CLASS_OUTPUT, "", AUTO_CONFIGURATION_IMPORTS_LOCATION); 260 | try (OutputStream out = autoConfigurationImportsFile.openOutputStream()) { 261 | FactoriesFiles.writeAutoConfigurationImportsFile(allAutoConfigurationImports, out); 262 | } 263 | } catch (IOException e) { 264 | fatalError(e); 265 | } 266 | } 267 | 268 | } 269 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | net.dreamlu 7 | mica-auto 8 | 4.0.1 9 | jar 10 | 11 | mica-auto 12 | An enhanced toolkit of Spring cloud to simplify development. 13 | https://github.com/lets-mica/mica-auto 14 | 15 | 16 | UTF-8 17 | 17 18 | 3.5.0 19 | 4.0.1 20 | 1.18.42 21 | 1.1.1 22 | 0.23.0 23 | 1.0.0 24 | 25 | 26 | 27 | scm:git:https://github.com/lets-mica/mica-auto.git 28 | scm:git:git@github.com:lets-mica/mica-auto.git 29 | https://github.com/lets-mica/mica-auto.git 30 | 31 | 32 | 33 | 34 | GNU LESSER GENERAL PUBLIC LICENSE 35 | https://www.gnu.org/licenses/lgpl-3.0.en.html 36 | 37 | 38 | 39 | 40 | 41 | Dreamlu 42 | qq596392912@gmail.com 43 | 44 | 45 | 46 | 47 | 48 | org.springframework.boot 49 | spring-boot-configuration-processor 50 | ${spring.boot.version} 51 | 52 | 53 | org.springframework.boot 54 | spring-boot-autoconfigure-processor 55 | ${spring.boot.version} 56 | 57 | 58 | org.springframework.boot 59 | spring-boot-autoconfigure 60 | ${spring.boot.version} 61 | provided 62 | 63 | 64 | org.springframework.boot 65 | spring-boot-starter-jdbc 66 | ${spring.boot.version} 67 | provided 68 | 69 | 70 | org.projectlombok 71 | lombok 72 | ${lombok.version} 73 | provided 74 | 75 | 76 | com.google.auto.service 77 | auto-service 78 | ${google.auto.service.version} 79 | provided 80 | 81 | 82 | net.ltgt.gradle.incap 83 | incap 84 | ${incap.version} 85 | provided 86 | 87 | 88 | 89 | com.google.testing.compile 90 | compile-testing 91 | ${compile.testing.version} 92 | test 93 | 94 | 95 | 96 | 97 | 98 | 99 | org.apache.maven.plugins 100 | maven-compiler-plugin 101 | 3.14.1 102 | 103 | ${java.version} 104 | ${java.version} 105 | ${java.version} 106 | ${project.build.sourceEncoding} 107 | true 108 | true 109 | 110 | -Xlint:unchecked 111 | -Xlint:deprecation 112 | 113 | 114 | 115 | org.projectlombok 116 | lombok 117 | ${lombok.version} 118 | 119 | 120 | com.google.auto.service 121 | auto-service 122 | ${google.auto.service.version} 123 | 124 | 125 | net.ltgt.gradle.incap 126 | incap-processor 127 | ${incap.version} 128 | 129 | 130 | 131 | 132 | 133 | 134 | org.apache.maven.plugins 135 | maven-jar-plugin 136 | ${maven-jar-plugin.version} 137 | 138 | 139 | 140 | true 141 | 142 | 143 | true 144 | true 145 | true 146 | 147 | 148 | false 149 | 150 | 151 | 152 | 153 | 154 | org.apache.maven.plugins 155 | maven-source-plugin 156 | 3.4.0 157 | 158 | 159 | attach-sources 160 | verify 161 | 162 | jar-no-fork 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | org.sonatype.central 173 | central-publishing-maven-plugin 174 | 0.9.0 175 | true 176 | 177 | central 178 | true 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | develop 188 | 189 | true 190 | 191 | 192 | 193 | aliyun 194 | aliyun 195 | https://maven.aliyun.com/repository/public/ 196 | 197 | false 198 | 199 | 200 | true 201 | 202 | 203 | 204 | 205 | 206 | snapshot 207 | 208 | 209 | central 210 | https://central.sonatype.com/repository/maven-snapshots/ 211 | 212 | 213 | 214 | 215 | 216 | 217 | org.sonatype.central 218 | central-publishing-maven-plugin 219 | 220 | 221 | 222 | 223 | 224 | release 225 | 226 | 227 | 228 | 229 | org.apache.maven.plugins 230 | maven-javadoc-plugin 231 | 3.12.0 232 | 233 | 234 | package 235 | 236 | jar 237 | 238 | 239 | 240 | 241 | 242 | 243 | org.apache.maven.plugins 244 | maven-gpg-plugin 245 | 3.2.8 246 | 247 | 248 | verify 249 | 250 | sign 251 | 252 | 253 | 254 | 255 | 256 | --pinentry-mode 257 | loopback 258 | 259 | 260 | 261 | 262 | 263 | org.sonatype.central 264 | central-publishing-maven-plugin 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | --------------------------------------------------------------------------------