├── LICENSE
├── README.md
├── ace-merge-core
├── ace-merge-core.iml
├── pom.xml
├── src
│ └── main
│ │ └── java
│ │ └── com
│ │ └── github
│ │ └── wxiaoqi
│ │ └── merge
│ │ ├── EnableAceMerge.java
│ │ ├── annonation
│ │ ├── MergeField.java
│ │ └── MergeResult.java
│ │ ├── aspect
│ │ └── MergeAspect.java
│ │ ├── configuration
│ │ ├── MergeAutoConfiguration.java
│ │ └── MergeProperties.java
│ │ ├── core
│ │ ├── BeanFactoryUtils.java
│ │ └── MergeCore.java
│ │ └── facade
│ │ ├── DefaultMergeResultParser.java
│ │ └── IMergeResultParser.java
└── target
│ ├── ace-merge-core-2.0-SNAPSHOT.jar
│ ├── classes
│ └── com
│ │ └── github
│ │ └── wxiaoqi
│ │ └── merge
│ │ ├── EnableAceMerge.class
│ │ ├── annonation
│ │ ├── MergeField.class
│ │ └── MergeResult.class
│ │ ├── aspect
│ │ └── MergeAspect.class
│ │ ├── configuration
│ │ ├── MergeAutoConfiguration.class
│ │ └── MergeProperties.class
│ │ ├── core
│ │ ├── BeanFactoryUtils.class
│ │ ├── MergeCore$1.class
│ │ └── MergeCore.class
│ │ └── facade
│ │ ├── DefaultMergeResultParser.class
│ │ └── IMergeResultParser.class
│ ├── maven-archiver
│ └── pom.properties
│ └── maven-status
│ └── maven-compiler-plugin
│ ├── compile
│ └── default-compile
│ │ ├── createdFiles.lst
│ │ └── inputFiles.lst
│ └── testCompile
│ └── default-testCompile
│ └── inputFiles.lst
├── ace-merge-demo
├── ace-data-merge-demo
│ ├── ace-data-merge-demo.iml
│ ├── pom.xml
│ ├── src
│ │ └── main
│ │ │ ├── java
│ │ │ └── com
│ │ │ │ └── github
│ │ │ │ └── wxiaoqi
│ │ │ │ └── ace
│ │ │ │ └── merge
│ │ │ │ └── demo
│ │ │ │ ├── DemoBootstrap.java
│ │ │ │ ├── biz
│ │ │ │ └── UserBiz.java
│ │ │ │ ├── entity
│ │ │ │ └── User.java
│ │ │ │ ├── feign
│ │ │ │ └── IDataFeign.java
│ │ │ │ ├── merge
│ │ │ │ └── TestMergeResultParser.java
│ │ │ │ └── rest
│ │ │ │ └── UserRest.java
│ │ │ └── resources
│ │ │ └── application.yml
│ └── target
│ │ ├── ace-data-merge-demo-2.0-SNAPSHOT.jar
│ │ ├── classes
│ │ ├── application.yml
│ │ └── com
│ │ │ └── github
│ │ │ └── wxiaoqi
│ │ │ └── ace
│ │ │ └── merge
│ │ │ └── demo
│ │ │ ├── DemoBootstrap.class
│ │ │ ├── biz
│ │ │ └── UserBiz.class
│ │ │ ├── entity
│ │ │ └── User.class
│ │ │ ├── feign
│ │ │ └── IDataFeign.class
│ │ │ ├── merge
│ │ │ └── TestMergeResultParser.class
│ │ │ └── rest
│ │ │ └── UserRest.class
│ │ ├── maven-archiver
│ │ └── pom.properties
│ │ └── maven-status
│ │ └── maven-compiler-plugin
│ │ ├── compile
│ │ └── default-compile
│ │ │ ├── createdFiles.lst
│ │ │ └── inputFiles.lst
│ │ └── testCompile
│ │ └── default-testCompile
│ │ └── inputFiles.lst
├── ace-data-provider
│ ├── ace-data-provider.iml
│ ├── pom.xml
│ ├── src
│ │ └── main
│ │ │ ├── java
│ │ │ └── com
│ │ │ │ └── github
│ │ │ │ └── wxiaoqi
│ │ │ │ └── ace
│ │ │ │ └── merge
│ │ │ │ └── provider
│ │ │ │ ├── ProviderBootstrap.java
│ │ │ │ └── rest
│ │ │ │ └── DataRest.java
│ │ │ └── resources
│ │ │ └── application.yml
│ └── target
│ │ ├── ace-data-provider-1.0-SNAPSHOT.jar
│ │ ├── classes
│ │ ├── application.yml
│ │ └── com
│ │ │ └── github
│ │ │ └── wxiaoqi
│ │ │ └── ace
│ │ │ └── merge
│ │ │ └── provider
│ │ │ ├── ProviderBootstrap.class
│ │ │ └── rest
│ │ │ └── DataRest.class
│ │ ├── maven-archiver
│ │ └── pom.properties
│ │ └── maven-status
│ │ └── maven-compiler-plugin
│ │ ├── compile
│ │ └── default-compile
│ │ │ ├── createdFiles.lst
│ │ │ └── inputFiles.lst
│ │ └── testCompile
│ │ └── default-testCompile
│ │ └── inputFiles.lst
├── ace-eureka
│ ├── ace-eureka.iml
│ ├── pom.xml
│ ├── src
│ │ └── main
│ │ │ ├── java
│ │ │ └── com
│ │ │ │ └── github
│ │ │ │ └── wxiaoqi
│ │ │ │ └── ace
│ │ │ │ └── merge
│ │ │ │ └── center
│ │ │ │ └── CenterBootstrap.java
│ │ │ └── resources
│ │ │ └── application.yml
│ └── target
│ │ ├── ace-eureka-1.0-SNAPSHOT.jar
│ │ ├── classes
│ │ ├── application.yml
│ │ └── com
│ │ │ └── github
│ │ │ └── wxiaoqi
│ │ │ └── ace
│ │ │ └── merge
│ │ │ └── center
│ │ │ └── CenterBootstrap.class
│ │ ├── maven-archiver
│ │ └── pom.properties
│ │ └── maven-status
│ │ └── maven-compiler-plugin
│ │ ├── compile
│ │ └── default-compile
│ │ │ ├── createdFiles.lst
│ │ │ └── inputFiles.lst
│ │ └── testCompile
│ │ └── default-testCompile
│ │ └── inputFiles.lst
├── ace-merge-demo.iml
└── pom.xml
├── ace-merge-parent.iml
└── pom.xml
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction, and
10 | distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by the copyright
13 | owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all other entities
16 | that control, are controlled by, or are under common control with that entity.
17 | For the purposes of this definition, "control" means (i) the power, direct or
18 | indirect, to cause the direction or management of such entity, whether by
19 | contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
20 | outstanding shares, or (iii) beneficial ownership of such entity.
21 |
22 | "You" (or "Your") shall mean an individual or Legal Entity exercising
23 | permissions granted by this License.
24 |
25 | "Source" form shall mean the preferred form for making modifications, including
26 | but not limited to software source code, documentation source, and configuration
27 | files.
28 |
29 | "Object" form shall mean any form resulting from mechanical transformation or
30 | translation of a Source form, including but not limited to compiled object code,
31 | generated documentation, and conversions to other media types.
32 |
33 | "Work" shall mean the work of authorship, whether in Source or Object form, made
34 | available under the License, as indicated by a copyright notice that is included
35 | in or attached to the work (an example is provided in the Appendix below).
36 |
37 | "Derivative Works" shall mean any work, whether in Source or Object form, that
38 | is based on (or derived from) the Work and for which the editorial revisions,
39 | annotations, elaborations, or other modifications represent, as a whole, an
40 | original work of authorship. For the purposes of this License, Derivative Works
41 | shall not include works that remain separable from, or merely link (or bind by
42 | name) to the interfaces of, the Work and Derivative Works thereof.
43 |
44 | "Contribution" shall mean any work of authorship, including the original version
45 | of the Work and any modifications or additions to that Work or Derivative Works
46 | thereof, that is intentionally submitted to Licensor for inclusion in the Work
47 | by the copyright owner or by an individual or Legal Entity authorized to submit
48 | on behalf of the copyright owner. For the purposes of this definition,
49 | "submitted" means any form of electronic, verbal, or written communication sent
50 | to the Licensor or its representatives, including but not limited to
51 | communication on electronic mailing lists, source code control systems, and
52 | issue tracking systems that are managed by, or on behalf of, the Licensor for
53 | the purpose of discussing and improving the Work, but excluding communication
54 | that is conspicuously marked or otherwise designated in writing by the copyright
55 | owner as "Not a Contribution."
56 |
57 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf
58 | of whom a Contribution has been received by Licensor and subsequently
59 | incorporated within the Work.
60 |
61 | 2. Grant of Copyright License.
62 |
63 | Subject to the terms and conditions of this License, each Contributor hereby
64 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
65 | irrevocable copyright license to reproduce, prepare Derivative Works of,
66 | publicly display, publicly perform, sublicense, and distribute the Work and such
67 | Derivative Works in Source or Object form.
68 |
69 | 3. Grant of Patent License.
70 |
71 | Subject to the terms and conditions of this License, each Contributor hereby
72 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
73 | irrevocable (except as stated in this section) patent license to make, have
74 | made, use, offer to sell, sell, import, and otherwise transfer the Work, where
75 | such license applies only to those patent claims licensable by such Contributor
76 | that are necessarily infringed by their Contribution(s) alone or by combination
77 | of their Contribution(s) with the Work to which such Contribution(s) was
78 | submitted. If You institute patent litigation against any entity (including a
79 | cross-claim or counterclaim in a lawsuit) alleging that the Work or a
80 | Contribution incorporated within the Work constitutes direct or contributory
81 | patent infringement, then any patent licenses granted to You under this License
82 | for that Work shall terminate as of the date such litigation is filed.
83 |
84 | 4. Redistribution.
85 |
86 | You may reproduce and distribute copies of the Work or Derivative Works thereof
87 | in any medium, with or without modifications, and in Source or Object form,
88 | provided that You meet the following conditions:
89 |
90 | You must give any other recipients of the Work or Derivative Works a copy of
91 | this License; and
92 | You must cause any modified files to carry prominent notices stating that You
93 | changed the files; and
94 | You must retain, in the Source form of any Derivative Works that You distribute,
95 | all copyright, patent, trademark, and attribution notices from the Source form
96 | of the Work, excluding those notices that do not pertain to any part of the
97 | Derivative Works; and
98 | If the Work includes a "NOTICE" text file as part of its distribution, then any
99 | Derivative Works that You distribute must include a readable copy of the
100 | attribution notices contained within such NOTICE file, excluding those notices
101 | that do not pertain to any part of the Derivative Works, in at least one of the
102 | following places: within a NOTICE text file distributed as part of the
103 | Derivative Works; within the Source form or documentation, if provided along
104 | with the Derivative Works; or, within a display generated by the Derivative
105 | Works, if and wherever such third-party notices normally appear. The contents of
106 | the NOTICE file are for informational purposes only and do not modify the
107 | License. You may add Your own attribution notices within Derivative Works that
108 | You distribute, alongside or as an addendum to the NOTICE text from the Work,
109 | provided that such additional attribution notices cannot be construed as
110 | modifying the License.
111 | You may add Your own copyright statement to Your modifications and may provide
112 | additional or different license terms and conditions for use, reproduction, or
113 | distribution of Your modifications, or for any such Derivative Works as a whole,
114 | provided Your use, reproduction, and distribution of the Work otherwise complies
115 | with the conditions stated in this License.
116 |
117 | 5. Submission of Contributions.
118 |
119 | Unless You explicitly state otherwise, any Contribution intentionally submitted
120 | for inclusion in the Work by You to the Licensor shall be under the terms and
121 | conditions of this License, without any additional terms or conditions.
122 | Notwithstanding the above, nothing herein shall supersede or modify the terms of
123 | any separate license agreement you may have executed with Licensor regarding
124 | such Contributions.
125 |
126 | 6. Trademarks.
127 |
128 | This License does not grant permission to use the trade names, trademarks,
129 | service marks, or product names of the Licensor, except as required for
130 | reasonable and customary use in describing the origin of the Work and
131 | reproducing the content of the NOTICE file.
132 |
133 | 7. Disclaimer of Warranty.
134 |
135 | Unless required by applicable law or agreed to in writing, Licensor provides the
136 | Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
137 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
138 | including, without limitation, any warranties or conditions of TITLE,
139 | NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
140 | solely responsible for determining the appropriateness of using or
141 | redistributing the Work and assume any risks associated with Your exercise of
142 | permissions under this License.
143 |
144 | 8. Limitation of Liability.
145 |
146 | In no event and under no legal theory, whether in tort (including negligence),
147 | contract, or otherwise, unless required by applicable law (such as deliberate
148 | and grossly negligent acts) or agreed to in writing, shall any Contributor be
149 | liable to You for damages, including any direct, indirect, special, incidental,
150 | or consequential damages of any character arising as a result of this License or
151 | out of the use or inability to use the Work (including but not limited to
152 | damages for loss of goodwill, work stoppage, computer failure or malfunction, or
153 | any and all other commercial damages or losses), even if such Contributor has
154 | been advised of the possibility of such damages.
155 |
156 | 9. Accepting Warranty or Additional Liability.
157 |
158 | While redistributing the Work or Derivative Works thereof, You may choose to
159 | offer, and charge a fee for, acceptance of support, warranty, indemnity, or
160 | other liability obligations and/or rights consistent with this License. However,
161 | in accepting such obligations, You may act only on Your own behalf and on Your
162 | sole responsibility, not on behalf of any other Contributor, and only if You
163 | agree to indemnify, defend, and hold each Contributor harmless for any liability
164 | incurred by, or claims asserted against, such Contributor by reason of your
165 | accepting any such warranty or additional liability.
166 |
167 | END OF TERMS AND CONDITIONS
168 |
169 | APPENDIX: How to apply the Apache License to your work
170 |
171 | To apply the Apache License to your work, attach the following boilerplate
172 | notice, with the fields enclosed by brackets "{}" replaced with your own
173 | identifying information. (Don't include the brackets!) The text should be
174 | enclosed in the appropriate comment syntax for the file format. We also
175 | recommend that a file or class name and description of purpose be included on
176 | the same "printed page" as the copyright notice for easier identification within
177 | third-party archives.
178 |
179 | Copyright 2018 老A
180 |
181 | Licensed under the Apache License, Version 2.0 (the "License");
182 | you may not use this file except in compliance with the License.
183 | You may obtain a copy of the License at
184 |
185 | http://www.apache.org/licenses/LICENSE-2.0
186 |
187 | Unless required by applicable law or agreed to in writing, software
188 | distributed under the License is distributed on an "AS IS" BASIS,
189 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
190 | See the License for the specific language governing permissions and
191 | limitations under the License.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AG-Merge
2 | Spring Cloud 跨服务数据聚合框架
3 |
4 | # 解决问题
5 | 解决Spring Cloud服务拆分后分页数据的属性或单个对象的属性拆分之痛,
6 | 支持对静态数据属性(数据字典)、动态主键数据进行自动注入和转化, 其中聚合的静态数据会进行`一级混存`(guava).
7 |
8 | # 示例
9 | 具体示例代码可以看`ace-merge-demo`模块
10 | ```
11 | |------- ace-eureka 注册中心
12 | |------- ace-data-merge-demo 查询数据,此处聚合示例
13 | |------- ace-data-provider 数据提供者
14 | ```
15 |
16 | ## Maven添加依赖
17 | ```
18 |
19 | com.github.wxiaoqi
20 | ace-merge-core
21 | 2.0-SNAPSHOT
22 |
23 | ```
24 | ## 启动类加注解
25 | ```
26 | @EnableAceMerge
27 | ```
28 | ## application.yml配置
29 | ```
30 | # 跨服务数据合并
31 | merge:
32 | enabled: true
33 | guavaCacheNumMaxSize: 1000
34 | guavaCacheRefreshWriteTime: 10 # min
35 | guavaCacheRefreshThreadPoolSize: 10
36 | aop: # 启动注解的方式,自动聚合
37 | enabled: true
38 |
39 | ```
40 |
41 | ## 代码示例(`@MergeField`标志对象的数据需要聚合)
42 | ```
43 | @Retention(RetentionPolicy.RUNTIME)
44 | @Target(value={ElementType.METHOD,ElementType.TYPE,ElementType.FIELD})
45 | public @interface MergeField {
46 | /**
47 | * 查询值
48 | * @return
49 | */
50 | String key() default "";
51 |
52 | /**
53 | * 目标类
54 | * @return
55 | */
56 | Class extends Object> feign() default Object.class;
57 |
58 | /**
59 | * 调用方法
60 | * @return
61 | */
62 | String method() default "";
63 |
64 | /**
65 | * 是否以属性值合并作为查询值
66 | * @return
67 | */
68 | boolean isValueNeedMerge() default false;
69 | }
70 | ```
71 | - 聚合对象
72 |
73 | ```
74 | public class User {
75 | private String name;
76 | // 需要聚合的属性
77 | @MergeField(key="test", feign = IService2.class,method = "writeLog")
78 | private String sex;
79 | // 需要聚合的属性
80 | @MergeField(feign = IService2.class,method = "getCitys",isValueNeedMerge = true)
81 | private String city;
82 |
83 | public User(String name, String sex, String city) {
84 | this.name = name;
85 | this.sex = sex;
86 | this.city = city;
87 | }
88 |
89 | public String getCity() {
90 | return city;
91 | }
92 |
93 | public void setCity(String city) {
94 | this.city = city;
95 | }
96 |
97 | public User(String name) {
98 | this.name = name;
99 | }
100 |
101 | public User(String name, String sex) {
102 | this.name = name;
103 | this.sex = sex;
104 | }
105 |
106 | public String getName() {
107 | return name;
108 | }
109 |
110 | public void setName(String name) {
111 | this.name = name;
112 | }
113 |
114 | public String getSex() {
115 | return sex;
116 | }
117 |
118 | public void setSex(String sex) {
119 | this.sex = sex;
120 | }
121 | }
122 | ```
123 |
124 | - 聚合数据来源方法(示例为通过FeignClient,也可以是本地的spring bean对象)
125 |
126 | 特别要求:入参必须为一个String,返回值必须为Map.
127 | 其中返回值的构成,就是聚合对象属性的key和对应的value.
128 |
129 | ```
130 | @FeignClient("test")
131 | public interface IService2 {
132 | @RequestMapping("car/do")
133 | public Map writeLog(String test);
134 |
135 | @RequestMapping("car/city")
136 | public Map getCitys(String ids);
137 | }
138 |
139 | ```
140 |
141 | 对应的远程服务接口
142 | ```
143 | /**
144 | * @author ace
145 | * @create 2017/11/20.
146 | */
147 | @RestController
148 | @RequestMapping("car")
149 | public class Service2Rest {
150 | private Logger logger = LoggerFactory.getLogger(Service2Rest.class);
151 |
152 | @RequestMapping("do")
153 | public Map writeLog(String test){
154 | logger.info("service 2 is writing log!");
155 | Map map = new HashMap();
156 | map.put("man","男");
157 | map.put("woman","女");
158 | return map;
159 | }
160 |
161 | @RequestMapping("city")
162 | public Map getCity(String ids){
163 | logger.info("service 2 is writing log!"+ids);
164 | Map map = new HashMap();
165 | map.put("1","广州");
166 | map.put("2","武汉");
167 | return map;
168 | }
169 | }
170 | ```
171 | - 聚合对象的Biz类(下面的方式是采用aop扫描注解的方式)
172 |
173 | ```
174 | @Service
175 | @Slf4j
176 | public class UserBiz {
177 | @Autowired
178 | private MergeCore mergeCore;
179 | /**
180 | * aop注解的聚合方式
181 | * 其中聚合的方法返回值必须为list,
182 | * 如果为复杂对象,则需要自定义自己的聚合解析器(实现接口IMergeResultParser)
183 | */
184 | @MergeResult(resultParser = TestMergeResultParser.class)
185 | public List getAopUser() {
186 | ArrayList users = new ArrayList();
187 | for (int i = 1000; i > 0; i--) {
188 | users.add(new User("zhangsan" + i, "man", "1"));
189 | users.add(new User("lisi" + i, "woman", "2"));
190 | users.add(new User("wangwu" + i, "unkonwn", "2"));
191 | }
192 | return users;
193 | }
194 |
195 | /**
196 | * 手动聚合方式
197 | * @return
198 | */
199 | public List getUser(){
200 | ArrayList users = new ArrayList();
201 | for (int i = 1000; i > 0; i--) {
202 | users.add(new User("zhangsan" + i, "man", "1"));
203 | users.add(new User("lisi" + i, "woman", "2"));
204 | users.add(new User("wangwu" + i, "unkonwn", "2"));
205 | }
206 | try {
207 | // list 聚合
208 | mergeCore.mergeResult(User.class,users);
209 | // 单个对象聚合
210 | // mergeCore.mergeOne(User.class,users.get(0));
211 | } catch (Exception e) {
212 | log.error("数据聚合失败",e);
213 | }finally {
214 | return users;
215 | }
216 | }
217 | }
218 | ```
219 |
--------------------------------------------------------------------------------
/ace-merge-core/ace-merge-core.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/ace-merge-core/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | ace-merge-parent
7 | com.github.wxiaoqi
8 | 2.0-SNAPSHOT
9 |
10 | 4.0.0
11 | jar
12 | ace-merge-core
13 |
14 |
15 |
16 | com.google.guava
17 | guava
18 | 20.0
19 |
20 |
21 | org.projectlombok
22 | lombok
23 | 1.16.14
24 |
25 |
26 | org.springframework.boot
27 | spring-boot-starter-aop
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/ace-merge-core/src/main/java/com/github/wxiaoqi/merge/EnableAceMerge.java:
--------------------------------------------------------------------------------
1 | package com.github.wxiaoqi.merge;
2 |
3 | import com.github.wxiaoqi.merge.configuration.MergeAutoConfiguration;
4 | import org.springframework.context.annotation.Import;
5 |
6 | import java.lang.annotation.*;
7 |
8 | /**
9 | * @author ace
10 | * @create 2018/2/3.
11 | */
12 | @Target({ElementType.TYPE})
13 | @Retention(RetentionPolicy.RUNTIME)
14 | @Documented
15 | @Inherited
16 | @Import({MergeAutoConfiguration.class})
17 | public @interface EnableAceMerge {
18 | }
19 |
--------------------------------------------------------------------------------
/ace-merge-core/src/main/java/com/github/wxiaoqi/merge/annonation/MergeField.java:
--------------------------------------------------------------------------------
1 | package com.github.wxiaoqi.merge.annonation;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | /**
9 | * @author ace
10 | * @create 2018/2/1.
11 | */
12 | @Retention(RetentionPolicy.RUNTIME)
13 | @Target(value={ElementType.METHOD,ElementType.TYPE,ElementType.FIELD})
14 | public @interface MergeField {
15 | /**
16 | * 查询值
17 | * @return
18 | */
19 | String key() default "";
20 |
21 | /**
22 | * 目标类
23 | * @return
24 | */
25 | Class extends Object> feign() default Object.class;
26 |
27 | /**
28 | * 调用方法
29 | * @return
30 | */
31 | String method() default "";
32 |
33 | /**
34 | * 是否以属性值合并作为查询值
35 | * @return
36 | */
37 | boolean isValueNeedMerge() default false;
38 | }
39 |
--------------------------------------------------------------------------------
/ace-merge-core/src/main/java/com/github/wxiaoqi/merge/annonation/MergeResult.java:
--------------------------------------------------------------------------------
1 | package com.github.wxiaoqi.merge.annonation;
2 |
3 | import com.github.wxiaoqi.merge.facade.DefaultMergeResultParser;
4 | import com.github.wxiaoqi.merge.facade.IMergeResultParser;
5 |
6 | import java.lang.annotation.ElementType;
7 | import java.lang.annotation.Retention;
8 | import java.lang.annotation.RetentionPolicy;
9 | import java.lang.annotation.Target;
10 |
11 | /**
12 | * @author ace
13 | * @create 2018/2/1.
14 | */
15 | @Retention(RetentionPolicy.RUNTIME)
16 | @Target(value = {ElementType.METHOD, ElementType.TYPE})
17 | public @interface MergeResult {
18 | Class extends IMergeResultParser> resultParser() default DefaultMergeResultParser.class;
19 | }
20 |
--------------------------------------------------------------------------------
/ace-merge-core/src/main/java/com/github/wxiaoqi/merge/aspect/MergeAspect.java:
--------------------------------------------------------------------------------
1 | package com.github.wxiaoqi.merge.aspect;
2 |
3 | import com.github.wxiaoqi.merge.annonation.MergeResult;
4 | import com.github.wxiaoqi.merge.core.MergeCore;
5 | import org.aspectj.lang.ProceedingJoinPoint;
6 | import org.aspectj.lang.annotation.Around;
7 | import org.aspectj.lang.annotation.Aspect;
8 | import org.aspectj.lang.annotation.Pointcut;
9 | import org.springframework.beans.factory.annotation.Autowired;
10 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
11 | import org.springframework.stereotype.Component;
12 |
13 | /**
14 | * @author ace
15 | * @create 2018/2/2.
16 | */
17 | @Aspect
18 | @Component
19 | @ConditionalOnProperty(name = "merge.aop.enabled", matchIfMissing = true)
20 | public class MergeAspect {
21 | @Autowired
22 | private MergeCore mergeCore;
23 |
24 | @Pointcut("@annotation(com.github.wxiaoqi.merge.annonation.MergeResult)")
25 | public void methodPointcut() {
26 | }
27 |
28 |
29 | @Around("methodPointcut()&&@annotation(anno)")
30 | public Object interceptor(ProceedingJoinPoint pjp,MergeResult anno) throws Throwable {
31 | try {
32 | return mergeCore.mergeData(pjp,anno);
33 | }catch(Exception e){
34 | return pjp.proceed();
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/ace-merge-core/src/main/java/com/github/wxiaoqi/merge/configuration/MergeAutoConfiguration.java:
--------------------------------------------------------------------------------
1 | package com.github.wxiaoqi.merge.configuration;
2 |
3 | import com.github.wxiaoqi.merge.core.BeanFactoryUtils;
4 | import com.github.wxiaoqi.merge.core.MergeCore;
5 | import com.github.wxiaoqi.merge.facade.DefaultMergeResultParser;
6 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
7 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
8 | import org.springframework.context.annotation.Bean;
9 | import org.springframework.context.annotation.ComponentScan;
10 | import org.springframework.context.annotation.Configuration;
11 |
12 | /**
13 | * @author ace
14 | * @create 2018/2/3.
15 | */
16 | @Configuration
17 | @ComponentScan("com.github.wxiaoqi.merge.aspect")
18 | @ConditionalOnProperty(name = "merge.enabled", matchIfMissing = true)
19 | public class MergeAutoConfiguration {
20 | @Bean
21 | @ConditionalOnMissingBean
22 | public MergeProperties mergeProperties() {
23 | return new MergeProperties();
24 | }
25 |
26 | @Bean
27 | @ConditionalOnMissingBean
28 | public BeanFactoryUtils beanFactoryUtils() {
29 | return new BeanFactoryUtils();
30 | }
31 |
32 | @Bean
33 | @ConditionalOnMissingBean
34 | public MergeCore mergeCore() {
35 | return new MergeCore(mergeProperties());
36 | }
37 |
38 | @Bean
39 | public DefaultMergeResultParser defaultMergeResultParser() {
40 | return new DefaultMergeResultParser();
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/ace-merge-core/src/main/java/com/github/wxiaoqi/merge/configuration/MergeProperties.java:
--------------------------------------------------------------------------------
1 | package com.github.wxiaoqi.merge.configuration;
2 |
3 | import lombok.Data;
4 | import org.springframework.boot.context.properties.ConfigurationProperties;
5 |
6 | /**
7 | * @author ace
8 | * @create 2018/2/3.
9 | */
10 | @Data
11 | @ConfigurationProperties("merge")
12 | public class MergeProperties {
13 | /**
14 | * guava缓存的键值数
15 | */
16 | private Integer guavaCacheNumMaxSize;
17 | /**
18 | * guava更新混存的下一次时间,分钟
19 | */
20 | private Integer guavaCacheRefreshWriteTime;
21 | /**
22 | * guava
23 | */
24 | private Integer guavaCacheRefreshThreadPoolSize;
25 |
26 | public Integer getGuavaCacheNumMaxSize() {
27 | return guavaCacheNumMaxSize;
28 | }
29 |
30 | public void setGuavaCacheNumMaxSize(Integer guavaCacheNumMaxSize) {
31 | this.guavaCacheNumMaxSize = guavaCacheNumMaxSize;
32 | }
33 |
34 | public Integer getGuavaCacheRefreshWriteTime() {
35 | return guavaCacheRefreshWriteTime;
36 | }
37 |
38 | public void setGuavaCacheRefreshWriteTime(Integer guavaCacheRefreshWriteTime) {
39 | this.guavaCacheRefreshWriteTime = guavaCacheRefreshWriteTime;
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/ace-merge-core/src/main/java/com/github/wxiaoqi/merge/core/BeanFactoryUtils.java:
--------------------------------------------------------------------------------
1 | package com.github.wxiaoqi.merge.core;
2 |
3 | import org.springframework.beans.BeansException;
4 | import org.springframework.context.ApplicationContext;
5 | import org.springframework.context.ApplicationContextAware;
6 |
7 | /**
8 | * 获取Bean实体工具类
9 | *
10 | * @author 老A
11 | * @create 2017-12-26 20:16
12 | **/
13 | public class BeanFactoryUtils implements ApplicationContextAware {
14 |
15 | private static ApplicationContext applicationContext;
16 |
17 | @Override
18 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
19 | if(null == BeanFactoryUtils.applicationContext) {
20 | BeanFactoryUtils.applicationContext = applicationContext;
21 | }
22 | }
23 |
24 | public static ApplicationContext getApplicationContext() {
25 | return applicationContext;
26 | }
27 |
28 | //通过name获取Bean
29 | public static Object getBean(String name) {
30 | return getApplicationContext().getBean(name);
31 | }
32 |
33 | //通过class获取Bean
34 | public static T getBean(Class clazz) {
35 | return getApplicationContext().getBean(clazz);
36 | }
37 |
38 | //通过name,以及Clazz返回指定的Bean
39 | public static T getBean(String name, Class clazz) {
40 | return getApplicationContext().getBean(name, clazz);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/ace-merge-core/src/main/java/com/github/wxiaoqi/merge/core/MergeCore.java:
--------------------------------------------------------------------------------
1 | package com.github.wxiaoqi.merge.core;
2 |
3 | import com.github.wxiaoqi.merge.annonation.MergeField;
4 | import com.github.wxiaoqi.merge.annonation.MergeResult;
5 | import com.github.wxiaoqi.merge.configuration.MergeProperties;
6 | import com.github.wxiaoqi.merge.facade.DefaultMergeResultParser;
7 | import com.github.wxiaoqi.merge.facade.IMergeResultParser;
8 | import com.google.common.cache.CacheBuilder;
9 | import com.google.common.cache.CacheLoader;
10 | import com.google.common.cache.LoadingCache;
11 | import com.google.common.util.concurrent.ListenableFuture;
12 | import com.google.common.util.concurrent.ListeningExecutorService;
13 | import com.google.common.util.concurrent.MoreExecutors;
14 | import lombok.extern.slf4j.Slf4j;
15 | import org.aspectj.lang.ProceedingJoinPoint;
16 | import org.aspectj.lang.reflect.MethodSignature;
17 |
18 | import java.lang.reflect.*;
19 | import java.util.*;
20 | import java.util.concurrent.ExecutionException;
21 | import java.util.concurrent.Executors;
22 | import java.util.concurrent.TimeUnit;
23 |
24 | /**
25 | * @author ace
26 | * @create 2018/2/2.
27 | */
28 | @Slf4j
29 | public class MergeCore {
30 |
31 | private Map mergeFieldMap;
32 | private ListeningExecutorService backgroundRefreshPools;
33 | private LoadingCache> caches;
34 |
35 | public MergeCore(MergeProperties mergeProperties) {
36 | this.backgroundRefreshPools =
37 | MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(mergeProperties.getGuavaCacheRefreshThreadPoolSize()));
38 | this.mergeFieldMap = new HashMap();
39 | this.caches = CacheBuilder.newBuilder()
40 | .maximumSize(mergeProperties.getGuavaCacheNumMaxSize())
41 | .refreshAfterWrite(mergeProperties.getGuavaCacheRefreshWriteTime(), TimeUnit.MINUTES)
42 | .build(new CacheLoader>() {
43 | @Override
44 | public Map load(String key) throws Exception {
45 | log.debug("首次读取缓存: " + key);
46 | MergeField mergeField = mergeFieldMap.get(key);
47 | Object bean = BeanFactoryUtils.getBean(mergeField.feign());
48 | Method method = mergeField.feign().getMethod(mergeField.method(), String.class);
49 | Map invoke = (Map) method.invoke(bean, mergeField.key());
50 | return invoke;
51 | }
52 |
53 | @Override
54 | public ListenableFuture