├── .gitignore ├── data-aggregate-core ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── github │ │ └── middleware │ │ └── aggregate │ │ ├── annonation │ │ ├── AggregeBatchProxy.java │ │ ├── AggregeEnable.java │ │ ├── AggregeField.java │ │ ├── AggregeProxy.java │ │ └── AggregeProxyArg.java │ │ ├── config │ │ └── MergeProperties.java │ │ ├── constant │ │ └── ArgGetMode.java │ │ ├── context │ │ ├── AggregeContext.java │ │ ├── AggregeEvent.java │ │ ├── AggregeListener.java │ │ ├── container │ │ │ ├── StartedAggregeEvent.java │ │ │ ├── StartedAggregeListener.java │ │ │ ├── StopAggregeEvent.java │ │ │ └── StopAggregeListener.java │ │ └── session │ │ │ ├── BreakDataBindAggregeEvent.java │ │ │ ├── BreakDataBindAggregeEventListener.java │ │ │ ├── ContractInvokeAfterAggregeEvent.java │ │ │ ├── ContractInvokeAfterAggregeListener.java │ │ │ ├── ContractInvokeBeforeAggregeEvent.java │ │ │ ├── ContractInvokeBeforeAggregeListener.java │ │ │ ├── DataBindBeforeAggregeEvent.java │ │ │ ├── DataBindBeforeAggregeListener.java │ │ │ ├── InterceptorAfterAggregeEvent.java │ │ │ ├── InterceptorAfterAggregeListener.java │ │ │ ├── InterceptorBeforeAggregeEvent.java │ │ │ └── InterceptorBeforeAggregeListener.java │ │ ├── contract │ │ ├── ResponseResolver.java │ │ ├── ServiceConsumerEndpoint.java │ │ └── support │ │ │ ├── NothingResponseResolver.java │ │ │ └── Proxys.java │ │ ├── core │ │ ├── AggregeEngine.java │ │ ├── AggregeEngineActivetor.java │ │ ├── AggregeException.java │ │ ├── ExtensionLoader.java │ │ ├── LasyLoadData.java │ │ ├── RequestPayLoad.java │ │ └── support │ │ │ ├── AbstractAggregeEngineActivetor.java │ │ │ ├── AggregeEngineActivetorFactory.java │ │ │ ├── AggregeEngineActivetors.java │ │ │ ├── DefaultAggregeEngine.java │ │ │ ├── DefaultAggregeEngineActivetor.java │ │ │ ├── DefaultExtensionLoader.java │ │ │ ├── ExtensionLoaders.java │ │ │ └── GenClzProxyAggregeEngineActivetor.java │ │ ├── flow │ │ ├── ItemBinder.java │ │ ├── ItemCommand.java │ │ ├── ItemInterceptor.java │ │ ├── ItemOrder.java │ │ ├── builder │ │ │ ├── ItemBinderChain.java │ │ │ └── Steps.java │ │ ├── context │ │ │ └── Invocation.java │ │ └── support │ │ │ ├── AbstractItemCommand.java │ │ │ ├── ItemProxyArgBuildCommand.java │ │ │ ├── ItemProxyFetchDataCommand.java │ │ │ ├── ItemProxyResponseResolverCommand.java │ │ │ ├── ItemRequestValidateCommand.java │ │ │ ├── ItemResponseCommand.java │ │ │ ├── ItemsProxyArgBuildCommand.java │ │ │ └── ItemsProxyFetchDataCommand.java │ │ ├── source │ │ ├── MetaHolderFactory.java │ │ ├── bean │ │ │ ├── FieldVisitor.java │ │ │ ├── MetaHolder.java │ │ │ └── MethodVisitor.java │ │ └── support │ │ │ ├── BeanPropertyLoaders.java │ │ │ └── ReflectMetaHolderFactory.java │ │ └── util │ │ ├── ArrayUtils.java │ │ ├── AsyncUtils.java │ │ ├── Reflections.java │ │ ├── RegexMatcher.java │ │ └── UnsafeUtils.java │ └── resources │ ├── META-INF │ └── services │ │ ├── com.github.middleware.aggregate.context.AggregeListener │ │ ├── com.github.middleware.aggregate.core.AggregeEngine │ │ ├── com.github.middleware.aggregate.flow.ItemBinder │ │ └── com.github.middleware.aggregate.source.MetaHolderFactory │ └── data-aggrege-demo.yml ├── data-aggregate-spring-boot-starter ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── github │ └── middleware │ └── aggregate │ └── spring │ └── boot │ └── autoconfigure │ ├── AggregateAutoConfiguration.java │ ├── AggregateProperties.java │ └── EnableDataAggregate.java ├── data-aggregate-spring ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── github │ │ │ └── middleware │ │ │ └── aggregate │ │ │ └── spring │ │ │ ├── init │ │ │ ├── DataAggregeAspect.java │ │ │ └── SpringContextHolder.java │ │ │ ├── remote │ │ │ └── SpringContractBeanEndpoint.java │ │ │ └── util │ │ │ └── AopUtils.java │ └── resources │ │ └── META-INF │ │ └── services │ │ └── com.github.middleware.aggregate.contract.ServiceConsumerEndpoint │ └── test │ ├── java │ └── com │ │ └── github │ │ └── middleware │ │ └── aggregate │ │ ├── QuickStart_test.java │ │ └── example │ │ ├── AddressRepository.java │ │ ├── AddressResponseResolver.java │ │ ├── GlobalDictionaryCode.java │ │ ├── OrderService.java │ │ ├── ProductService.java │ │ └── domain │ │ ├── Address.java │ │ ├── Order.java │ │ ├── Order2.java │ │ └── Product.java │ └── resources │ ├── data-aggrege.yml │ ├── logback.xml │ ├── mock │ └── config.json │ └── spring.xml ├── pom.xml └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear in the root of a volume 35 | .DocumentRevisions-V100 36 | .fseventsd 37 | .Spotlight-V100 38 | .TemporaryItems 39 | .Trashes 40 | .VolumeIcon.icns 41 | 42 | # Directories potentially created on remote AFP share 43 | .AppleDB 44 | .AppleDesktop 45 | Network Trash Folder 46 | Temporary Items 47 | .apdisk 48 | 49 | 50 | 51 | #my 52 | /target/ 53 | /.classpath 54 | /.settings 55 | /.project 56 | /.idea 57 | *.iml 58 | /.springBeans -------------------------------------------------------------------------------- /data-aggregate-core/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | data-aggregate-parent 7 | com.github.middleware 8 | 1.0 9 | 10 | 4.0.0 11 | ${aggregate.verion} 12 | data-aggregate-core 13 | 14 | data-aggregate-core 15 | http://www.example.com 16 | 17 | 18 | com.google.guava 19 | guava 20 | 21 | 22 | org.yaml 23 | snakeyaml 24 | 25 | 26 | org.springframework 27 | spring-core 28 | 29 | 30 | org.slf4j 31 | slf4j-api 32 | 33 | 34 | io.reactivex.rxjava2 35 | rxjava 36 | 37 | 38 | cglib 39 | cglib 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/annonation/AggregeBatchProxy.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.annonation; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * @Author: alex 7 | * @Description: 8 | * @Date: created in 2019/2/14. 9 | */ 10 | @Target(ElementType.TYPE) 11 | @Retention(RetentionPolicy.RUNTIME) 12 | @Documented 13 | public @interface AggregeBatchProxy { 14 | /** 15 | * @return 16 | */ 17 | AggregeProxy list() default @AggregeProxy(enable = false); 18 | 19 | /** 20 | * 21 | * @return 22 | */ 23 | AggregeProxy item() default @AggregeProxy(enable = false); 24 | } 25 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/annonation/AggregeEnable.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.annonation; 2 | 3 | 4 | import java.lang.annotation.*; 5 | 6 | /** 7 | * @Author: alex 8 | * @Description: 9 | * @Date: created in 2019/1/7. 10 | */ 11 | @Target(value = {ElementType.METHOD}) 12 | @Retention(RetentionPolicy.RUNTIME) 13 | @Documented 14 | public @interface AggregeEnable { 15 | /** 16 | * 开启并行填充 17 | * 18 | * @return 19 | */ 20 | boolean parallel() default false; 21 | } 22 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/annonation/AggregeField.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.annonation; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * @Author: alex 7 | * @Description: 8 | * @Date: created in 2019/1/7. 9 | */ 10 | @Target(value = {ElementType.FIELD}) 11 | @Retention(RetentionPolicy.RUNTIME) 12 | @Documented 13 | public @interface AggregeField { 14 | /** 15 | * 远程或本地服务,服务于单VO 16 | * 17 | * @return 18 | */ 19 | AggregeProxy proxy() default @AggregeProxy(enable = false); 20 | 21 | /** 22 | * 开启性能优化(批量问题),执行顺序是batchProxy->proxy 23 | * 24 | * @return 25 | */ 26 | AggregeBatchProxy batchProxy() default @AggregeBatchProxy; 27 | 28 | /** 29 | * 是否忽略错误 30 | * 31 | * @return 32 | */ 33 | boolean ignoreError() default false; 34 | } 35 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/annonation/AggregeProxy.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.annonation; 2 | 3 | import com.github.middleware.aggregate.contract.ResponseResolver; 4 | import com.github.middleware.aggregate.contract.support.NothingResponseResolver; 5 | 6 | import java.lang.annotation.*; 7 | 8 | /** 9 | * @Author: alex 10 | * @Description: 11 | * @Date: created in 2019/1/7. 12 | */ 13 | @Target(ElementType.TYPE) 14 | @Retention(RetentionPolicy.RUNTIME) 15 | @Documented 16 | public @interface AggregeProxy { 17 | /** 18 | * 是否启用 19 | * 20 | * @return 21 | */ 22 | boolean enable() default true; 23 | 24 | /** 25 | * 目标服务名 26 | * 名称以#开头,代表从当前IOC中获取,否则类全名,如下: 27 | * #omsProductServcie 28 | * com.github.oms.contract.ProductServcie 29 | * 30 | * @return 31 | */ 32 | String name() default ""; 33 | 34 | /** 35 | * 调用方法 36 | * 37 | * @return 38 | */ 39 | String method() default ""; 40 | 41 | /** 42 | * 查询值 43 | * 44 | * @return 45 | */ 46 | AggregeProxyArg[] params() default {}; 47 | 48 | /** 49 | * 是否缓存 50 | * @deprecated (不需要) 51 | * @return 52 | */ 53 | @Deprecated 54 | boolean cache() default false; 55 | 56 | /** 57 | * @return 58 | */ 59 | Class resolver() default NothingResponseResolver.class; 60 | } 61 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/annonation/AggregeProxyArg.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.annonation; 2 | 3 | import com.github.middleware.aggregate.constant.ArgGetMode; 4 | 5 | import java.lang.annotation.*; 6 | 7 | /** 8 | * @Author: alex 9 | * @Description: 10 | * @Date: created in 2019/1/7. 11 | */ 12 | @Target(ElementType.TYPE) 13 | @Retention(RetentionPolicy.RUNTIME) 14 | @Documented 15 | public @interface AggregeProxyArg { 16 | /** 17 | * 参数获取模式 18 | * 19 | * @return 20 | */ 21 | ArgGetMode argGetMode() default ArgGetMode.ITEM; 22 | 23 | /** 24 | * @deprecated (contract的参数名) 25 | * 26 | * @return 27 | */ 28 | @Deprecated 29 | String paramName() default ""; 30 | 31 | /** 32 | * @return 33 | */ 34 | String paramValue() default ""; 35 | 36 | /** 37 | * 为vo的属性名或session中的key 38 | * 39 | * @return 40 | */ 41 | String key() default ""; 42 | } 43 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/config/MergeProperties.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.config; 2 | 3 | /** 4 | * @Author: alex 5 | * @Description: 全局配置 6 | * @Date: created in 2019/1/18. 7 | */ 8 | public class MergeProperties { 9 | private Integer clzMetasCacheSize; 10 | private Integer responseResolverCacheSize; 11 | private Integer proxyMethodCacheSize; 12 | private Integer corePoolSize; 13 | /** 14 | * 秒 15 | */ 16 | private Integer keepAliveTime = 300; 17 | private Integer workQueueSize = 500; 18 | 19 | public MergeProperties() { 20 | corePoolSize = Runtime.getRuntime().availableProcessors(); 21 | } 22 | 23 | /** 24 | * 异步获取结果时最大阻塞时间(默认:20秒) 25 | */ 26 | private Integer maxBlockTimeout = 20000; 27 | 28 | private String[] scanPackages; 29 | 30 | public Integer getClzMetasCacheSize() { 31 | return clzMetasCacheSize; 32 | } 33 | 34 | public void setClzMetasCacheSize(Integer clzMetasCacheSize) { 35 | this.clzMetasCacheSize = clzMetasCacheSize; 36 | } 37 | 38 | public Integer getResponseResolverCacheSize() { 39 | return responseResolverCacheSize; 40 | } 41 | 42 | public void setResponseResolverCacheSize(Integer responseResolverCacheSize) { 43 | this.responseResolverCacheSize = responseResolverCacheSize; 44 | } 45 | 46 | public Integer getProxyMethodCacheSize() { 47 | return proxyMethodCacheSize; 48 | } 49 | 50 | public void setProxyMethodCacheSize(Integer proxyMethodCacheSize) { 51 | this.proxyMethodCacheSize = proxyMethodCacheSize; 52 | } 53 | public String[] getScanPackages() { 54 | return scanPackages; 55 | } 56 | 57 | public void setScanPackages(String[] scanPackages) { 58 | this.scanPackages = scanPackages; 59 | } 60 | 61 | public Integer getMaxBlockTimeout() { 62 | return maxBlockTimeout; 63 | } 64 | 65 | public void setMaxBlockTimeout(Integer maxBlockTimeout) { 66 | this.maxBlockTimeout = maxBlockTimeout; 67 | } 68 | 69 | public Integer getCorePoolSize() { 70 | return corePoolSize; 71 | } 72 | 73 | public void setCorePoolSize(Integer corePoolSize) { 74 | this.corePoolSize = corePoolSize; 75 | } 76 | 77 | public Integer getKeepAliveTime() { 78 | return keepAliveTime; 79 | } 80 | 81 | public void setKeepAliveTime(Integer keepAliveTime) { 82 | this.keepAliveTime = keepAliveTime; 83 | } 84 | 85 | public Integer getWorkQueueSize() { 86 | return workQueueSize; 87 | } 88 | 89 | public void setWorkQueueSize(Integer workQueueSize) { 90 | this.workQueueSize = workQueueSize; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/constant/ArgGetMode.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.constant; 2 | 3 | /** 4 | * @Author: alex 5 | * @Description: 6 | * @Date: created in 2019/1/10. 7 | */ 8 | public enum ArgGetMode { 9 | 10 | /** 11 | * 从当前VO中获取 12 | */ 13 | ITEM, 14 | /** 15 | * 从session中获取 16 | */ 17 | SESSION, 18 | /** 19 | * 从batch中获取 20 | */ 21 | BATCH 22 | } -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/context/AggregeContext.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.context; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | /** 7 | * @Author: alex 8 | * @Description: 它主要服务于客户接入端与本组件的交互,致力于解决参数传递问题: 9 | * 1.支持从item(DataVo)中提取属性 10 | * 2.支持复杂参数(item中可能不存在的)从session(ThreadLocal)中获取 11 | * @Date: created in 2019/1/14. 12 | */ 13 | public class AggregeContext { 14 | private static final ThreadLocal LOCAL =ThreadLocal.withInitial(AggregeContext::new); 15 | /** 16 | * prxoy(contract)所需的参数 17 | */ 18 | private final Map attachments = new HashMap(); 19 | /** 20 | * 触发源 21 | */ 22 | private String fireSource; 23 | 24 | public static AggregeContext getContext() { 25 | return LOCAL.get(); 26 | } 27 | 28 | public static void removeContext() { 29 | LOCAL.remove(); 30 | } 31 | 32 | public Object getAttachment(String key) { 33 | return this.attachments.get(key); 34 | } 35 | 36 | public AggregeContext setAttachment(String key, Object value) { 37 | if (value == null) { 38 | this.attachments.remove(key); 39 | } else { 40 | this.attachments.put(key, value); 41 | } 42 | return this; 43 | } 44 | 45 | public AggregeContext setAttachments(Map attachment) { 46 | this.attachments.clear(); 47 | if (attachment != null && attachment.size() > 0) { 48 | this.attachments.putAll(attachment); 49 | } 50 | return this; 51 | } 52 | 53 | public String getFireSource() { 54 | return fireSource; 55 | } 56 | 57 | public void setFireSource(String fireSource) { 58 | this.fireSource = fireSource; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/context/AggregeEvent.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.context; 2 | 3 | import java.util.Date; 4 | import java.util.EventObject; 5 | /** 6 | * @Author: alex 7 | * @Description: 8 | * @Date: created in 2019/1/17. 9 | */ 10 | public abstract class AggregeEvent extends EventObject { 11 | private final Date time; 12 | 13 | public AggregeEvent(Object source) { 14 | super(source); 15 | this.time = new Date(); 16 | } 17 | 18 | public Date getTime() { 19 | return this.time; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/context/AggregeListener.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.context; 2 | /** 3 | * @Author: alex 4 | * @Description: 5 | * @Date: created in 2019/1/17. 6 | */ 7 | public interface AggregeListener { 8 | void lister(T event); 9 | } 10 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/context/container/StartedAggregeEvent.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.context.container; 2 | 3 | import com.github.middleware.aggregate.context.AggregeEvent; 4 | 5 | /** 6 | * @Author: alex 7 | * @Description: AggregeEngine.start,容器级事件 8 | * @Date: created in 2019/1/17. 9 | */ 10 | public class StartedAggregeEvent extends AggregeEvent { 11 | public StartedAggregeEvent(Object source) { 12 | super(source); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/context/container/StartedAggregeListener.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.context.container; 2 | 3 | import com.github.middleware.aggregate.context.AggregeListener; 4 | import com.google.common.eventbus.Subscribe; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | /** 9 | * @Author: alex 10 | * @Description: 11 | * @Date: created in 2019/1/17. 12 | */ 13 | public class StartedAggregeListener implements AggregeListener { 14 | private static final Logger LOGGER = LoggerFactory.getLogger(StartedAggregeListener.class); 15 | 16 | @Subscribe 17 | @Override 18 | public void lister(StartedAggregeEvent event) { 19 | if (LOGGER.isDebugEnabled()) LOGGER.debug("Started"); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/context/container/StopAggregeEvent.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.context.container; 2 | 3 | import com.github.middleware.aggregate.context.AggregeEvent; 4 | 5 | /** 6 | * @Author: alex 7 | * @Description: AggregeEngine.stop 容器级事件 8 | * @Date: created in 2019/1/17. 9 | */ 10 | public class StopAggregeEvent extends AggregeEvent { 11 | public StopAggregeEvent(Object source) { 12 | super(source); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/context/container/StopAggregeListener.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.context.container; 2 | 3 | import com.github.middleware.aggregate.context.AggregeListener; 4 | import com.google.common.eventbus.Subscribe; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | /** 9 | * @Author: alex 10 | * @Description: 11 | * @Date: created in 2019/1/17. 12 | */ 13 | public class StopAggregeListener implements AggregeListener { 14 | private static final Logger LOGGER = LoggerFactory.getLogger(StopAggregeListener.class); 15 | 16 | @Subscribe 17 | @Override 18 | public void lister(StopAggregeEvent event) { 19 | if (LOGGER.isDebugEnabled()) LOGGER.debug("Stop"); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/context/session/BreakDataBindAggregeEvent.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.context.session; 2 | 3 | import com.github.middleware.aggregate.context.AggregeEvent; 4 | import com.github.middleware.aggregate.flow.context.Invocation; 5 | 6 | /** 7 | * @Author: alex 8 | * @Description: 9 | * @Date: created in 2019/2/14. 10 | */ 11 | public class BreakDataBindAggregeEvent extends AggregeEvent { 12 | private transient Invocation invocation; 13 | public BreakDataBindAggregeEvent(Object source, Invocation invocation) { 14 | super(source); 15 | this.invocation = invocation; 16 | } 17 | 18 | public Invocation getInvocation() { 19 | return invocation; 20 | } 21 | 22 | public void setInvocation(Invocation invocation) { 23 | this.invocation = invocation; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/context/session/BreakDataBindAggregeEventListener.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.context.session; 2 | 3 | import com.github.middleware.aggregate.context.AggregeListener; 4 | import com.github.middleware.aggregate.flow.ItemCommand; 5 | import com.google.common.collect.Lists; 6 | import com.google.common.eventbus.Subscribe; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | import java.util.List; 11 | 12 | /** 13 | * @Author: alex 14 | * @Description: 15 | * @Date: created in 2019/2/14. 16 | */ 17 | public class BreakDataBindAggregeEventListener implements AggregeListener { 18 | private static final Logger LOGGER = LoggerFactory.getLogger(BreakDataBindAggregeEventListener.class); 19 | private List breakFilterRules = Lists.newArrayList(ItemCommand.ALL); 20 | 21 | @Subscribe 22 | @Override 23 | public void lister(BreakDataBindAggregeEvent event) { 24 | if (LOGGER.isDebugEnabled()) LOGGER.debug("field={}", event.getSource()); 25 | event.getInvocation().getMetaContext().setFilterRules(breakFilterRules); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/context/session/ContractInvokeAfterAggregeEvent.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.context.session; 2 | 3 | import com.github.middleware.aggregate.context.AggregeEvent; 4 | import com.github.middleware.aggregate.flow.context.Invocation; 5 | 6 | /** 7 | * @Author: alex 8 | * @Description: ItemProxyFetchDataCommand.invoke之后,后一个链之前 9 | * @Date: created in 2019/1/18. 10 | */ 11 | public class ContractInvokeAfterAggregeEvent extends AggregeEvent { 12 | private transient Object response; 13 | private transient Invocation invocation; 14 | 15 | public ContractInvokeAfterAggregeEvent(Object fireSource, Object response, Invocation invocation) { 16 | super(fireSource); 17 | this.response = response; 18 | this.invocation = invocation; 19 | } 20 | 21 | public Object getResponse() { 22 | return response; 23 | } 24 | 25 | public void setResponse(Object response) { 26 | this.response = response; 27 | } 28 | 29 | public Invocation getInvocation() { 30 | return invocation; 31 | } 32 | 33 | public void setInvocation(Invocation invocation) { 34 | this.invocation = invocation; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/context/session/ContractInvokeAfterAggregeListener.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.context.session; 2 | 3 | import com.github.middleware.aggregate.context.AggregeListener; 4 | import com.google.common.eventbus.Subscribe; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | /** 9 | * @Author: alex 10 | * @Description: 11 | * @Date: created in 2019/1/18. 12 | */ 13 | public class ContractInvokeAfterAggregeListener implements AggregeListener { 14 | private static final Logger LOGGER = LoggerFactory.getLogger(ContractInvokeAfterAggregeListener.class); 15 | 16 | @Subscribe 17 | @Override 18 | public void lister(ContractInvokeAfterAggregeEvent event) { 19 | if (LOGGER.isDebugEnabled()) LOGGER.debug("field={},response={}",event.getSource(),event.getResponse()); 20 | if (event.getResponse() == null) { 21 | //转发事件 22 | event.getInvocation().getEventBus().post(new BreakDataBindAggregeEvent(event.getSource(), event.getInvocation())); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/context/session/ContractInvokeBeforeAggregeEvent.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.context.session; 2 | 3 | import com.github.middleware.aggregate.context.AggregeEvent; 4 | import com.github.middleware.aggregate.flow.context.Invocation; 5 | 6 | /** 7 | * @Author: alex 8 | * @Description: ItemProxyFetchDataCommand.invoke之前,前一个链(ItemProxyArgBuildCommand)之后 9 | * @Date: created in 2019/1/18. 10 | */ 11 | public class ContractInvokeBeforeAggregeEvent extends AggregeEvent { 12 | private transient Invocation invocation; 13 | private transient Object arg; 14 | 15 | public ContractInvokeBeforeAggregeEvent(Object source, Object arg, Invocation invocation) { 16 | super(source); 17 | this.arg = arg; 18 | this.invocation = invocation; 19 | } 20 | 21 | public Object getArg() { 22 | return arg; 23 | } 24 | 25 | public void setArg(Object arg) { 26 | this.arg = arg; 27 | } 28 | 29 | public Invocation getInvocation() { 30 | return invocation; 31 | } 32 | 33 | public void setInvocation(Invocation invocation) { 34 | this.invocation = invocation; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/context/session/ContractInvokeBeforeAggregeListener.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.context.session; 2 | 3 | import com.github.middleware.aggregate.context.AggregeListener; 4 | import com.google.common.eventbus.Subscribe; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import java.util.List; 9 | import java.util.Objects; 10 | 11 | /** 12 | * @Author: alex 13 | * @Description: 14 | * @Date: created in 2019/1/18. 15 | */ 16 | public class ContractInvokeBeforeAggregeListener implements AggregeListener { 17 | private static final Logger LOGGER = LoggerFactory.getLogger(ContractInvokeBeforeAggregeListener.class); 18 | 19 | @Subscribe 20 | @Override 21 | public void lister(ContractInvokeBeforeAggregeEvent event) { 22 | if (LOGGER.isDebugEnabled()) LOGGER.debug("field={},arg={}",event.getSource(), event.getArg()); 23 | if (isNullParams(event)) { 24 | //转发事件 25 | event.getInvocation().getEventBus().post(new BreakDataBindAggregeEvent(event.getSource(), event.getInvocation())); 26 | } 27 | 28 | } 29 | 30 | private boolean isNullParams(ContractInvokeBeforeAggregeEvent event) { 31 | if (event.getArg() == null) { 32 | return true; 33 | } 34 | if (event.getArg() instanceof List) { 35 | List eventArg = (List) event.getArg(); 36 | long nullCount = eventArg.stream().filter(Objects::isNull).count(); 37 | if (eventArg.size() == nullCount) { 38 | return true; 39 | } 40 | } 41 | return false; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/context/session/DataBindBeforeAggregeEvent.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.context.session; 2 | 3 | import com.github.middleware.aggregate.context.AggregeEvent; 4 | 5 | /** 6 | * @Author: alex 7 | * @Description: ItemBinder.invoke 执行之前,其实也是MethodProceedCallback.proceed 之后 8 | * @Date: created in 2019/1/17. 9 | */ 10 | public class DataBindBeforeAggregeEvent extends AggregeEvent { 11 | private transient Object item; 12 | 13 | public DataBindBeforeAggregeEvent(Object source, Object item) { 14 | super(source); 15 | this.item = item; 16 | } 17 | 18 | public Object getItem() { 19 | return item; 20 | } 21 | 22 | public void setItem(Object item) { 23 | this.item = item; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/context/session/DataBindBeforeAggregeListener.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.context.session; 2 | 3 | import com.github.middleware.aggregate.context.AggregeListener; 4 | import com.google.common.eventbus.Subscribe; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | /** 9 | * @Author: alex 10 | * @Description: 11 | * @Date: created in 2019/1/17. 12 | */ 13 | public class DataBindBeforeAggregeListener implements AggregeListener { 14 | private static final Logger LOGGER = LoggerFactory.getLogger(DataBindBeforeAggregeListener.class); 15 | 16 | @Subscribe 17 | @Override 18 | public void lister(DataBindBeforeAggregeEvent event) { 19 | if (LOGGER.isDebugEnabled()) LOGGER.debug("data={}", event.getItem()); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/context/session/InterceptorAfterAggregeEvent.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.context.session; 2 | 3 | import com.github.middleware.aggregate.context.AggregeEvent; 4 | 5 | /** 6 | * @Author: alex 7 | * @Description: AggregeEngineActivetor.intercept 退出前 8 | * @Date: created in 2019/1/17. 9 | */ 10 | public class InterceptorAfterAggregeEvent extends AggregeEvent { 11 | private transient Object result; 12 | 13 | public InterceptorAfterAggregeEvent(Object source, Object result) { 14 | super(source); 15 | this.result = result; 16 | } 17 | 18 | public Object getResult() { 19 | return result; 20 | } 21 | 22 | public void setResult(Object result) { 23 | this.result = result; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/context/session/InterceptorAfterAggregeListener.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.context.session; 2 | 3 | import com.github.middleware.aggregate.context.AggregeContext; 4 | import com.github.middleware.aggregate.context.AggregeListener; 5 | import com.google.common.eventbus.Subscribe; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | /** 10 | * @Author: alex 11 | * @Description: 12 | * @Date: created in 2019/1/17. 13 | */ 14 | public class InterceptorAfterAggregeListener implements AggregeListener { 15 | private static final Logger LOGGER = LoggerFactory.getLogger(InterceptorAfterAggregeListener.class); 16 | 17 | @Subscribe 18 | @Override 19 | public void lister(InterceptorAfterAggregeEvent event) { 20 | if (LOGGER.isDebugEnabled()) LOGGER.debug("method={},data={}", event.getSource(), event.getResult()); 21 | AggregeContext.removeContext(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/context/session/InterceptorBeforeAggregeEvent.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.context.session; 2 | 3 | import com.github.middleware.aggregate.context.AggregeEvent; 4 | 5 | /** 6 | * @Author: alex 7 | * @Description: AggregeEngineActivetor.intercept 进入后 8 | * @Date: created in 2019/1/17. 9 | */ 10 | public class InterceptorBeforeAggregeEvent extends AggregeEvent { 11 | 12 | public InterceptorBeforeAggregeEvent(Object source) { 13 | super(source); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/context/session/InterceptorBeforeAggregeListener.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.context.session; 2 | 3 | import com.github.middleware.aggregate.context.AggregeContext; 4 | import com.github.middleware.aggregate.context.AggregeListener; 5 | import com.google.common.eventbus.Subscribe; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | /** 10 | * @Author: alex 11 | * @Description: 12 | * @Date: created in 2019/1/17. 13 | */ 14 | public class InterceptorBeforeAggregeListener implements AggregeListener { 15 | private static final Logger LOGGER = LoggerFactory.getLogger(InterceptorBeforeAggregeListener.class); 16 | 17 | @Subscribe 18 | @Override 19 | public void lister(InterceptorBeforeAggregeEvent event) { 20 | if (LOGGER.isDebugEnabled()) LOGGER.debug("method={}" ,event.getSource()); 21 | AggregeContext.getContext().setFireSource(event.getSource().toString()); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/contract/ResponseResolver.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.contract; 2 | 3 | /** 4 | * 包含自定义convert,过滤 5 | */ 6 | /** 7 | * @Author: alex 8 | * @Description: 9 | * @Date: created in 2019/1/10. 10 | */ 11 | public interface ResponseResolver { 12 | Object resolve(Object response); 13 | } 14 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/contract/ServiceConsumerEndpoint.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.contract; 2 | 3 | 4 | /** 5 | * @Author: alex 6 | * @Description: esb、eureka、tcp、普通的bean 7 | * @Date: created in 2019/1/9. 8 | */ 9 | public interface ServiceConsumerEndpoint { 10 | Object getServiceBean(String beanName, Object applicationContext); 11 | } 12 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/contract/support/NothingResponseResolver.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.contract.support; 2 | 3 | import com.github.middleware.aggregate.contract.ResponseResolver; 4 | 5 | /** 6 | * @Author: alex 7 | * @Description: 8 | * @Date: created in 2019/1/10. 9 | */ 10 | public class NothingResponseResolver implements ResponseResolver { 11 | @Override 12 | public Object resolve(Object response) { 13 | return response; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/contract/support/Proxys.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.contract.support; 2 | 3 | import com.github.middleware.aggregate.contract.ServiceConsumerEndpoint; 4 | import com.github.middleware.aggregate.core.AggregeException; 5 | import com.github.middleware.aggregate.core.support.ExtensionLoaders; 6 | import com.google.common.base.Preconditions; 7 | import com.google.common.base.Strings; 8 | import com.google.common.collect.Maps; 9 | import org.springframework.util.ClassUtils; 10 | 11 | import java.util.Map; 12 | 13 | /** 14 | * @Author: alex 15 | * @Description: 16 | * @Date: created in 2019/1/9. 17 | */ 18 | public final class Proxys { 19 | private static final Map serviceEndpoint = Maps.newConcurrentMap(); 20 | 21 | private static Object monitor = new Object(); 22 | 23 | private Proxys() { 24 | } 25 | 26 | public static Object getBean(String proxyName, Object springIOC) { 27 | Preconditions.checkArgument(!Strings.isNullOrEmpty(proxyName), "获取Client Proxy失败,参数AggregeProxy[name]为必填项。"); 28 | if (serviceEndpoint.containsKey(proxyName)) { 29 | return serviceEndpoint.get(proxyName); 30 | } 31 | if (proxyName.startsWith("#")) { 32 | loadBean(proxyName, springIOC); 33 | } else { 34 | newBean(proxyName); 35 | } 36 | return serviceEndpoint.get(proxyName); 37 | } 38 | 39 | private static void newBean(String cls) { 40 | Object proxy = ServiceEndpointCreators.instance(cls); 41 | synchronized (monitor) { 42 | serviceEndpoint.put(cls, proxy); 43 | } 44 | } 45 | 46 | private static void loadBean(String beanName, Object applicationContext) { 47 | synchronized (monitor) { 48 | ExtensionLoaders.getExtensionLoader(ServiceConsumerEndpoint.class).flatMap(x -> x.getExtension()).ifPresent(x -> { 49 | String name = beanName.substring(1); 50 | Object serviceBean = x.getServiceBean(name, applicationContext); 51 | serviceEndpoint.put(beanName, serviceBean); 52 | }); 53 | } 54 | } 55 | 56 | public static class ServiceEndpointCreators { 57 | private ServiceEndpointCreators() { 58 | } 59 | 60 | public static Object instance(String cls) { 61 | try { 62 | return ClassUtils.forName(cls, Thread.currentThread().getContextClassLoader()).newInstance(); 63 | } catch (Exception e) { 64 | throw new AggregeException("实例化AggregeProxy.name[" + cls + "]失败,", e); 65 | } 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/core/AggregeEngine.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.core; 2 | 3 | import com.github.middleware.aggregate.config.MergeProperties; 4 | import com.google.common.eventbus.EventBus; 5 | import com.github.middleware.aggregate.annonation.AggregeEnable; 6 | 7 | /** 8 | * @Author: alex 9 | * @Description: 功能描述:完成对数据项(Item)的聚合及绑定 10 | * @Date: created in 2019/1/15. 11 | */ 12 | public interface AggregeEngine { 13 | void loadConfig(MergeProperties config); 14 | 15 | void start(); 16 | 17 | boolean isRunning(); 18 | 19 | void stop(); 20 | 21 | Object dataBind(RequestPayLoad requestPayLoad); 22 | 23 | EventBus getEventBus(); 24 | } 25 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/core/AggregeEngineActivetor.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.core; 2 | 3 | 4 | /** 5 | * @Author: alex 6 | * @Description: 7 | * @Date: created in 2019/1/15. 8 | */ 9 | public interface AggregeEngineActivetor { 10 | Object intercept(RequestPayLoad request); 11 | 12 | AggregeEngine getAggregeEngine(); 13 | } 14 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/core/AggregeException.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.core; 2 | 3 | /** 4 | * @Author: alex 5 | * @Description: 6 | * @Date: created in 2019/2/15. 7 | */ 8 | public class AggregeException extends RuntimeException { 9 | private String requestId; 10 | private String errorCode; 11 | private String errorMessage; 12 | 13 | public AggregeException(String errorMessage) { 14 | this(errorMessage, null); 15 | } 16 | 17 | public AggregeException(Throwable cause) { 18 | this(null, cause); 19 | } 20 | 21 | public AggregeException(String errorMessage, Throwable cause) { 22 | super(null, cause); 23 | this.errorMessage = errorMessage; 24 | } 25 | 26 | public AggregeException(String errorMessage, String errorCode, String requestId, Throwable cause) { 27 | this(errorMessage, cause); 28 | this.errorCode = errorCode; 29 | this.requestId = requestId; 30 | } 31 | 32 | public AggregeException(String errorMessage, String errorCode, String requestId) { 33 | this(errorMessage, errorCode, requestId, null); 34 | } 35 | 36 | @Override 37 | public String getMessage() { 38 | return super.getMessage() 39 | + (requestId == null ? "" : "\n[requestId]: " + requestId) 40 | + (errorCode == null ? "" : "\n[errorCode]: " + errorCode); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/core/ExtensionLoader.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.core; 2 | 3 | import java.util.List; 4 | import java.util.Optional; 5 | 6 | /** 7 | * @Author: alex 8 | * @Description: 9 | * @Date: created in 2019/1/9. 10 | */ 11 | public interface ExtensionLoader { 12 | List getExtensions(); 13 | 14 | Optional getExtension(); 15 | 16 | Optional getExtension(String regex); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/core/LasyLoadData.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.core; 2 | 3 | import java.util.function.Supplier; 4 | 5 | /** 6 | * @Author: alex 7 | * @Description: 封装被拦截的业务方法,提供触发点 8 | * @Date: created in 2019/1/11. 9 | */ 10 | @FunctionalInterface 11 | public interface LasyLoadData extends Supplier { 12 | } 13 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/core/RequestPayLoad.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.core; 2 | 3 | import com.github.middleware.aggregate.annonation.AggregeEnable; 4 | 5 | import java.io.Serializable; 6 | import java.lang.reflect.Method; 7 | 8 | /** 9 | * @Author: alex.chen 10 | * @Description: 11 | * @Date: 2019/10/30 12 | */ 13 | public class RequestPayLoad implements Serializable { 14 | private String eventSource; 15 | private Object springIOC; 16 | private T data; 17 | private LasyLoadData lasyLoadData; 18 | private Boolean parallel; 19 | private AggregeEnable enable; 20 | 21 | public RequestPayLoad(String eventSource, Object springIOC, T data, Boolean parallel) { 22 | this.eventSource = eventSource; 23 | this.springIOC = springIOC; 24 | this.data = data; 25 | this.parallel = parallel; 26 | } 27 | 28 | public RequestPayLoad(Method intercept, Object springIOC, LasyLoadData lasyLoadData, AggregeEnable enable) { 29 | if (intercept != null) { 30 | eventSource = String.format("%s.%s", intercept.getDeclaringClass().getName(), intercept.getName()); 31 | } 32 | this.springIOC = springIOC; 33 | this.lasyLoadData = lasyLoadData; 34 | if (enable != null) { 35 | parallel = enable.parallel(); 36 | } 37 | } 38 | 39 | public String getEventSource() { 40 | return eventSource; 41 | } 42 | 43 | public void setEventSource(String eventSource) { 44 | this.eventSource = eventSource; 45 | } 46 | 47 | public Object getSpringIOC() { 48 | return springIOC; 49 | } 50 | 51 | public void setSpringIOC(Object springIOC) { 52 | this.springIOC = springIOC; 53 | } 54 | 55 | public T getData() { 56 | return data; 57 | } 58 | 59 | public void setData(T data) { 60 | this.data = data; 61 | } 62 | 63 | public LasyLoadData getLasyLoadData() { 64 | return lasyLoadData; 65 | } 66 | 67 | public void setLasyLoadData(LasyLoadData lasyLoadData) { 68 | this.lasyLoadData = lasyLoadData; 69 | } 70 | 71 | public Boolean getParallel() { 72 | return parallel; 73 | } 74 | 75 | public void setParallel(Boolean parallel) { 76 | this.parallel = parallel; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/core/support/AbstractAggregeEngineActivetor.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.core.support; 2 | 3 | import com.github.middleware.aggregate.annonation.AggregeEnable; 4 | import com.github.middleware.aggregate.context.session.DataBindBeforeAggregeEvent; 5 | import com.github.middleware.aggregate.context.session.InterceptorAfterAggregeEvent; 6 | import com.github.middleware.aggregate.context.session.InterceptorBeforeAggregeEvent; 7 | import com.github.middleware.aggregate.core.*; 8 | import com.google.common.base.Preconditions; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | /** 13 | * @Author: alex.chen 14 | * @Description: 15 | * @Date: 2019/10/30 16 | */ 17 | public abstract class AbstractAggregeEngineActivetor implements AggregeEngineActivetor { 18 | private static final Logger LOGGER = LoggerFactory.getLogger(AbstractAggregeEngineActivetor.class); 19 | protected AggregeEngine aggregeEngine; 20 | 21 | public AbstractAggregeEngineActivetor() { 22 | ExtensionLoaders.getExtensionLoader(AggregeEngine.class).flatMap(ExtensionLoader::getExtension).ifPresent(x -> aggregeEngine = x); 23 | } 24 | 25 | @Override 26 | public Object intercept(RequestPayLoad request) { 27 | Preconditions.checkNotNull(request.getEventSource(), "target method is required."); 28 | Preconditions.checkNotNull(aggregeEngine, "aggregeEngine is required."); 29 | Preconditions.checkState(aggregeEngine.isRunning(), "aggregeEngine must be start."); 30 | try { 31 | aggregeEngine.getEventBus().post(new InterceptorBeforeAggregeEvent(request.getEventSource())); 32 | Object item = request.getData(); 33 | if (request.getLasyLoadData() != null) { 34 | item = request.getLasyLoadData().get(); 35 | } 36 | if (item == null) { 37 | LOGGER.warn("{}的返回值为null.", request.getEventSource()); 38 | return null; 39 | } 40 | request.setData(item); 41 | aggregeEngine.getEventBus().post(new DataBindBeforeAggregeEvent(request.getEventSource(), item)); 42 | Object result = doDataBind(request); 43 | aggregeEngine.getEventBus().post(new InterceptorAfterAggregeEvent(request.getEventSource(), result)); 44 | return result; 45 | } catch (AggregeException ex1) { 46 | aggregeEngine.getEventBus().post(new InterceptorAfterAggregeEvent(request.getEventSource(), null)); 47 | throw ex1; 48 | } catch (Exception ex) { 49 | aggregeEngine.getEventBus().post(new InterceptorAfterAggregeEvent(request.getEventSource(), null)); 50 | throw new AggregeException(ex); 51 | } 52 | } 53 | 54 | @Override 55 | public AggregeEngine getAggregeEngine() { 56 | return aggregeEngine; 57 | } 58 | 59 | protected abstract Object doDataBind(RequestPayLoad request); 60 | } 61 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/core/support/AggregeEngineActivetorFactory.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.core.support; 2 | 3 | import com.github.middleware.aggregate.core.AggregeEngineActivetor; 4 | 5 | /** 6 | * @Author: alex 7 | * @Description: 8 | * @Date: created in 2019/1/15. 9 | */ 10 | public class AggregeEngineActivetorFactory { 11 | private static final AggregeEngineActivetorFactory FACTORY = new AggregeEngineActivetorFactory(); 12 | 13 | private AggregeEngineActivetorFactory() { 14 | } 15 | 16 | public static AggregeEngineActivetorFactory getInstance() { 17 | return FACTORY; 18 | } 19 | 20 | public AggregeEngineActivetor create(Boolean sateful) { 21 | if (sateful == null) { 22 | return getResource(); 23 | } 24 | return new GenClzProxyAggregeEngineActivetor(); 25 | } 26 | 27 | public AggregeEngineActivetor getResource() { 28 | return ResourceHolder.AOP_ENGINE; 29 | } 30 | 31 | private static class ResourceHolder { 32 | // This will be lazily initialised 33 | public static AggregeEngineActivetor AOP_ENGINE = new DefaultAggregeEngineActivetor(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/core/support/AggregeEngineActivetors.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.core.support; 2 | 3 | import com.github.middleware.aggregate.core.AggregeEngineActivetor; 4 | 5 | /** 6 | * @Author: alex 7 | * @Description: 8 | * @Date: created in 2019/1/15. 9 | */ 10 | public class AggregeEngineActivetors { 11 | private AggregeEngineActivetors() { 12 | 13 | } 14 | 15 | public static AggregeEngineActivetor getEngineAcitvetor() { 16 | return AggregeEngineActivetorFactory.getInstance().create(null); 17 | } 18 | 19 | public static AggregeEngineActivetor getEngineAcitvetorStateful() { 20 | return AggregeEngineActivetorFactory.getInstance().create(true); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/core/support/DefaultAggregeEngine.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.core.support; 2 | 3 | import com.github.middleware.aggregate.config.MergeProperties; 4 | import com.github.middleware.aggregate.context.AggregeContext; 5 | import com.github.middleware.aggregate.context.AggregeListener; 6 | import com.github.middleware.aggregate.core.AggregeEngine; 7 | import com.github.middleware.aggregate.core.AggregeException; 8 | import com.github.middleware.aggregate.core.ExtensionLoader; 9 | import com.github.middleware.aggregate.core.RequestPayLoad; 10 | import com.github.middleware.aggregate.flow.ItemBinder; 11 | import com.github.middleware.aggregate.flow.ItemCommand; 12 | import com.github.middleware.aggregate.flow.builder.Steps; 13 | import com.github.middleware.aggregate.flow.context.Invocation; 14 | import com.github.middleware.aggregate.source.MetaHolderFactory; 15 | import com.github.middleware.aggregate.source.bean.MetaHolder; 16 | import com.google.common.base.Preconditions; 17 | import com.google.common.collect.Lists; 18 | import com.google.common.eventbus.EventBus; 19 | import com.github.middleware.aggregate.context.container.StartedAggregeEvent; 20 | import com.github.middleware.aggregate.context.container.StopAggregeEvent; 21 | import com.github.middleware.aggregate.annonation.AggregeEnable; 22 | import io.reactivex.Flowable; 23 | import io.reactivex.schedulers.Schedulers; 24 | import org.yaml.snakeyaml.Yaml; 25 | 26 | import java.util.List; 27 | import java.util.concurrent.*; 28 | import java.util.concurrent.atomic.AtomicBoolean; 29 | import java.util.concurrent.atomic.AtomicInteger; 30 | 31 | /** 32 | * @Author: alex 33 | * @Description: 34 | * @Date: created in 2019/1/15. 35 | */ 36 | public final class DefaultAggregeEngine implements AggregeEngine { 37 | private AtomicBoolean start = new AtomicBoolean(false); 38 | private static final String PROPERTY_FILE_NAME = "data-aggrege.yml"; 39 | private List notBatchFilterRules = Lists.newArrayList(ItemCommand.BATCHPROXYARGBUILD, ItemCommand.BATCHPROXYFETCHDATA); 40 | private MergeProperties properties; 41 | private ThreadPoolExecutor threadPoolExecutor = null; 42 | private MetaHolderFactory metaHolderFactory; 43 | private ItemBinder itemBinder; 44 | private EventBus eventBus; 45 | 46 | @Override 47 | public void start() { 48 | if (start.compareAndSet(false, true)) { 49 | initComponent(); 50 | eventBus.post(new StartedAggregeEvent("start")); 51 | } 52 | } 53 | 54 | /** 55 | * 支持spring或非spring环境下配置 56 | * 57 | * @param config 58 | */ 59 | @Override 60 | public void loadConfig(MergeProperties config) { 61 | if (config != null) { 62 | properties = config; 63 | } 64 | if (properties == null) { 65 | //读配置 66 | properties = readProperty(MergeProperties.class, PROPERTY_FILE_NAME); 67 | } 68 | } 69 | 70 | private void initComponent() { 71 | loadConfig(null); 72 | threadPoolExecutor = new ThreadPoolExecutor(properties.getCorePoolSize(), properties.getCorePoolSize(), properties.getKeepAliveTime(), 73 | TimeUnit.SECONDS, new LinkedBlockingQueue(properties.getWorkQueueSize()), new NamedThreadFactory("aggrege"), new ThreadPoolExecutor.AbortPolicy()); 74 | //实例化元数据读取组件 75 | ExtensionLoaders.getExtensionLoader(MetaHolderFactory.class).flatMap(ExtensionLoader::getExtension).ifPresent(x -> { 76 | metaHolderFactory = x; 77 | metaHolderFactory.lasyInit(properties); 78 | }); 79 | //实例化数据聚合处理组件 80 | itemBinder = Steps.getBuilder().start().config(properties).loadAndSort().buildInvokerChain(); 81 | //事件风暴组件 82 | eventBus = new EventBus(); 83 | ExtensionLoaders.getExtensionLoader(AggregeListener.class).ifPresent(x -> { 84 | x.getExtensions().forEach(v -> eventBus.register(v)); 85 | }); 86 | } 87 | 88 | @Override 89 | public boolean isRunning() { 90 | return start.get(); 91 | } 92 | 93 | @Override 94 | public void stop() { 95 | if (start.compareAndSet(true, false)) { 96 | eventBus.post(new StopAggregeEvent("stop")); 97 | threadPoolExecutor.shutdown(); 98 | } 99 | } 100 | 101 | @Override 102 | public Object dataBind(RequestPayLoad request) { 103 | Preconditions.checkArgument(start.get(), "AggregeEngine未启动,请确认用法是否正确!"); 104 | if (request.getData() == null) { 105 | return null; 106 | } 107 | Invocation invocation = new Invocation(request.getParallel(), eventBus, AggregeContext.getContext()); 108 | invocation.setSpringIOC(request.getSpringIOC()); 109 | if (request.getData() instanceof List) { 110 | List list = (List) request.getData(); 111 | return mergeItems(list, invocation); 112 | } 113 | return mergeItem(request.getData().getClass(), request.getData(), invocation); 114 | } 115 | 116 | private Object mergeItem(Class sourceCls, Object item, Invocation invocation) { 117 | List metas = metaHolderFactory.create(sourceCls); 118 | if (metas == null || metas.isEmpty()) { 119 | return item; 120 | } 121 | boolean parallel = invocation.getParallel(); 122 | if (parallel) { 123 | Flowable.fromIterable(() -> metas.iterator()).parallel().runOn(Schedulers.from(threadPoolExecutor)).map(x -> { 124 | realMerge(x, invocation, item); 125 | return 0; 126 | }).sequential().blockingLast(); 127 | } else { 128 | Flowable.fromIterable(() -> metas.iterator()).subscribe(x -> { 129 | realMerge(x, invocation, item); 130 | }); 131 | } 132 | return item; 133 | } 134 | 135 | private void realMerge(MetaHolder meta, Invocation invocation, Object item) { 136 | /** 137 | * 为何直接使用invocation.setItemElementMeta(meta)? 138 | * 使用它必须对realMerge添加synchronized,为了提高并发而采用invocation.getMetaContext() 139 | */ 140 | invocation.getMetaContext().setItemElementMeta(meta); 141 | try { 142 | if (invocation.getMetaContext().getFilterRules() == null && !invocation.getMetaContext().isBatch()) { 143 | //过滤某些链 144 | invocation.getMetaContext().setFilterRules(notBatchFilterRules); 145 | } 146 | itemBinder.handle(null, item, invocation); 147 | } finally { 148 | invocation.removeMetaContext(); 149 | } 150 | } 151 | 152 | private Object mergeItems(List items, Invocation invocation) { 153 | invocation.setOrgItems(items); 154 | items.forEach(x -> mergeItem(x.getClass(), x, invocation)); 155 | return items; 156 | } 157 | 158 | @Override 159 | public EventBus getEventBus() { 160 | return eventBus; 161 | } 162 | 163 | private T readProperty(Class clz, String fileName) { 164 | try { 165 | Yaml yaml = new Yaml(); 166 | return yaml.loadAs(this.getClass().getClassLoader().getResourceAsStream(fileName), clz); 167 | } catch (Exception ex) { 168 | throw new AggregeException("数据聚合组件读取配置失败,", ex); 169 | } 170 | } 171 | 172 | public static class NamedThreadFactory implements ThreadFactory { 173 | private static final AtomicInteger poolNumber = new AtomicInteger(1); 174 | private final ThreadGroup group; 175 | private final AtomicInteger threadNumber = new AtomicInteger(1); 176 | private final String namePrefix; 177 | 178 | public NamedThreadFactory(String prefixName) { 179 | SecurityManager s = System.getSecurityManager(); 180 | group = (s != null) ? s.getThreadGroup() : 181 | Thread.currentThread().getThreadGroup(); 182 | namePrefix = prefixName + "-pool-" + poolNumber.getAndIncrement() + "-thread-"; 183 | } 184 | 185 | @Override 186 | public Thread newThread(Runnable r) { 187 | Thread t = new Thread(group, r, 188 | namePrefix + threadNumber.getAndIncrement(), 189 | 0); 190 | if (t.isDaemon()) { 191 | t.setDaemon(false); 192 | } 193 | if (t.getPriority() != Thread.NORM_PRIORITY) { 194 | t.setPriority(Thread.NORM_PRIORITY); 195 | } 196 | return t; 197 | } 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/core/support/DefaultAggregeEngineActivetor.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.core.support; 2 | 3 | import com.github.middleware.aggregate.core.*; 4 | import com.google.common.base.Preconditions; 5 | import com.github.middleware.aggregate.annonation.AggregeEnable; 6 | import com.github.middleware.aggregate.context.session.DataBindBeforeAggregeEvent; 7 | import com.github.middleware.aggregate.context.session.InterceptorAfterAggregeEvent; 8 | import com.github.middleware.aggregate.context.session.InterceptorBeforeAggregeEvent; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | import javax.annotation.concurrent.ThreadSafe; 13 | import java.lang.reflect.Method; 14 | 15 | /** 16 | * @Author: alex 17 | * @Description: 客户端已经使用AOP切入(代理类已存在) 18 | * @Date: created in 2019/1/15. 19 | */ 20 | @ThreadSafe 21 | public class DefaultAggregeEngineActivetor extends AbstractAggregeEngineActivetor { 22 | private static final Logger LOGGER = LoggerFactory.getLogger(DefaultAggregeEngineActivetor.class); 23 | 24 | @Override 25 | protected Object doDataBind(RequestPayLoad request) { 26 | return aggregeEngine.dataBind(request); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/core/support/DefaultExtensionLoader.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.core.support; 2 | 3 | import com.github.middleware.aggregate.core.ExtensionLoader; 4 | import com.google.common.base.Strings; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | import java.util.Optional; 9 | import java.util.ServiceLoader; 10 | import java.util.concurrent.atomic.AtomicReference; 11 | 12 | /** 13 | * @Author: alex 14 | * @Description: 15 | * @Date: created in 2019/1/9. 16 | */ 17 | public class DefaultExtensionLoader implements ExtensionLoader { 18 | private final ServiceLoader serviceLoader; 19 | private List extTypes; 20 | 21 | public DefaultExtensionLoader(Class clz) { 22 | this(clz, Thread.currentThread().getContextClassLoader()); 23 | } 24 | 25 | public DefaultExtensionLoader(Class clz, ClassLoader classLoader) { 26 | serviceLoader = ServiceLoader.load(clz, classLoader); 27 | extTypes = new ArrayList(); 28 | for (T service : serviceLoader) { 29 | extTypes.add(service); 30 | } 31 | } 32 | 33 | @Override 34 | public List getExtensions() { 35 | return extTypes; 36 | } 37 | 38 | @Override 39 | public Optional getExtension() { 40 | if (isEmpty()) { 41 | return Optional.empty(); 42 | } 43 | return Optional.ofNullable(getExtensions().get(0)); 44 | } 45 | 46 | private boolean isEmpty() { 47 | List list = getExtensions(); 48 | return list == null || list.isEmpty(); 49 | } 50 | 51 | @Override 52 | public Optional getExtension(String regex) { 53 | if (isEmpty()) { 54 | return Optional.empty(); 55 | } 56 | if (!Strings.isNullOrEmpty(regex)) { 57 | AtomicReference result = new AtomicReference(); 58 | List list = getExtensions(); 59 | list.stream().filter(x -> x.getClass().getName().contains(regex)).findFirst().ifPresent(x -> result.set(x)); 60 | return Optional.ofNullable(result.get()); 61 | } 62 | return Optional.ofNullable(getExtensions().get(0)); 63 | } 64 | } 65 | 66 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/core/support/ExtensionLoaders.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.core.support; 2 | 3 | import com.github.middleware.aggregate.core.ExtensionLoader; 4 | import com.google.common.base.Preconditions; 5 | import com.google.common.collect.Maps; 6 | 7 | import java.util.Optional; 8 | import java.util.concurrent.ConcurrentMap; 9 | 10 | /** 11 | * @Author: alex 12 | * @Description: 13 | * @Date: created in 2019/1/9. 14 | */ 15 | public class ExtensionLoaders { 16 | private static final ConcurrentMap> EXTLOADERS = Maps.newConcurrentMap(); 17 | private static final Object monitor = new Object(); 18 | 19 | private ExtensionLoaders() { 20 | } 21 | 22 | public static Optional> getExtensionLoader(Class clz) { 23 | String key = loadClz(clz); 24 | return Optional.ofNullable((ExtensionLoader) EXTLOADERS.get(key)); 25 | } 26 | 27 | private static String loadClz(Class clz) { 28 | Preconditions.checkNotNull(clz, "clz is requird.."); 29 | String key = clz.getName(); 30 | if (!EXTLOADERS.containsKey(key)) { 31 | synchronized (monitor) { 32 | EXTLOADERS.put(key, new DefaultExtensionLoader(clz)); 33 | } 34 | } 35 | return key; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/core/support/GenClzProxyAggregeEngineActivetor.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.core.support; 2 | 3 | import com.github.middleware.aggregate.core.RequestPayLoad; 4 | 5 | import javax.annotation.concurrent.NotThreadSafe; 6 | 7 | /** 8 | * @Author: alex 9 | * @Description: 非spring-aop客户端(代理类不存在),需先先生成代理类 10 | * @Date: created in 2019/1/15. 11 | */ 12 | @NotThreadSafe 13 | public class GenClzProxyAggregeEngineActivetor extends AbstractAggregeEngineActivetor { 14 | 15 | public GenClzProxyAggregeEngineActivetor() { 16 | initEngine(); 17 | } 18 | 19 | private void initEngine() { 20 | if (!aggregeEngine.isRunning()) { 21 | aggregeEngine.start(); 22 | } 23 | } 24 | 25 | @Override 26 | protected Object doDataBind(RequestPayLoad request) { 27 | return aggregeEngine.dataBind(request); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/flow/ItemBinder.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.flow; 2 | 3 | import com.github.middleware.aggregate.config.MergeProperties; 4 | import com.github.middleware.aggregate.flow.context.Invocation; 5 | 6 | /** 7 | * @Author: alex 8 | * @Description: 9 | * @Date: created in 2019/1/11. 10 | */ 11 | public interface ItemBinder extends ItemCommand, ItemOrder, ItemInterceptor { 12 | public static final String ISFAST = "aggregate.isFast"; 13 | 14 | void lasyInit(MergeProperties properties); 15 | 16 | void handle(ItemBinder itemBinder, Object item, Invocation invocation); 17 | } 18 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/flow/ItemCommand.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.flow; 2 | 3 | /** 4 | * @Author: alex 5 | * @Description: 6 | * @Date: created in 2019/1/12. 7 | */ 8 | public interface ItemCommand { 9 | String getCommandName(); 10 | 11 | public static final String ALL = "*"; 12 | public static final String REQUESTVALIDATE = "RequestValidate"; 13 | public static final String PROXYARGBUILD = "ProxyArgBuild"; 14 | public static final String PROXYFETCHDATA = "ProxyFetchData"; 15 | public static final String PROXYRESPONSERESOLVER = "ProxyResponseResolver"; 16 | public static final String ITEMRESPONSE = "ItemResponse"; 17 | public static final String BATCHPROXYARGBUILD = "batchProxyArgBuild"; 18 | public static final String BATCHPROXYFETCHDATA = "batchProxyFetchData"; 19 | } 20 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/flow/ItemInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.flow; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * @Author: alex 7 | * @Description: 过滤某些Command 8 | * @Date: created in 2019/2/14. 9 | */ 10 | public interface ItemInterceptor { 11 | boolean filter(List filterRules); 12 | } 13 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/flow/ItemOrder.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.flow; 2 | 3 | /** 4 | * @Author: alex 5 | * @Description: 排序 6 | * @Date: created in 2019/1/18. 7 | */ 8 | public interface ItemOrder { 9 | /** 10 | * 尽可能以x*5的倍数,便于拓展(可对任何链进行介入) 11 | * 12 | * @return 13 | */ 14 | Integer getOrder(); 15 | } 16 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/flow/builder/ItemBinderChain.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.flow.builder; 2 | 3 | import com.github.middleware.aggregate.config.MergeProperties; 4 | import com.github.middleware.aggregate.flow.ItemBinder; 5 | import com.google.common.collect.Lists; 6 | import com.github.middleware.aggregate.flow.context.Invocation; 7 | 8 | import java.util.Collections; 9 | import java.util.List; 10 | 11 | /** 12 | * @Author: alex 13 | * @Description: 14 | * @Date: created in 2019/1/14. 15 | */ 16 | public class ItemBinderChain { 17 | private List itemHandles = Collections.synchronizedList(Lists.newArrayList()); 18 | 19 | public void addItemBinder(ItemBinder binder) { 20 | itemHandles.add(binder); 21 | } 22 | 23 | public ItemBinder buildInvokerChain() { 24 | ItemBinder last = null; 25 | for (int i = itemHandles.size() - 1; i >= 0; i--) { 26 | ItemBinder handle = itemHandles.get(i); 27 | ItemBinder next = last; 28 | last = new ItemBinder() { 29 | @Override 30 | public boolean filter(List filterRules) { 31 | return handle.filter(filterRules); 32 | } 33 | 34 | @Override 35 | public Integer getOrder() { 36 | return handle.getOrder(); 37 | } 38 | 39 | @Override 40 | public String getCommandName() { 41 | return handle.getCommandName(); 42 | } 43 | 44 | @Override 45 | public void lasyInit(MergeProperties properties) { 46 | handle.lasyInit(properties); 47 | } 48 | 49 | @Override 50 | public void handle(ItemBinder itemBinder, Object item, Invocation invocation) { 51 | handle.handle(next, item, invocation); 52 | } 53 | }; 54 | } 55 | return last; 56 | } 57 | 58 | public List getItemHandleChain() { 59 | return itemHandles; 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/flow/builder/Steps.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.flow.builder; 2 | 3 | import com.github.middleware.aggregate.config.MergeProperties; 4 | import com.github.middleware.aggregate.flow.ItemBinder; 5 | import com.github.middleware.aggregate.flow.support.*; 6 | import com.github.middleware.aggregate.core.support.ExtensionLoaders; 7 | 8 | import java.util.Collections; 9 | import java.util.List; 10 | 11 | /** 12 | * @Author: alex 13 | * @Description: 14 | * @Date: created in 2019/1/14. 15 | */ 16 | public class Steps { 17 | private Steps() { 18 | } 19 | 20 | public static StepBuilder getBuilder() { 21 | return new StepBuilder(); 22 | } 23 | 24 | public static class StepBuilder { 25 | private ItemBinderChain chain; 26 | private MergeProperties properties; 27 | 28 | public StepBuilder start() { 29 | chain = new ItemBinderChain(); 30 | return this; 31 | } 32 | 33 | public StepBuilder config(MergeProperties mergeProperties) { 34 | this.properties = mergeProperties; 35 | return this; 36 | } 37 | 38 | public StepBuilder next(ItemBinder itemBinder) { 39 | if (properties != null) { 40 | itemBinder.lasyInit(properties); 41 | } 42 | chain.addItemBinder(itemBinder); 43 | return this; 44 | } 45 | 46 | public ItemBinderChain loadAndSort() { 47 | ExtensionLoaders.getExtensionLoader(ItemBinder.class).ifPresent(x -> { 48 | List itemBinders = x.getExtensions(); 49 | Collections.sort(itemBinders, (o1, o2) -> o1.getOrder().compareTo(o2.getOrder())); 50 | itemBinders.forEach(this::next); 51 | }); 52 | return end(); 53 | } 54 | 55 | public ItemBinderChain end() { 56 | return chain; 57 | } 58 | 59 | /** 60 | * 替换为loadAndSort 61 | * @deprecated (废弃) 62 | * @return 63 | */ 64 | @Deprecated 65 | public ItemBinderChain standardBuild() { 66 | return this.next(new ItemRequestValidateCommand()) 67 | .next(new ItemProxyArgBuildCommand()) 68 | .next(new ItemProxyFetchDataCommand()) 69 | .next(new ItemProxyResponseResolverCommand()) 70 | .next(new ItemResponseCommand()).end(); 71 | } 72 | 73 | public ItemBinderChain build() { 74 | return chain; 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/flow/context/Invocation.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.flow.context; 2 | 3 | import com.github.middleware.aggregate.context.AggregeContext; 4 | import com.github.middleware.aggregate.source.bean.MetaHolder; 5 | import com.google.common.collect.Maps; 6 | import com.google.common.eventbus.EventBus; 7 | import com.github.middleware.aggregate.annonation.AggregeEnable; 8 | 9 | import java.util.HashMap; 10 | import java.util.List; 11 | 12 | /** 13 | * @Author: alex 14 | * @Description: 15 | * @Date: created in 2019/1/11. 16 | */ 17 | public class Invocation { 18 | private Boolean parallel; 19 | private EventBus eventBus; 20 | /** 21 | * 为何要定义aggregeContext?主要是ItemBinder有多线程不能使用AggregeContext.getContext() 22 | */ 23 | private AggregeContext aggregeContext; 24 | /** 25 | * META_LOCAL主要服务于单个Item 某个Meta,区别于AggregeContext 26 | */ 27 | private final ThreadLocal META_LOCAL = ThreadLocal.withInitial(MetaItemContext::new); 28 | private MetaHolder itemElementMeta; 29 | /** 30 | * 原始数据,批量时才有效 31 | */ 32 | protected List orgItems; 33 | private Object springIOC; 34 | 35 | public Invocation(Boolean parallel, EventBus eventBus, AggregeContext aggregeContext) { 36 | this.parallel = parallel; 37 | this.eventBus = eventBus; 38 | this.aggregeContext = aggregeContext; 39 | } 40 | 41 | public Boolean getParallel() { 42 | return parallel; 43 | } 44 | 45 | public void setParallel(Boolean parallel) { 46 | this.parallel = parallel; 47 | } 48 | 49 | public AggregeContext getAggregeContext() { 50 | return aggregeContext; 51 | } 52 | 53 | public void setAggregeContext(AggregeContext aggregeContext) { 54 | this.aggregeContext = aggregeContext; 55 | } 56 | 57 | public MetaItemContext getMetaContext() { 58 | return META_LOCAL.get(); 59 | } 60 | 61 | public void removeMetaContext() { 62 | META_LOCAL.remove(); 63 | } 64 | 65 | public EventBus getEventBus() { 66 | return eventBus; 67 | } 68 | 69 | public void setEventBus(EventBus eventBus) { 70 | this.eventBus = eventBus; 71 | } 72 | 73 | public MetaHolder getItemElementMeta() { 74 | return itemElementMeta; 75 | } 76 | 77 | public void setItemElementMeta(MetaHolder itemElementMeta) { 78 | this.itemElementMeta = itemElementMeta; 79 | } 80 | 81 | public List getOrgItems() { 82 | return orgItems; 83 | } 84 | 85 | public void setOrgItems(List orgItems) { 86 | this.orgItems = orgItems; 87 | } 88 | 89 | public Object getSpringIOC() { 90 | return springIOC; 91 | } 92 | 93 | public void setSpringIOC(Object springIOC) { 94 | this.springIOC = springIOC; 95 | } 96 | 97 | /** 98 | * 作用于Field 99 | */ 100 | public class MetaItemContext { 101 | private MetaHolder itemElementMeta; 102 | private List proxyParams; 103 | private Object proxyResult; 104 | private List filterRules; 105 | private List batchProxyParams; 106 | private Object batchProxyResult; 107 | /** 108 | * 批量时缓存field的值 109 | */ 110 | private HashMap filedValueCache; 111 | 112 | public MetaHolder getItemElementMeta() { 113 | return itemElementMeta; 114 | } 115 | 116 | public void setItemElementMeta(MetaHolder itemElementMeta) { 117 | this.itemElementMeta = itemElementMeta; 118 | } 119 | 120 | public List getProxyParams() { 121 | return proxyParams; 122 | } 123 | 124 | public void setProxyParams(List proxyParams) { 125 | this.proxyParams = proxyParams; 126 | } 127 | 128 | public Object getProxyResult() { 129 | return proxyResult; 130 | } 131 | 132 | public void setProxyResult(Object proxyResult) { 133 | this.proxyResult = proxyResult; 134 | } 135 | 136 | public List getFilterRules() { 137 | return filterRules; 138 | } 139 | 140 | public void setFilterRules(List filterRules) { 141 | this.filterRules = filterRules; 142 | } 143 | 144 | public List getBatchProxyParams() { 145 | return batchProxyParams; 146 | } 147 | 148 | public void setBatchProxyParams(List batchProxyParams) { 149 | this.batchProxyParams = batchProxyParams; 150 | } 151 | 152 | public Object getBatchProxyResult() { 153 | return batchProxyResult; 154 | } 155 | 156 | public void setBatchProxyResult(Object batchProxyResult) { 157 | this.batchProxyResult = batchProxyResult; 158 | } 159 | 160 | 161 | public HashMap getFiledValueCache() { 162 | return filedValueCache; 163 | } 164 | 165 | public void setFiledValueCache(HashMap filedValueCache) { 166 | this.filedValueCache = filedValueCache; 167 | } 168 | 169 | public Object getFiledValueCache(Integer key) { 170 | return filedValueCache.get(key); 171 | } 172 | 173 | public void addFiledValueCache(Integer key, Object value) { 174 | if (filedValueCache == null) { 175 | filedValueCache = Maps.newHashMap(); 176 | } 177 | this.filedValueCache.putIfAbsent(key, value); 178 | } 179 | 180 | public boolean isBatch() { 181 | if (itemElementMeta == null || itemElementMeta.getBatchProxyMeta() == null 182 | || itemElementMeta.getBatchProxyMeta().list().enable() == false || itemElementMeta.getBatchProxyMeta().item().enable() == false) { 183 | return false; 184 | } 185 | //从使用作用域中是否开启优化 186 | if (orgItems == null || orgItems.isEmpty()) { 187 | return false; 188 | } 189 | return true; 190 | } 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/flow/support/AbstractItemCommand.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.flow.support; 2 | 3 | import com.google.common.base.Strings; 4 | import com.github.middleware.aggregate.config.MergeProperties; 5 | import com.github.middleware.aggregate.flow.ItemBinder; 6 | import com.github.middleware.aggregate.flow.ItemCommand; 7 | import com.github.middleware.aggregate.flow.context.Invocation; 8 | 9 | import java.util.List; 10 | import java.util.Optional; 11 | 12 | /** 13 | * @Author: alex 14 | * @Description: 15 | * @Date: created in 2019/1/18. 16 | */ 17 | public abstract class AbstractItemCommand implements ItemBinder { 18 | protected MergeProperties config; 19 | 20 | @Override 21 | public void lasyInit(MergeProperties properties) { 22 | this.config = properties; 23 | } 24 | 25 | @Override 26 | public void handle(ItemBinder itemBinder, Object item, Invocation invocation) { 27 | if (!filter(invocation.getMetaContext().getFilterRules())) { 28 | handle(item, invocation); 29 | } 30 | Optional.ofNullable(itemBinder).ifPresent(x -> x.handle(itemBinder, item, invocation)); 31 | } 32 | 33 | public abstract void handle(Object item, Invocation invocation); 34 | 35 | /** 36 | * 过滤某些命令指令操作 37 | * 38 | * @param filterRules * 表示后续执行链全部终止,CommandName表示跳出某些,只有这两种场景 39 | * @return 40 | */ 41 | @Override 42 | 43 | public boolean filter(List filterRules) { 44 | if (filterRules == null || filterRules.isEmpty() || Strings.isNullOrEmpty(getCommandName())) { 45 | return false; 46 | } 47 | if (filterRules.size() == 1 && ItemCommand.ALL.equals(filterRules.get(0))) { 48 | return true; 49 | } 50 | return filterRules.contains(getCommandName()); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/flow/support/ItemProxyArgBuildCommand.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.flow.support; 2 | 3 | import com.github.middleware.aggregate.flow.ItemCommand; 4 | import com.github.middleware.aggregate.flow.context.Invocation; 5 | import com.github.middleware.aggregate.source.bean.FieldVisitor; 6 | import com.google.common.base.Preconditions; 7 | import com.google.common.base.Strings; 8 | import com.google.common.collect.Lists; 9 | import com.github.middleware.aggregate.annonation.AggregeProxyArg; 10 | import com.github.middleware.aggregate.constant.ArgGetMode; 11 | import com.github.middleware.aggregate.core.AggregeException; 12 | import java.util.List; 13 | import java.util.Map; 14 | import java.util.Optional; 15 | 16 | /** 17 | * @Author: alex 18 | * @Description: 获取远程服务参数信息 19 | * @Date: created in 2019/1/11. 20 | */ 21 | public class ItemProxyArgBuildCommand extends AbstractItemCommand { 22 | @Override 23 | public String getCommandName() { 24 | return ItemCommand.PROXYARGBUILD; 25 | } 26 | 27 | @Override 28 | public Integer getOrder() { 29 | return 15; 30 | } 31 | 32 | @Override 33 | public void handle(Object item, Invocation invocation) { 34 | if (invocation.getMetaContext().isBatch()) { 35 | Optional.ofNullable(invocation.getMetaContext().getItemElementMeta().getBatchProxyMeta().item().params()).ifPresent(x -> { 36 | invocation.getMetaContext().setProxyParams(getParams(x, invocation, item, true)); 37 | }); 38 | } else { 39 | Optional.ofNullable(invocation.getMetaContext().getItemElementMeta().getProxyArgMetas()).ifPresent(x -> { 40 | invocation.getMetaContext().setProxyParams(getParams(x, invocation, item, true)); 41 | }); 42 | } 43 | } 44 | 45 | protected List getParams(AggregeProxyArg[] args, Invocation invocation, Object item, boolean isItemOfBatch) { 46 | List params = Lists.newArrayList(); 47 | for (AggregeProxyArg arg : args) { 48 | if (Strings.isNullOrEmpty(arg.paramValue())) { 49 | Preconditions.checkArgument(!(Strings.isNullOrEmpty(arg.key()) && arg.argGetMode() != ArgGetMode.BATCH), "参数AggregateProxyArg.key为必填项。"); 50 | params.add(getParamValue(invocation, arg, item, isItemOfBatch)); 51 | } else { 52 | params.add(arg.paramValue()); 53 | } 54 | } 55 | return params; 56 | } 57 | 58 | private Object getParamValue(Invocation invocation, AggregeProxyArg arg, Object item, boolean isItemOfBatch) { 59 | switch (arg.argGetMode()) { 60 | case ITEM: 61 | return getPropertyValue(invocation, arg.key(), item, isItemOfBatch); 62 | case SESSION: 63 | return getSessionValue(invocation, arg.key()); 64 | case BATCH: 65 | return invocation.getMetaContext().getBatchProxyResult(); 66 | default: 67 | throw new AggregeException("未知的参数类型ArgGetMode=" + arg.argGetMode()); 68 | } 69 | } 70 | 71 | private Object getPropertyValue(Invocation invocation, String name, Object item, boolean isItemOfBatch) { 72 | Map dependFields = invocation.getMetaContext().getItemElementMeta().getDependFields(); 73 | Preconditions.checkNotNull(dependFields, "failed to get dependFields from class: %s", item.getClass().getName()); 74 | FieldVisitor field = dependFields.get(name); 75 | Preconditions.checkNotNull(field, "failed to get field[%s] from class: %s", name, item.getClass().getName()); 76 | if (invocation.getMetaContext().isBatch()) { 77 | if (isItemOfBatch) { 78 | return invocation.getMetaContext().getFiledValueCache(item.hashCode()); 79 | } else { 80 | List fields = Lists.newArrayList(); 81 | invocation.getOrgItems().forEach(x -> Optional.ofNullable(field.getField(x)).ifPresent(y -> { 82 | /** 83 | * 优化:缓存key为item的hash 84 | */ 85 | invocation.getMetaContext().addFiledValueCache(x.hashCode(), y); 86 | if (y instanceof List) { 87 | ((List) y).forEach(z -> fields.add(z)); 88 | } else { 89 | fields.add(y); 90 | } 91 | })); 92 | return fields.isEmpty() ? null : fields; 93 | } 94 | } else { 95 | return field.getField(item); 96 | } 97 | } 98 | 99 | private Object getSessionValue(Invocation invocation, String key) { 100 | return invocation.getAggregeContext().getAttachment(key); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/flow/support/ItemProxyFetchDataCommand.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.flow.support; 2 | 3 | import com.github.middleware.aggregate.config.MergeProperties; 4 | import com.github.middleware.aggregate.flow.ItemCommand; 5 | import com.github.middleware.aggregate.source.bean.FieldVisitor; 6 | import com.github.middleware.aggregate.source.bean.MethodVisitor; 7 | import com.google.common.base.Preconditions; 8 | import com.google.common.base.Strings; 9 | import com.google.common.cache.Cache; 10 | import com.google.common.cache.CacheBuilder; 11 | import com.github.middleware.aggregate.contract.ResponseResolver; 12 | import com.github.middleware.aggregate.contract.support.NothingResponseResolver; 13 | import com.github.middleware.aggregate.core.AggregeException; 14 | import com.github.middleware.aggregate.flow.context.Invocation; 15 | import com.github.middleware.aggregate.context.session.ContractInvokeAfterAggregeEvent; 16 | import com.github.middleware.aggregate.context.session.ContractInvokeBeforeAggregeEvent; 17 | import com.github.middleware.aggregate.contract.support.Proxys; 18 | import org.slf4j.Logger; 19 | import org.slf4j.LoggerFactory; 20 | import org.springframework.util.ClassUtils; 21 | 22 | import java.util.Optional; 23 | import java.util.concurrent.ExecutionException; 24 | 25 | /** 26 | * @Author: alex 27 | * @Description: 28 | * @Date: created in 2019/1/11. 29 | */ 30 | public class ItemProxyFetchDataCommand extends AbstractItemCommand { 31 | private static final Logger LOGGER = LoggerFactory.getLogger(ItemProxyFetchDataCommand.class); 32 | private Cache proxyMethodCache; 33 | private Cache responseResolverCache; 34 | private String remoteErrorMsg = "调用远程服务出错[%s.%s]"; 35 | 36 | @Override 37 | public void lasyInit(MergeProperties properties) { 38 | super.lasyInit(properties); 39 | proxyMethodCache = CacheBuilder.newBuilder().maximumSize(properties.getProxyMethodCacheSize()).build(); 40 | responseResolverCache = CacheBuilder.newBuilder().maximumSize(properties.getResponseResolverCacheSize()).build(); 41 | } 42 | 43 | @Override 44 | public String getCommandName() { 45 | return ItemCommand.PROXYFETCHDATA; 46 | } 47 | 48 | @Override 49 | public Integer getOrder() { 50 | return 20; 51 | } 52 | 53 | @Override 54 | public void handle(Object item, Invocation invocation) { 55 | Object response = request(invocation, item, true); 56 | Optional.ofNullable(response).ifPresent(x -> invocation.getMetaContext().setProxyResult(response)); 57 | } 58 | 59 | protected Object request(Invocation invocation, Object item, boolean isItemOfBatch) { 60 | String fireSource = getFireSource(invocation.getMetaContext().getItemElementMeta().getSourceField()); 61 | Object proxy = null; 62 | String methodName = null; 63 | Object[] args = null; 64 | Class resolver = null; 65 | if (invocation.getMetaContext().isBatch()) { 66 | if (isItemOfBatch) { 67 | invocation.getEventBus().post(new ContractInvokeBeforeAggregeEvent(fireSource, invocation.getMetaContext().getProxyParams(), invocation)); 68 | proxy = Proxys.getBean(invocation.getMetaContext().getItemElementMeta().getBatchProxyMeta().item().name(), invocation.getSpringIOC()); 69 | methodName = invocation.getMetaContext().getItemElementMeta().getBatchProxyMeta().item().method(); 70 | resolver = invocation.getMetaContext().getItemElementMeta().getBatchProxyMeta().item().resolver(); 71 | if (invocation.getMetaContext().getProxyParams() != null) { 72 | args = invocation.getMetaContext().getProxyParams().toArray(); 73 | } 74 | } else { 75 | invocation.getEventBus().post(new ContractInvokeBeforeAggregeEvent(fireSource, invocation.getMetaContext().getBatchProxyParams(), invocation)); 76 | proxy = Proxys.getBean(invocation.getMetaContext().getItemElementMeta().getBatchProxyMeta().list().name(), invocation.getSpringIOC()); 77 | methodName = invocation.getMetaContext().getItemElementMeta().getBatchProxyMeta().list().method(); 78 | resolver = invocation.getMetaContext().getItemElementMeta().getBatchProxyMeta().list().resolver(); 79 | if (invocation.getMetaContext().getBatchProxyParams() != null) { 80 | args = invocation.getMetaContext().getBatchProxyParams().toArray(); 81 | } 82 | } 83 | } else { 84 | invocation.getEventBus().post(new ContractInvokeBeforeAggregeEvent(fireSource, invocation.getMetaContext().getProxyParams(), invocation)); 85 | if (invocation.getMetaContext().getItemElementMeta().getProxyMeta().enable() == false) { 86 | invocation.getEventBus().post(new ContractInvokeAfterAggregeEvent(fireSource, null, invocation)); 87 | LOGGER.warn("{} 配置AggregeField[proxy]缺失,不做聚合填充!", fireSource); 88 | return null; 89 | } 90 | proxy = Proxys.getBean(invocation.getMetaContext().getItemElementMeta().getProxyMeta().name(), invocation.getSpringIOC()); 91 | methodName = invocation.getMetaContext().getItemElementMeta().getProxyMeta().method(); 92 | resolver = invocation.getMetaContext().getItemElementMeta().getProxyMeta().resolver(); 93 | if (invocation.getMetaContext().getProxyParams() != null) { 94 | args = invocation.getMetaContext().getProxyParams().toArray(); 95 | } 96 | } 97 | Object response = request(proxy, methodName, args, invocation.getMetaContext().getItemElementMeta().getFieldMeta().ignoreError()); 98 | return resolverResponse(response, resolver, invocation); 99 | } 100 | 101 | private Object resolverResponse(Object response, Class resolver, Invocation invocation) { 102 | if (response == null) { 103 | return null; 104 | } 105 | if (resolver == null || ClassUtils.isAssignable(resolver, NothingResponseResolver.class)) { 106 | return response; 107 | } 108 | try { 109 | ResponseResolver resolverObj = responseResolverCache.get(resolver.getName(), () -> resolver.newInstance()); 110 | return resolverObj.resolve(response); 111 | } catch (ExecutionException e) { 112 | throw new AggregeException(e); 113 | } 114 | } 115 | 116 | private String getFireSource(FieldVisitor field) { 117 | return String.format("%s.%s", field.getSource().getDeclaringClass().getTypeName(), field.getSource().getName()); 118 | } 119 | 120 | private Object request(Object proxy, String methodName, Object[] args, boolean ignoreError) { 121 | Preconditions.checkNotNull(!Strings.isNullOrEmpty(methodName), "参数校验失败,AggregeProxy.method为必填项。"); 122 | String cacheName = proxy.getClass().getName() + methodName; 123 | try { 124 | MethodVisitor method = proxyMethodCache.get(cacheName, () -> new MethodVisitor(proxy.getClass(), methodName, args)); 125 | return method.invokeMethod(proxy, args); 126 | } catch (Exception ex) { 127 | if (ignoreError) { 128 | LOGGER.error(String.format(remoteErrorMsg, proxy.getClass().getName(), methodName), ex); 129 | return null; 130 | } else { 131 | throw new AggregeException(String.format(remoteErrorMsg, proxy.getClass().getName(), methodName), ex); 132 | } 133 | } 134 | } 135 | 136 | } 137 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/flow/support/ItemProxyResponseResolverCommand.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.flow.support; 2 | 3 | import com.github.middleware.aggregate.config.MergeProperties; 4 | import com.github.middleware.aggregate.flow.ItemCommand; 5 | import com.github.middleware.aggregate.flow.context.Invocation; 6 | import com.google.common.cache.Cache; 7 | import com.google.common.cache.CacheBuilder; 8 | import com.github.middleware.aggregate.contract.ResponseResolver; 9 | import com.github.middleware.aggregate.core.AggregeException; 10 | 11 | import java.util.Optional; 12 | import java.util.concurrent.ExecutionException; 13 | 14 | /** 15 | * @Author: alex 16 | * @Description: 17 | * @Date: created in 2019/1/15. 18 | */ 19 | @Deprecated 20 | public class ItemProxyResponseResolverCommand extends AbstractItemCommand { 21 | private Cache responseResolverCache; 22 | 23 | @Override 24 | public void lasyInit(MergeProperties properties) { 25 | super.lasyInit(properties); 26 | responseResolverCache = CacheBuilder.newBuilder().maximumSize(properties.getResponseResolverCacheSize()).build(); 27 | } 28 | 29 | @Override 30 | public String getCommandName() { 31 | return ItemCommand.PROXYRESPONSERESOLVER; 32 | } 33 | 34 | @Override 35 | public Integer getOrder() { 36 | return 25; 37 | } 38 | 39 | @Override 40 | public void handle(Object item, Invocation invocation) { 41 | Class resolver = invocation.getMetaContext().getItemElementMeta().getProxyMeta().resolver(); 42 | Optional.ofNullable(resolver).ifPresent(x -> { 43 | try { 44 | ResponseResolver resolverObj = responseResolverCache.get(resolver.getName(), () -> x.newInstance()); 45 | invocation.getMetaContext().setProxyResult(resolverObj.resolve(invocation.getMetaContext().getProxyResult())); 46 | } catch (ExecutionException e) { 47 | throw new AggregeException(e); 48 | } 49 | }); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/flow/support/ItemRequestValidateCommand.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.flow.support; 2 | 3 | import com.github.middleware.aggregate.flow.ItemCommand; 4 | import com.github.middleware.aggregate.flow.context.Invocation; 5 | import com.google.common.base.Preconditions; 6 | import com.github.middleware.aggregate.context.session.BreakDataBindAggregeEvent; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | /** 11 | * @Author: alex 12 | * @Description: 13 | * @Date: created in 2019/1/11. 14 | */ 15 | public class ItemRequestValidateCommand extends AbstractItemCommand { 16 | private static final Logger LOGGER = LoggerFactory.getLogger(ItemRequestValidateCommand.class); 17 | 18 | @Override 19 | public void handle(Object item, Invocation invocation) { 20 | Preconditions.checkNotNull(item, "参数校验失败,item为必填项。"); 21 | Preconditions.checkNotNull(invocation, "参数校验失败,invocation为必填项。"); 22 | // 提前终止执行链 23 | if (invocation.getMetaContext().getItemElementMeta() == null) { 24 | LOGGER.warn("item[{}]元数据配置有误.", item); 25 | invocation.getEventBus().post(new BreakDataBindAggregeEvent(this, invocation)); 26 | } 27 | } 28 | 29 | @Override 30 | public String getCommandName() { 31 | return ItemCommand.REQUESTVALIDATE; 32 | } 33 | 34 | @Override 35 | public Integer getOrder() { 36 | return 1; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/flow/support/ItemResponseCommand.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.flow.support; 2 | 3 | import com.github.middleware.aggregate.flow.ItemCommand; 4 | import com.github.middleware.aggregate.flow.context.Invocation; 5 | import com.github.middleware.aggregate.core.AggregeException; 6 | 7 | /** 8 | * @Author: alex 9 | * @Description: 10 | * @Date: created in 2019/1/15. 11 | */ 12 | public class ItemResponseCommand extends AbstractItemCommand { 13 | @Override 14 | public String getCommandName() { 15 | return ItemCommand.ITEMRESPONSE; 16 | } 17 | 18 | @Override 19 | public Integer getOrder() { 20 | return 30; 21 | } 22 | 23 | @Override 24 | public void handle(Object item, Invocation invocation) { 25 | try { 26 | invocation.getMetaContext().getItemElementMeta().getSourceField().setField(item, invocation.getMetaContext().getProxyResult()); 27 | } catch (Exception e) { 28 | throw new AggregeException(e); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/flow/support/ItemsProxyArgBuildCommand.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.flow.support; 2 | 3 | import com.github.middleware.aggregate.flow.ItemCommand; 4 | import com.github.middleware.aggregate.flow.context.Invocation; 5 | 6 | import java.util.Optional; 7 | 8 | /** 9 | * @Author: alex 10 | * @Description: 11 | * @Date: created in 2019/2/14. 12 | */ 13 | public class ItemsProxyArgBuildCommand extends ItemProxyArgBuildCommand { 14 | @Override 15 | public String getCommandName() { 16 | return ItemCommand.BATCHPROXYARGBUILD; 17 | } 18 | 19 | @Override 20 | public Integer getOrder() { 21 | return 5; 22 | } 23 | 24 | @Override 25 | public void handle(Object item, Invocation invocation) { 26 | Optional.ofNullable(invocation.getMetaContext().getItemElementMeta().getBatchProxyMeta().list().params()).ifPresent(x -> { 27 | invocation.getMetaContext().setBatchProxyParams(getParams(x, invocation, item,false)); 28 | }); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/flow/support/ItemsProxyFetchDataCommand.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.flow.support; 2 | 3 | import com.github.middleware.aggregate.flow.ItemCommand; 4 | import com.github.middleware.aggregate.flow.context.Invocation; 5 | 6 | import java.util.Optional; 7 | 8 | 9 | /** 10 | * @Author: alex 11 | * @Description: 12 | * @Date: created in 2019/2/14. 13 | */ 14 | public class ItemsProxyFetchDataCommand extends ItemProxyFetchDataCommand { 15 | 16 | @Override 17 | public String getCommandName() { 18 | return ItemCommand.BATCHPROXYFETCHDATA; 19 | } 20 | 21 | @Override 22 | public Integer getOrder() { 23 | return 10; 24 | } 25 | 26 | @Override 27 | public void handle(Object item, Invocation invocation) { 28 | Object response = request(invocation, item, false); 29 | Optional.ofNullable(response).ifPresent(x -> invocation.getMetaContext().setBatchProxyResult(response)); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/source/MetaHolderFactory.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.source; 2 | 3 | import com.github.middleware.aggregate.config.MergeProperties; 4 | import com.github.middleware.aggregate.source.bean.MetaHolder; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * @Author: alex 10 | * @Description: 11 | * @Date: created in 2019/1/10. 12 | */ 13 | public interface MetaHolderFactory { 14 | void lasyInit(MergeProperties properties); 15 | 16 | List create(Class source); 17 | } 18 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/source/bean/FieldVisitor.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.source.bean; 2 | 3 | import com.github.middleware.aggregate.flow.ItemBinder; 4 | import com.github.middleware.aggregate.util.UnsafeUtils; 5 | import org.springframework.util.ReflectionUtils; 6 | 7 | import java.lang.reflect.Field; 8 | 9 | /** 10 | * @Author: alex.chen 11 | * @Description: 12 | * @Date: 2019/10/30 13 | */ 14 | public class FieldVisitor { 15 | private Field source; 16 | private Long offset; 17 | private Boolean isFast = true; 18 | 19 | public FieldVisitor(Field source) { 20 | this.source = source; 21 | if (source != null) { 22 | offset = UnsafeUtils.unsafe().objectFieldOffset(source); 23 | } 24 | if (Boolean.getBoolean(ItemBinder.ISFAST)) { 25 | isFast = true; 26 | } 27 | } 28 | 29 | public Object getField(Object target) { 30 | if (isFast) { 31 | return UnsafeUtils.unsafe().getObject(target, offset); 32 | } 33 | source.setAccessible(true); 34 | return ReflectionUtils.getField(source, target); 35 | } 36 | 37 | public void setField(Object target, Object value) { 38 | if (isFast) { 39 | UnsafeUtils.unsafe().putObject(target, offset, value); 40 | return; 41 | } 42 | source.setAccessible(true); 43 | ReflectionUtils.setField(source, target, value); 44 | } 45 | 46 | public Field getSource() { 47 | return source; 48 | } 49 | 50 | public void setSource(Field source) { 51 | this.source = source; 52 | } 53 | 54 | public Long getOffset() { 55 | return offset; 56 | } 57 | 58 | public void setOffset(Long offset) { 59 | this.offset = offset; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/source/bean/MetaHolder.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.source.bean; 2 | 3 | 4 | import com.google.common.collect.Maps; 5 | import com.github.middleware.aggregate.annonation.AggregeBatchProxy; 6 | import com.github.middleware.aggregate.annonation.AggregeField; 7 | import com.github.middleware.aggregate.annonation.AggregeProxy; 8 | import com.github.middleware.aggregate.annonation.AggregeProxyArg; 9 | 10 | import java.beans.PropertyDescriptor; 11 | import java.beans.PropertyEditor; 12 | import java.lang.reflect.Field; 13 | import java.util.Map; 14 | import java.util.Optional; 15 | 16 | /** 17 | * @Author: alex 18 | * @Description: 19 | * @Date: created in 2019/1/10. 20 | */ 21 | public class MetaHolder { 22 | private Class sourceClz; 23 | private FieldVisitor sourceField; 24 | private AggregeField fieldMeta; 25 | private AggregeProxy proxyMeta; 26 | private AggregeProxyArg[] proxyArgMetas; 27 | private Map dependFields; 28 | private AggregeBatchProxy batchProxyMeta; 29 | private PropertyDescriptor propertyDescriptor; 30 | private PropertyEditor propertyEditor; 31 | 32 | public MetaHolder(Class sourceClz, Field field, AggregeField fieldMeta) { 33 | this.sourceClz = sourceClz; 34 | this.sourceField = new FieldVisitor(field); 35 | Optional.ofNullable(fieldMeta).ifPresent(x -> { 36 | this.fieldMeta = fieldMeta; 37 | if (x.proxy() != null) { 38 | this.proxyMeta = x.proxy(); 39 | this.proxyArgMetas = x.proxy().params(); 40 | } 41 | if (x.batchProxy() != null) { 42 | this.batchProxyMeta = x.batchProxy(); 43 | } 44 | }); 45 | dependFields = Maps.newHashMap(); 46 | } 47 | 48 | public Class getSourceClz() { 49 | return sourceClz; 50 | } 51 | 52 | public void setSourceClz(Class sourceClz) { 53 | this.sourceClz = sourceClz; 54 | } 55 | 56 | public FieldVisitor getSourceField() { 57 | return sourceField; 58 | } 59 | 60 | public void setSourceField(FieldVisitor sourceField) { 61 | this.sourceField = sourceField; 62 | } 63 | 64 | public AggregeField getFieldMeta() { 65 | return fieldMeta; 66 | } 67 | 68 | public void setFieldMeta(AggregeField fieldMeta) { 69 | this.fieldMeta = fieldMeta; 70 | } 71 | 72 | public AggregeProxy getProxyMeta() { 73 | return proxyMeta; 74 | } 75 | 76 | public void setProxyMeta(AggregeProxy proxyMeta) { 77 | this.proxyMeta = proxyMeta; 78 | } 79 | 80 | public AggregeProxyArg[] getProxyArgMetas() { 81 | return proxyArgMetas; 82 | } 83 | 84 | public void setProxyArgMetas(AggregeProxyArg[] proxyArgMetas) { 85 | this.proxyArgMetas = proxyArgMetas; 86 | } 87 | 88 | public Map getDependFields() { 89 | return dependFields; 90 | } 91 | 92 | public void setDependFields(Map dependFields) { 93 | this.dependFields = dependFields; 94 | } 95 | 96 | public void addDependFields(String name, Field dependField) { 97 | this.dependFields.put(name, new FieldVisitor(dependField)); 98 | } 99 | 100 | public AggregeBatchProxy getBatchProxyMeta() { 101 | return batchProxyMeta; 102 | } 103 | 104 | public void setBatchProxyMeta(AggregeBatchProxy batchProxyMeta) { 105 | this.batchProxyMeta = batchProxyMeta; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/source/bean/MethodVisitor.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.source.bean; 2 | 3 | import com.github.middleware.aggregate.flow.ItemBinder; 4 | import com.github.middleware.aggregate.util.Reflections; 5 | import com.google.common.base.Preconditions; 6 | import org.springframework.util.ReflectionUtils; 7 | 8 | import java.lang.reflect.Method; 9 | 10 | /** 11 | * @Author: alex.chen 12 | * @Description: 13 | * @Date: 2019/10/30 14 | */ 15 | public class MethodVisitor { 16 | private Method source; 17 | private Boolean isFast = true; 18 | private Reflections.FastMethodInvoker fastMethod; 19 | 20 | public MethodVisitor(Class clazz, String methodName, Object... args) { 21 | findMethod(clazz, methodName, args); 22 | if (Boolean.getBoolean(ItemBinder.ISFAST)) { 23 | isFast = true; 24 | } 25 | } 26 | 27 | private void findMethod(Class clz, String methodName, Object... args) { 28 | Class[] parameterTypes = null; 29 | source = Reflections.getAccessibleMethodNotSafe(clz, methodName); 30 | Preconditions.checkNotNull(methodName, "Could not find method [" + methodName + "] on target [" + clz + "]"); 31 | fastMethod = Reflections.create(clz, source); 32 | } 33 | 34 | public Object invokeMethod(Object proxy, Object... args) { 35 | if (isFast) { 36 | return fastMethod.invoke(proxy, args); 37 | } 38 | return ReflectionUtils.invokeMethod(source, proxy, args); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/source/support/BeanPropertyLoaders.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.source.support; 2 | 3 | import com.google.common.cache.Cache; 4 | import com.google.common.cache.CacheBuilder; 5 | import com.github.middleware.aggregate.core.AggregeException; 6 | 7 | import java.beans.BeanInfo; 8 | import java.beans.Introspector; 9 | import java.beans.PropertyDescriptor; 10 | import java.util.stream.Stream; 11 | 12 | /** 13 | * @Author: alex 14 | * @Description: 15 | * @deprecated (无用) 16 | * @Date: created in 2019/1/10. 17 | */ 18 | @Deprecated 19 | public class BeanPropertyLoaders { 20 | private static Cache beanCahes; 21 | 22 | private BeanPropertyLoaders() { 23 | } 24 | 25 | public static PropertyDescriptor getPropDesc(Class sourceClz, String propertyName, int cacheSize) { 26 | try { 27 | if (beanCahes == null) { 28 | beanCahes = CacheBuilder.newBuilder().maximumSize(cacheSize).build(); 29 | } 30 | BeanInfo beanInfo = beanCahes.get(sourceClz.getName(), () -> Introspector.getBeanInfo(sourceClz)); 31 | return Stream.of(beanInfo.getPropertyDescriptors()).filter(x -> x.getName().equals(propertyName)).findFirst().get(); 32 | } catch (Exception ex) { 33 | throw new AggregeException(ex); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/source/support/ReflectMetaHolderFactory.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.source.support; 2 | 3 | import com.github.middleware.aggregate.config.MergeProperties; 4 | import com.github.middleware.aggregate.source.MetaHolderFactory; 5 | import com.google.common.base.Preconditions; 6 | import com.google.common.base.Strings; 7 | import com.google.common.cache.Cache; 8 | import com.google.common.cache.CacheBuilder; 9 | import com.google.common.collect.Lists; 10 | import com.google.common.collect.Maps; 11 | import com.github.middleware.aggregate.annonation.AggregeField; 12 | import com.github.middleware.aggregate.annonation.AggregeProxyArg; 13 | import com.github.middleware.aggregate.core.AggregeException; 14 | import com.github.middleware.aggregate.source.bean.MetaHolder; 15 | import org.slf4j.Logger; 16 | import org.slf4j.LoggerFactory; 17 | import org.springframework.util.ReflectionUtils; 18 | 19 | import java.lang.reflect.Field; 20 | import java.util.List; 21 | import java.util.Map; 22 | import java.util.concurrent.ExecutionException; 23 | 24 | /** 25 | * @Author: alex 26 | * @Description: 27 | * @Date: created in 2019/1/10. 28 | */ 29 | public class ReflectMetaHolderFactory implements MetaHolderFactory { 30 | private static final Logger LOGGER = LoggerFactory.getLogger(ReflectMetaHolderFactory.class); 31 | private Cache> clzMetasCache; 32 | 33 | @Override 34 | public void lasyInit(MergeProperties properties) { 35 | clzMetasCache = CacheBuilder.newBuilder().maximumSize(properties.getClzMetasCacheSize()).build(); 36 | } 37 | 38 | @Override 39 | public List create(Class source) { 40 | Preconditions.checkNotNull(clzMetasCache, "MetaHolderFactory初始化有誤!"); 41 | return read(source); 42 | } 43 | 44 | private List read(Class itemClz) { 45 | Preconditions.checkNotNull(itemClz, "itemClz is required."); 46 | try { 47 | String clzName = itemClz.getName(); 48 | return clzMetasCache.get(clzName, () -> { 49 | List result = Lists.newArrayList(); 50 | Map extFields = Maps.newConcurrentMap(); 51 | ReflectionUtils.doWithFields(itemClz, prop -> { 52 | AggregeField fieldMeta = prop.getAnnotation(AggregeField.class); 53 | if (fieldMeta != null) { 54 | MetaHolder property = new MetaHolder(itemClz, prop, fieldMeta); 55 | result.add(property); 56 | } else { 57 | extFields.put(prop.getName(), prop); 58 | } 59 | }); 60 | 61 | result.forEach(x -> { 62 | addDependFields(x, extFields, x.getProxyMeta().params(), clzName); 63 | addDependFields(x, extFields, x.getBatchProxyMeta().list().params(), clzName); 64 | addDependFields(x, extFields, x.getBatchProxyMeta().item().params(), clzName); 65 | }); 66 | return result; 67 | }); 68 | } catch (ExecutionException e) { 69 | throw new AggregeException(e); 70 | } 71 | } 72 | 73 | private void addDependFields(MetaHolder metaHolder, Map extFields, AggregeProxyArg[] params, String clzName) { 74 | if (params != null && params.length > 0) { 75 | for (AggregeProxyArg param : params) { 76 | if (!Strings.isNullOrEmpty(param.key())) { 77 | Field field = extFields.get(param.key()); 78 | if (field == null) { 79 | String key=param.key(); 80 | LOGGER.warn("failed to get field from class: {} by key: {}", clzName, key); 81 | } else { 82 | metaHolder.addDependFields(param.key(), extFields.get(param.key())); 83 | } 84 | } 85 | } 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/util/ArrayUtils.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.util; 2 | 3 | import java.lang.reflect.Array; 4 | 5 | /** 6 | * @Author: alex.chen 7 | * @Description: 8 | * @Date: 2019/10/30 9 | */ 10 | public abstract class ArrayUtils { 11 | public static final Class[] EMPTY_CLASS_ARRAY = new Class[0]; 12 | 13 | public static Class[] nullToEmpty(Class[] array) { 14 | return isEmpty((Object[]) array) ? EMPTY_CLASS_ARRAY : array; 15 | } 16 | 17 | public static boolean isEmpty(Object[] array) { 18 | return getLength(array) == 0; 19 | } 20 | 21 | public static int getLength(Object array) { 22 | return array == null ? 0 : Array.getLength(array); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/util/AsyncUtils.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.util; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | import java.util.concurrent.atomic.AtomicBoolean; 5 | 6 | /** 7 | * @Author: alex 8 | * @Description: 9 | * @Date: created in 2019/2/14. 10 | */ 11 | public abstract class AsyncUtils { 12 | private AsyncUtils() { 13 | } 14 | 15 | public static void awaitDone(AtomicBoolean isComplate, int maxBlockTimeout) { 16 | final long timeout = TimeUnit.MILLISECONDS.toNanos(maxBlockTimeout); 17 | final long deadline = System.nanoTime() + timeout; 18 | while (true) { 19 | if (isComplate.get() || awaitDone(deadline)) { 20 | break; 21 | } 22 | } 23 | } 24 | 25 | private static boolean awaitDone(long deadline) { 26 | long nanos = deadline - System.nanoTime(); 27 | if (nanos <= 0L) { 28 | return true; 29 | } 30 | return false; 31 | } 32 | 33 | private static boolean awaitDone(long timeout, long deadline) { 34 | long nanos = deadline - System.nanoTime(); 35 | if (nanos <= 0L) { 36 | return true; 37 | } 38 | return false; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/util/Reflections.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.util; 2 | 3 | import com.google.common.base.Preconditions; 4 | import com.google.common.base.Throwables; 5 | import com.google.common.collect.HashMultiset; 6 | import com.google.common.collect.Maps; 7 | import net.sf.cglib.reflect.FastClass; 8 | import net.sf.cglib.reflect.FastMethod; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | import java.lang.reflect.Method; 13 | import java.lang.reflect.Modifier; 14 | import java.util.IdentityHashMap; 15 | import java.util.Map; 16 | import java.util.concurrent.ConcurrentMap; 17 | import java.util.stream.Stream; 18 | 19 | /** 20 | * @Author: alex 21 | * @Description: 22 | * @Date: created in 2019/2/12. 23 | */ 24 | public abstract class Reflections { 25 | private static final Logger LOGGER = LoggerFactory.getLogger(Reflections.class); 26 | private static final Map, Class> primitiveWrapperTypeMap = new IdentityHashMap(8); 27 | private static ConcurrentMap, FastClass> fastClassMap = Maps.newConcurrentMap(); 28 | 29 | private Reflections() { 30 | } 31 | 32 | public static Method getAccessibleMethodNotSafe(Class clazz, String methodName) { 33 | Preconditions.checkNotNull(clazz, "Class must not be null"); 34 | Preconditions.checkNotNull(methodName, "Method name must not be null"); 35 | HashMultiset multiset = HashMultiset.create(); 36 | for (Class searchType = clazz; searchType != null; searchType = searchType.getSuperclass()) { 37 | if (searchType.isInterface()) { 38 | continue; 39 | } 40 | Method[] methods = searchType.getDeclaredMethods(); 41 | Method[] var5 = methods; 42 | Stream.of(var5).forEach(x -> multiset.add(x.getName())); 43 | int var6 = methods.length; 44 | for (int var7 = 0; var7 < var6; ++var7) { 45 | Method method = var5[var7]; 46 | if (methodName.equals(method.getName())) { 47 | if (multiset.count(methodName) != 1) { 48 | throw new RuntimeException(String.format("%s暂时不支持方法[%s]重写.", clazz.getName(), methodName)); 49 | } 50 | return method; 51 | } 52 | } 53 | } 54 | 55 | return null; 56 | } 57 | 58 | public static Method getAccessibleMethod(Class clazz, String methodName, Class... parameterTypes) { 59 | Preconditions.checkNotNull(clazz, "Class must not be null"); 60 | Preconditions.checkNotNull(methodName, "Method name must not be null"); 61 | Class[] theParameterTypes = ArrayUtils.nullToEmpty(parameterTypes); 62 | wrapClassses(theParameterTypes); 63 | Class searchType = clazz; 64 | 65 | while (searchType != Object.class) { 66 | try { 67 | Method method = searchType.getDeclaredMethod(methodName, theParameterTypes); 68 | makeAccessible(method); 69 | return method; 70 | } catch (NoSuchMethodException var6) { 71 | searchType = searchType.getSuperclass(); 72 | } 73 | } 74 | return null; 75 | } 76 | 77 | public static void makeAccessible(Method method) { 78 | if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers())) && !method.isAccessible()) { 79 | method.setAccessible(true); 80 | } 81 | } 82 | 83 | private static void wrapClassses(Class[] source) { 84 | for (int i = 0; i < source.length; ++i) { 85 | Class wrapClass = (Class) primitiveWrapperTypeMap.get(source[i]); 86 | if (wrapClass != null) { 87 | source[i] = wrapClass; 88 | } 89 | } 90 | 91 | } 92 | 93 | public static FastMethodInvoker create(Class clz, Method method) { 94 | FastClass fastClz = fastClassMap.get(clz); 95 | if (fastClz == null) { 96 | fastClz = FastClass.create(clz); 97 | fastClassMap.put(clz, fastClz); 98 | } 99 | return new FastMethodInvoker(fastClz.getMethod(method)); 100 | } 101 | 102 | public static class FastMethodInvoker { 103 | private final FastMethod fastMethod; 104 | 105 | public FastMethodInvoker(FastMethod fastMethod) { 106 | this.fastMethod = fastMethod; 107 | } 108 | 109 | public Object invoke(Object obj, Object... args) { 110 | try { 111 | return fastMethod.invoke(obj, args); 112 | } catch (Exception e) { 113 | Throwables.throwIfUnchecked(e); 114 | } 115 | return null; 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/util/RegexMatcher.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.util; 2 | 3 | import com.google.common.base.Strings; 4 | 5 | import java.util.regex.Pattern; 6 | 7 | /** 8 | * @Author: alex 9 | * @Description: 10 | * @Date: created in 2019/1/9. 11 | */ 12 | public abstract class RegexMatcher { 13 | private RegexMatcher() { 14 | } 15 | 16 | public static boolean match(String text, String regexPattern) { 17 | if (Strings.isNullOrEmpty(text) || Strings.isNullOrEmpty(regexPattern)) { 18 | return false; 19 | } 20 | return Pattern.matches(regexPattern, text); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/java/com/github/middleware/aggregate/util/UnsafeUtils.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.util; 2 | 3 | import sun.misc.Unsafe; 4 | 5 | /** 6 | * @Author: alex 7 | * @Description: 8 | * @Date: created in 2019/10/30 9 | */ 10 | 11 | public abstract class UnsafeUtils { 12 | final static private Unsafe _unsafe; 13 | 14 | static { 15 | Unsafe tmpUnsafe = null; 16 | 17 | try { 18 | java.lang.reflect.Field field = Unsafe.class.getDeclaredField("theUnsafe"); 19 | field.setAccessible(true); 20 | tmpUnsafe = (Unsafe) field.get(null); 21 | } catch (Exception e) { 22 | throw new Error(e); 23 | } 24 | 25 | _unsafe = tmpUnsafe; 26 | } 27 | 28 | public static final Unsafe unsafe() { 29 | return _unsafe; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/resources/META-INF/services/com.github.middleware.aggregate.context.AggregeListener: -------------------------------------------------------------------------------- 1 | com.github.middleware.aggregate.context.container.StartedAggregeListener 2 | com.github.middleware.aggregate.context.container.StopAggregeListener 3 | com.github.middleware.aggregate.context.session.InterceptorBeforeAggregeListener 4 | com.github.middleware.aggregate.context.session.DataBindBeforeAggregeListener 5 | com.github.middleware.aggregate.context.session.InterceptorAfterAggregeListener 6 | com.github.middleware.aggregate.context.session.ContractInvokeBeforeAggregeListener 7 | com.github.middleware.aggregate.context.session.ContractInvokeAfterAggregeListener 8 | com.github.middleware.aggregate.context.session.BreakDataBindAggregeEventListener -------------------------------------------------------------------------------- /data-aggregate-core/src/main/resources/META-INF/services/com.github.middleware.aggregate.core.AggregeEngine: -------------------------------------------------------------------------------- 1 | com.github.middleware.aggregate.core.support.DefaultAggregeEngine -------------------------------------------------------------------------------- /data-aggregate-core/src/main/resources/META-INF/services/com.github.middleware.aggregate.flow.ItemBinder: -------------------------------------------------------------------------------- 1 | com.github.middleware.aggregate.flow.support.ItemRequestValidateCommand 2 | com.github.middleware.aggregate.flow.support.ItemProxyArgBuildCommand 3 | com.github.middleware.aggregate.flow.support.ItemProxyFetchDataCommand 4 | com.github.middleware.aggregate.flow.support.ItemResponseCommand 5 | com.github.middleware.aggregate.flow.support.ItemsProxyArgBuildCommand 6 | com.github.middleware.aggregate.flow.support.ItemsProxyFetchDataCommand 7 | -------------------------------------------------------------------------------- /data-aggregate-core/src/main/resources/META-INF/services/com.github.middleware.aggregate.source.MetaHolderFactory: -------------------------------------------------------------------------------- 1 | com.github.middleware.aggregate.source.support.ReflectMetaHolderFactory -------------------------------------------------------------------------------- /data-aggregate-core/src/main/resources/data-aggrege-demo.yml: -------------------------------------------------------------------------------- 1 | clzMetasCacheSize: 10000 2 | responseResolverCacheSize: 1000 3 | proxyMethodCacheSize: 10000 4 | maxBlockTimeout: 30000 5 | corePoolSize: 6 6 | keepAliveTime: 500 7 | workQueueSize: 800 -------------------------------------------------------------------------------- /data-aggregate-spring-boot-starter/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | data-aggregate-parent 7 | com.github.middleware 8 | 1.0 9 | 10 | 4.0.0 11 | ${aggregate.verion} 12 | data-aggregate-spring-boot-starter 13 | data-aggregate-spring-boot-starter 14 | http://www.example.com 15 | 16 | UTF-8 17 | 1.8 18 | 1.8 19 | 1.5.3.RELEASE 20 | 21 | 22 | 23 | 24 | org.springframework.boot 25 | spring-boot-dependencies 26 | ${spring-boot.version} 27 | pom 28 | import 29 | 30 | 31 | 32 | 33 | 34 | com.github.middleware 35 | data-aggregate-spring 36 | ${aggregate.verion} 37 | 38 | 39 | org.springframework.boot 40 | spring-boot-configuration-processor 41 | true 42 | 43 | 44 | org.springframework.boot 45 | spring-boot-autoconfigure 46 | 47 | 48 | ch.qos.logback 49 | logback-classic 50 | 51 | 52 | junit 53 | junit 54 | test 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /data-aggregate-spring-boot-starter/src/main/java/com/github/middleware/aggregate/spring/boot/autoconfigure/AggregateAutoConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.spring.boot.autoconfigure; 2 | 3 | import com.github.middleware.aggregate.spring.init.DataAggregeAspect; 4 | import com.github.middleware.aggregate.spring.init.SpringContextHolder; 5 | import org.aspectj.lang.annotation.Aspect; 6 | import org.springframework.boot.autoconfigure.AutoConfigureAfter; 7 | import org.springframework.boot.autoconfigure.aop.AopAutoConfiguration; 8 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; 9 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 10 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 11 | import org.springframework.context.annotation.Bean; 12 | import org.springframework.context.annotation.Configuration; 13 | 14 | /** 15 | * @Author: alex 16 | * @Description: 17 | * @Date: created in 2019/2/13. 18 | */ 19 | @Configuration 20 | @ConditionalOnClass({EnableDataAggregate.class, Aspect.class}) 21 | @AutoConfigureAfter({AopAutoConfiguration.class}) 22 | @EnableConfigurationProperties({AggregateProperties.class}) 23 | public class AggregateAutoConfiguration { 24 | @Bean 25 | @ConditionalOnMissingBean 26 | public DataAggregeAspect aggregeAspect(AggregateProperties config) { 27 | DataAggregeAspect aggregeAspect = new DataAggregeAspect(); 28 | aggregeAspect.setConfig(config); 29 | return aggregeAspect; 30 | } 31 | 32 | @Bean 33 | @ConditionalOnMissingBean 34 | public SpringContextHolder springContextHolder() { 35 | return new SpringContextHolder(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /data-aggregate-spring-boot-starter/src/main/java/com/github/middleware/aggregate/spring/boot/autoconfigure/AggregateProperties.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.spring.boot.autoconfigure; 2 | 3 | import com.github.middleware.aggregate.config.MergeProperties; 4 | import org.springframework.boot.context.properties.ConfigurationProperties; 5 | 6 | /** 7 | * @Author: alex 8 | * @Description: 9 | * @Date: created in 2019/2/13. 10 | */ 11 | @ConfigurationProperties(prefix = "github.aggregate") 12 | public class AggregateProperties extends MergeProperties { 13 | } 14 | -------------------------------------------------------------------------------- /data-aggregate-spring-boot-starter/src/main/java/com/github/middleware/aggregate/spring/boot/autoconfigure/EnableDataAggregate.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.spring.boot.autoconfigure; 2 | 3 | import org.springframework.context.annotation.Import; 4 | 5 | import java.lang.annotation.*; 6 | 7 | /** 8 | * @Author: alex 9 | * @Description: 10 | * @Date: created in 2019/2/13. 11 | */ 12 | @Target(ElementType.TYPE) 13 | @Retention(RetentionPolicy.RUNTIME) 14 | @Documented 15 | @Import(AggregateAutoConfiguration.class) 16 | public @interface EnableDataAggregate { 17 | } 18 | -------------------------------------------------------------------------------- /data-aggregate-spring/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | data-aggregate-parent 7 | com.github.middleware 8 | 1.0 9 | 10 | 4.0.0 11 | ${aggregate.verion} 12 | data-aggregate-spring 13 | data-aggregate-spring 14 | 15 | 16 | com.github.middleware 17 | data-aggregate-core 18 | ${aggregate.verion} 19 | 20 | 21 | org.springframework 22 | spring-context 23 | 24 | 25 | org.springframework 26 | spring-aop 27 | 28 | 29 | org.springframework 30 | spring-aspects 31 | 32 | 33 | 34 | org.projectlombok 35 | lombok 36 | provided 37 | 38 | 39 | ch.qos.logback 40 | logback-classic 41 | 42 | 43 | org.javatuples 44 | javatuples 45 | 46 | 47 | org.springframework 48 | spring-test 49 | test 50 | 51 | 52 | junit 53 | junit 54 | test 55 | 56 | 57 | 58 | 59 | 60 | org.projectlombok 61 | lombok-maven-plugin 62 | 63 | 64 | com.github.middleware 65 | mock-plugin-maven 66 | 1.0-SNAPSHOT 67 | 68 | 8088 69 | src/test/resources/mock/config.json 70 | 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /data-aggregate-spring/src/main/java/com/github/middleware/aggregate/spring/init/DataAggregeAspect.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.spring.init; 2 | 3 | import com.github.middleware.aggregate.annonation.AggregeEnable; 4 | import com.github.middleware.aggregate.config.MergeProperties; 5 | import com.github.middleware.aggregate.core.AggregeEngineActivetor; 6 | import com.github.middleware.aggregate.core.RequestPayLoad; 7 | import com.github.middleware.aggregate.core.support.AggregeEngineActivetors; 8 | import com.github.middleware.aggregate.spring.util.AopUtils; 9 | import com.google.common.base.Preconditions; 10 | import com.google.common.base.Throwables; 11 | import org.aspectj.lang.ProceedingJoinPoint; 12 | import org.aspectj.lang.annotation.Around; 13 | import org.aspectj.lang.annotation.Aspect; 14 | import org.aspectj.lang.annotation.Pointcut; 15 | import org.springframework.beans.BeansException; 16 | import org.springframework.beans.factory.DisposableBean; 17 | import org.springframework.beans.factory.InitializingBean; 18 | import org.springframework.context.ApplicationContext; 19 | import org.springframework.context.ApplicationContextAware; 20 | 21 | import java.lang.reflect.Method; 22 | import java.util.Optional; 23 | 24 | /** 25 | * @Author: alex 26 | * @Description: 27 | * @Date: created in 2019/1/21. 28 | */ 29 | @Aspect 30 | public class DataAggregeAspect implements InitializingBean, DisposableBean, ApplicationContextAware { 31 | private AggregeEngineActivetor ENGINE_ACTIVETOR; 32 | private MergeProperties config; 33 | private static ApplicationContext appContext; 34 | 35 | @Pointcut("@annotation(com.github.middleware.aggregate.annonation.AggregeEnable)") 36 | public void dataAggregeAnnotationPointcut() { 37 | //todo 38 | } 39 | 40 | @Around("dataAggregeAnnotationPointcut()") 41 | public Object methodsAnnotatedWithAggerege(final ProceedingJoinPoint joinPoint) throws Throwable { 42 | Method method = AopUtils.getMethodFromTarget(joinPoint); 43 | Preconditions.checkNotNull(method, "failed to get method from joinPoint: %s", new Object[]{joinPoint}); 44 | AggregeEnable enable = method.getAnnotation(AggregeEnable.class); 45 | RequestPayLoad request = new RequestPayLoad(method, appContext, () -> { 46 | try { 47 | return joinPoint.proceed(); 48 | } catch (Throwable throwable) { 49 | Throwables.throwIfUnchecked(throwable); 50 | return null; 51 | } 52 | },enable); 53 | return ENGINE_ACTIVETOR.intercept(request); 54 | } 55 | 56 | @Override 57 | public void afterPropertiesSet() throws Exception { 58 | ENGINE_ACTIVETOR = AggregeEngineActivetors.getEngineAcitvetor(); 59 | Optional.ofNullable(config).ifPresent(x -> ENGINE_ACTIVETOR.getAggregeEngine().loadConfig(config)); 60 | ENGINE_ACTIVETOR.getAggregeEngine().start(); 61 | } 62 | 63 | @Override 64 | public void destroy() throws Exception { 65 | ENGINE_ACTIVETOR.getAggregeEngine().stop(); 66 | } 67 | 68 | public void setConfig(MergeProperties config) { 69 | this.config = config; 70 | } 71 | 72 | public AggregeEngineActivetor getEngineActivetor() { 73 | return ENGINE_ACTIVETOR; 74 | } 75 | 76 | @Override 77 | public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 78 | appContext = applicationContext; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /data-aggregate-spring/src/main/java/com/github/middleware/aggregate/spring/init/SpringContextHolder.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.spring.init; 2 | 3 | import com.google.common.base.Strings; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.springframework.beans.BeansException; 7 | import org.springframework.context.ApplicationContext; 8 | import org.springframework.context.ApplicationContextAware; 9 | 10 | import java.util.Optional; 11 | 12 | /** 13 | * @Author: alex 14 | * @Description: 15 | * @Date: created in 2019/1/21. 16 | */ 17 | public class SpringContextHolder implements ApplicationContextAware { 18 | private static final Logger LOGGER = LoggerFactory.getLogger(SpringContextHolder.class); 19 | private static ApplicationContext appContext; 20 | 21 | public static final T getBean(Class requireType) { 22 | return appContext.getBean(requireType); 23 | } 24 | 25 | public static Optional getBean(ApplicationContext applicationContext, String beanName) { 26 | if (appContext == null) { 27 | appContext = applicationContext; 28 | } 29 | return getBean(beanName); 30 | } 31 | 32 | public static Optional getBean(String beanName) { 33 | if (Strings.isNullOrEmpty(beanName) || appContext == null) { 34 | return Optional.empty(); 35 | } 36 | try { 37 | Object var1 = appContext.getBean(beanName); 38 | return (Optional) Optional.ofNullable(var1); 39 | } catch (Exception var3) { 40 | LOGGER.error("获取spring bean[" + beanName + "]错误:" + var3.getMessage(), var3); 41 | return Optional.empty(); 42 | } 43 | } 44 | 45 | @Override 46 | public void setApplicationContext(ApplicationContext applicationContext) { 47 | appContext = applicationContext; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /data-aggregate-spring/src/main/java/com/github/middleware/aggregate/spring/remote/SpringContractBeanEndpoint.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.spring.remote; 2 | 3 | import com.github.middleware.aggregate.core.AggregeException; 4 | import com.github.middleware.aggregate.spring.init.SpringContextHolder; 5 | import com.github.middleware.aggregate.contract.ServiceConsumerEndpoint; 6 | import org.springframework.context.ApplicationContext; 7 | import org.springframework.util.Assert; 8 | 9 | /** 10 | * @Author: alex 11 | * @Description: 12 | * @Date: created in 2019/1/9. 13 | */ 14 | public class SpringContractBeanEndpoint implements ServiceConsumerEndpoint { 15 | private ApplicationContext applicationContext; 16 | 17 | @Override 18 | public Object getServiceBean(String beanName, Object ioc) { 19 | Assert.notNull(ioc, "未找到对应的applicationContext."); 20 | if (applicationContext == null) { 21 | applicationContext = (ApplicationContext) ioc; 22 | } 23 | return SpringContextHolder.getBean(applicationContext, beanName).orElseThrow(() -> new AggregeException("找不到ID为[" + beanName + "]的spring bean实现!")); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /data-aggregate-spring/src/main/java/com/github/middleware/aggregate/spring/util/AopUtils.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.spring.util; 2 | 3 | import com.github.middleware.aggregate.core.AggregeException; 4 | import org.aspectj.lang.JoinPoint; 5 | import org.aspectj.lang.reflect.MethodSignature; 6 | import org.springframework.util.ReflectionUtils; 7 | 8 | import java.lang.reflect.Method; 9 | 10 | /** 11 | * @Author: alex 12 | * @Description: 13 | * @Date: created in 2019/1/23. 14 | */ 15 | public class AopUtils { 16 | private AopUtils() { 17 | } 18 | 19 | public static Method getMethodFromTarget(JoinPoint joinPoint) { 20 | Method method = null; 21 | if (joinPoint.getSignature() instanceof MethodSignature) { 22 | MethodSignature signature = (MethodSignature) joinPoint.getSignature(); 23 | method = getDeclaredMethod(joinPoint.getTarget().getClass(), signature.getName(), getParameterTypes(joinPoint)); 24 | } 25 | 26 | return method; 27 | } 28 | 29 | public static Class[] getParameterTypes(JoinPoint joinPoint) { 30 | MethodSignature signature = (MethodSignature) joinPoint.getSignature(); 31 | Method method = signature.getMethod(); 32 | return method.getParameterTypes(); 33 | } 34 | 35 | public static Method getDeclaredMethod(Class targetClass, String methodName, Class... parameterTypes) { 36 | Method method = null; 37 | try { 38 | method = ReflectionUtils.findMethod(targetClass, methodName, parameterTypes); 39 | } catch (Exception ex) { 40 | throw new AggregeException(ex); 41 | } 42 | return method; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /data-aggregate-spring/src/main/resources/META-INF/services/com.github.middleware.aggregate.contract.ServiceConsumerEndpoint: -------------------------------------------------------------------------------- 1 | com.github.middleware.aggregate.spring.remote.SpringContractBeanEndpoint -------------------------------------------------------------------------------- /data-aggregate-spring/src/test/java/com/github/middleware/aggregate/QuickStart_test.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate; 2 | 3 | import com.github.middleware.aggregate.context.AggregeContext; 4 | import com.github.middleware.aggregate.core.RequestPayLoad; 5 | import com.github.middleware.aggregate.core.support.AggregeEngineActivetors; 6 | import com.github.middleware.aggregate.example.OrderService; 7 | import com.github.middleware.aggregate.example.domain.Order; 8 | import com.github.middleware.aggregate.example.domain.Order2; 9 | import com.github.middleware.aggregate.spring.init.DataAggregeAspect; 10 | import com.google.common.collect.Lists; 11 | import org.junit.Assert; 12 | import org.junit.BeforeClass; 13 | import org.junit.Test; 14 | import org.junit.runner.RunWith; 15 | import org.springframework.beans.factory.annotation.Autowired; 16 | import org.springframework.context.ApplicationContext; 17 | import org.springframework.test.context.ContextConfiguration; 18 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 19 | 20 | import java.lang.reflect.Method; 21 | import java.util.List; 22 | 23 | /** 24 | * @Author: alex 25 | * @Description: 26 | * @Date: created in 2019/1/18. 27 | */ 28 | @RunWith(SpringJUnit4ClassRunner.class) 29 | @ContextConfiguration(locations = "classpath:spring.xml") 30 | public class QuickStart_test { 31 | @Autowired 32 | private OrderService orderService; 33 | @Autowired 34 | private DataAggregeAspect aggregeAspect; 35 | @Autowired 36 | private ApplicationContext applicationContext; 37 | 38 | @BeforeClass 39 | public static void init() { 40 | System.setProperty("aggregate.isFast", "true"); 41 | } 42 | 43 | /** 44 | * 手动的方式调用 45 | * 很多时候,我们并不需要AOP的模式运行的,提供工具模式 46 | */ 47 | @Test() 48 | public void manualFire() { 49 | Order order = new Order(1); 50 | order.setProductIds(Lists.newArrayList(1)); 51 | order.setOrderSourceType(1); 52 | RequestPayLoad request = new RequestPayLoad("manualFire", applicationContext, order, true); 53 | AggregeEngineActivetors.getEngineAcitvetorStateful().intercept(request); 54 | System.out.println(order); 55 | } 56 | 57 | /** 58 | * 单VO同步 59 | */ 60 | @Test 61 | public void getOrder() { 62 | Order order = orderService.getOrder(1); 63 | Assert.assertNotNull(order); 64 | System.out.printf("result:%s", order); 65 | } 66 | 67 | /** 68 | * 单VO并发 69 | */ 70 | @Test 71 | public void getOrderAsync() { 72 | Order order = orderService.getOrder2(1); 73 | Assert.assertNotNull(order); 74 | System.out.printf("result:%s", order); 75 | } 76 | 77 | /** 78 | * List并发,不开启(批量)优化 79 | */ 80 | @Test 81 | public void getOrders() { 82 | List orders = orderService.getOrders(); 83 | Assert.assertNotNull(orders); 84 | System.out.printf("result:%s", orders); 85 | } 86 | 87 | /** 88 | * 批量聚合填充 89 | */ 90 | @Test 91 | public void getOrders2() { 92 | List orders = orderService.getOrders1(); 93 | Assert.assertNotNull(orders); 94 | System.out.printf("result:%s", orders); 95 | } 96 | 97 | /** 98 | * 单VO和批量同上注解存在,兼容性 99 | */ 100 | @Test 101 | public void getOrder22() { 102 | Order2 orders = orderService.getOrder22(); 103 | Assert.assertNotNull(orders); 104 | System.out.printf("result:%s", orders); 105 | } 106 | 107 | /** 108 | * 批量聚合填充,,不开启优化 109 | */ 110 | @Test 111 | public void getOrders3() { 112 | List orders = orderService.getOrders3(); 113 | Assert.assertNotNull(orders); 114 | System.out.printf("result:%s", orders); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /data-aggregate-spring/src/test/java/com/github/middleware/aggregate/example/AddressRepository.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.example; 2 | 3 | import com.github.middleware.aggregate.example.domain.Address; 4 | import org.springframework.stereotype.Service; 5 | 6 | import java.util.List; 7 | import java.util.stream.Collectors; 8 | 9 | /** 10 | * @Author: alex 11 | * @Description: 这是一个数据持久化服务 12 | * @Date: created in 2019/1/23. 13 | */ 14 | @Service("addressRepository") 15 | public class AddressRepository { 16 | 17 | public Address getAddressById(Integer id) { 18 | if (id == null) { 19 | return null; 20 | } 21 | return new Address(id); 22 | } 23 | 24 | public List
getAddressByIds(List ids) { 25 | return ids.stream().map(x -> new Address(x)).collect(Collectors.toList()); 26 | } 27 | 28 | public Address getAddressById2(List
addresses, Integer id) { 29 | if (addresses == null || addresses.isEmpty()) return null; 30 | return addresses.stream().filter(x -> x.getAddressId() == id).findFirst().get(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /data-aggregate-spring/src/test/java/com/github/middleware/aggregate/example/AddressResponseResolver.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.example; 2 | 3 | import com.github.middleware.aggregate.contract.ResponseResolver; 4 | import com.github.middleware.aggregate.example.domain.Address; 5 | 6 | /** 7 | * @Author: alex 8 | * @Description: 9 | * @Date: created in 2019/2/15. 10 | */ 11 | public class AddressResponseResolver implements ResponseResolver { 12 | @Override 13 | public Object resolve(Object response) { 14 | if (response == null) return response; 15 | if (response instanceof Address) { 16 | Address address = (Address) response; 17 | address.setPhone("15201829272"); 18 | } 19 | return response; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /data-aggregate-spring/src/test/java/com/github/middleware/aggregate/example/GlobalDictionaryCode.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.example; 2 | 3 | import com.google.common.base.Strings; 4 | import com.google.common.collect.HashBasedTable; 5 | import com.google.common.collect.Table; 6 | 7 | /** 8 | * @Author: alex 9 | * @Description: 10 | * @Date: created in 2019/1/23. 11 | */ 12 | public class GlobalDictionaryCode { 13 | private static Table dictionary = HashBasedTable.create(); 14 | 15 | public GlobalDictionaryCode() { 16 | dictionary.put("orderSource", "1", "淘宝"); 17 | dictionary.put("orderSource", "2", "京东"); 18 | 19 | dictionary.put("sex", "1", "男"); 20 | dictionary.put("sex", "2", "女"); 21 | } 22 | 23 | public String getDictValue(String dictSource, Object dictType) { 24 | if (Strings.isNullOrEmpty(dictSource) || dictType == null) { 25 | return "未知"; 26 | } 27 | return dictionary.get(dictSource, dictType.toString()); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /data-aggregate-spring/src/test/java/com/github/middleware/aggregate/example/OrderService.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.example; 2 | 3 | import com.github.middleware.aggregate.context.AggregeContext; 4 | import com.google.common.collect.Lists; 5 | import com.github.middleware.aggregate.annonation.AggregeEnable; 6 | import com.github.middleware.aggregate.example.domain.Order; 7 | import com.github.middleware.aggregate.example.domain.Order2; 8 | import org.springframework.stereotype.Service; 9 | 10 | import java.util.List; 11 | 12 | /** 13 | * @Author: alex 14 | * @Description: 15 | * @Date: created in 2019/1/23. 16 | */ 17 | @Service 18 | public class OrderService { 19 | 20 | @AggregeEnable 21 | public Order getOrder(int id) { 22 | Order order = new Order(id); 23 | order.setProductIds(Lists.newArrayList(1)); 24 | order.setOrderSourceType(1); 25 | AggregeContext.getContext().setAttachment("addressId", 2); 26 | return order; 27 | } 28 | 29 | @AggregeEnable(parallel = true) 30 | public Order getOrder2(int id) { 31 | Order order = new Order(id); 32 | AggregeContext.getContext().setAttachment("addressId", 2); 33 | order.setOrderSourceType(1); 34 | return order; 35 | } 36 | 37 | @AggregeEnable(parallel = true) 38 | public List getOrders() { 39 | Order order = new Order(2); 40 | AggregeContext.getContext().setAttachment("addressId", 2); 41 | order.setOrderSourceType(1); 42 | Order order2 = new Order(3); 43 | order2.setOrderSourceType(2); 44 | return Lists.newArrayList(order, order2); 45 | } 46 | 47 | @AggregeEnable 48 | public List getOrders1() { 49 | Order2 order = new Order2(2); 50 | order.setAddressId(3); 51 | // order.setProductIds(Lists.newArrayList(7,8)); 52 | Order2 order2 = new Order2(3); 53 | order2.setAddressId(5); 54 | // order2.setProductIds(Lists.newArrayList(12,32)); 55 | return Lists.newArrayList(order, order2); 56 | } 57 | 58 | @AggregeEnable 59 | public Order2 getOrder22() { 60 | Order2 order = new Order2(2); 61 | order.setAddressId(3); 62 | order.setProductIds(Lists.newArrayList(12, 32)); 63 | return order; 64 | } 65 | 66 | @AggregeEnable(parallel = true) 67 | public List getOrders3() { 68 | Order2 order = new Order2(2); 69 | order.setAddressId(3); 70 | Order2 order2 = new Order2(3); 71 | order2.setAddressId(5); 72 | return Lists.newArrayList(order, order2); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /data-aggregate-spring/src/test/java/com/github/middleware/aggregate/example/ProductService.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.example; 2 | 3 | import com.github.middleware.aggregate.example.domain.Product; 4 | import org.springframework.stereotype.Service; 5 | 6 | import java.util.List; 7 | import java.util.stream.Collectors; 8 | 9 | /** 10 | * @Author: alex 11 | * @Description: 这是产品服务 12 | * @Date: created in 2019/1/23. 13 | */ 14 | @Service("productService") 15 | public class ProductService { 16 | 17 | public List listByIds(List productIds) throws InterruptedException { 18 | if (productIds == null) { 19 | return null; 20 | } 21 | // Thread.sleep(2000); 22 | return productIds.stream().map(x -> new Product(x)).collect(Collectors.toList()); 23 | } 24 | 25 | public List listByIds2(List products, List productIds) { 26 | return products.stream().filter(x -> productIds.contains(x.getProductId())).collect(Collectors.toList()); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /data-aggregate-spring/src/test/java/com/github/middleware/aggregate/example/domain/Address.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.example.domain; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | import lombok.ToString; 6 | 7 | /** 8 | * @Author: alex 9 | * @Description: 10 | * @Date: created in 2019/1/23. 11 | */ 12 | @ToString 13 | @Getter 14 | @Setter 15 | public class Address { 16 | private Integer addressId; 17 | private String consigneeName; 18 | private String phone; 19 | private String addressDetail; 20 | 21 | public Address(Integer addressId) { 22 | this.addressId = addressId; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /data-aggregate-spring/src/test/java/com/github/middleware/aggregate/example/domain/Order.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.example.domain; 2 | 3 | import com.github.middleware.aggregate.example.AddressResponseResolver; 4 | import com.github.middleware.aggregate.annonation.AggregeField; 5 | import com.github.middleware.aggregate.annonation.AggregeProxy; 6 | import com.github.middleware.aggregate.annonation.AggregeProxyArg; 7 | import com.github.middleware.aggregate.constant.ArgGetMode; 8 | import lombok.Getter; 9 | import lombok.Setter; 10 | import lombok.ToString; 11 | 12 | import java.util.List; 13 | 14 | /** 15 | * @Author: alex 16 | * @Description: 17 | * @Date: created in 2019/1/23. 18 | */ 19 | @ToString 20 | @Getter 21 | @Setter 22 | public class Order { 23 | private Integer id; 24 | private String orderNo; 25 | private Integer orderSourceType; 26 | @AggregeField(proxy = @AggregeProxy(name = "com.github.middleware.aggregate.example.GlobalDictionaryCode", method = "getDictValue", params = {@AggregeProxyArg(paramValue = "orderSource"), @AggregeProxyArg(key = "orderSourceType")})) 27 | private String orderSource; 28 | private Integer addressId; 29 | @AggregeField(proxy = @AggregeProxy(name = "#addressRepository", method = "getAddressById", params = {@AggregeProxyArg(argGetMode = ArgGetMode.SESSION, key = "addressId")}, resolver = AddressResponseResolver.class)) 30 | private Address address; 31 | private List productIds; 32 | @AggregeField(proxy = @AggregeProxy(name = "#productService", method = "listByIds", params = {@AggregeProxyArg(key = "productIds", paramName = "ids")})) 33 | private List products; 34 | public Order(int id) { 35 | this.id = id; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /data-aggregate-spring/src/test/java/com/github/middleware/aggregate/example/domain/Order2.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.example.domain; 2 | 3 | import com.github.middleware.aggregate.annonation.AggregeBatchProxy; 4 | import com.github.middleware.aggregate.annonation.AggregeField; 5 | import com.github.middleware.aggregate.annonation.AggregeProxy; 6 | import com.github.middleware.aggregate.annonation.AggregeProxyArg; 7 | import com.github.middleware.aggregate.constant.ArgGetMode; 8 | import lombok.Getter; 9 | import lombok.Setter; 10 | import lombok.ToString; 11 | 12 | import java.util.List; 13 | 14 | /** 15 | * @Author: alex 16 | * @Description: 17 | * @Date: created in 2019/2/14. 18 | */ 19 | @ToString 20 | @Getter 21 | @Setter 22 | public class Order2 { 23 | private Integer id; 24 | private String orderNo; 25 | private Integer orderSourceType; 26 | private String orderSource; 27 | private Integer addressId; 28 | @AggregeField(batchProxy = @AggregeBatchProxy(list = @AggregeProxy(name = "#addressRepository", method = "getAddressByIds", params = {@AggregeProxyArg(argGetMode = ArgGetMode.ITEM, key = "addressId")}), 29 | item = @AggregeProxy(name = "#addressRepository", method = "getAddressById2", params = {@AggregeProxyArg(argGetMode = ArgGetMode.BATCH), @AggregeProxyArg(argGetMode = ArgGetMode.ITEM, key = "addressId")}))) 30 | private Address address; 31 | private List productIds; 32 | @AggregeField(proxy = @AggregeProxy(name = "#productService", method = "listByIds", params = {@AggregeProxyArg(key = "productIds", paramName = "ids")}), batchProxy = @AggregeBatchProxy( 33 | list = @AggregeProxy(name = "#productService", method = "listByIds", params = {@AggregeProxyArg(key = "productIds")}), 34 | item = @AggregeProxy(name = "#productService", method = "listByIds2", params = {@AggregeProxyArg(argGetMode = ArgGetMode.BATCH), @AggregeProxyArg(key = "productIds")}))) 35 | private List products; 36 | public Order2(int id) { 37 | this.id = id; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /data-aggregate-spring/src/test/java/com/github/middleware/aggregate/example/domain/Product.java: -------------------------------------------------------------------------------- 1 | package com.github.middleware.aggregate.example.domain; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | import lombok.ToString; 6 | 7 | /** 8 | * @Author: alex 9 | * @Description: 10 | * @Date: created in 2019/1/23. 11 | */ 12 | @ToString 13 | @Getter 14 | @Setter 15 | public class Product { 16 | private Integer productId; 17 | private String productName; 18 | private double price; 19 | 20 | public Product(Integer productId) { 21 | this.productId = productId; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /data-aggregate-spring/src/test/resources/data-aggrege.yml: -------------------------------------------------------------------------------- 1 | clzMetasCacheSize: 10000 2 | responseResolverCacheSize: 1000 3 | proxyMethodCacheSize: 10000 4 | maxBlockTimeout: 30000 5 | corePoolSize: 6 6 | keepAliveTime: 500 7 | workQueueSize: 800 -------------------------------------------------------------------------------- /data-aggregate-spring/src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 |     2 |       3 |           4 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36}:%L - %msg%n  5 | 6 | 7 |        8 |   9 | 10 | -------------------------------------------------------------------------------- /data-aggregate-spring/src/test/resources/mock/config.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "request": { 4 | "uri": "/demo/user/save", 5 | "method": "post" 6 | }, 7 | "response": { 8 | "status": 200, 9 | "headers": { 10 | "content-type": "application/json" 11 | }, 12 | "json": { 13 | "errorMsg": "用户名不能为空", 14 | "suc": false 15 | } 16 | } 17 | }, 18 | { 19 | "request": { 20 | "uri": "/demo/user/query", 21 | "method": "post" 22 | }, 23 | "response": { 24 | "status": 200, 25 | "headers": { 26 | "content-type": "application/json" 27 | }, 28 | "json": { 29 | "id": 2, 30 | "name": "西城枢纽", 31 | "email": "用户@", 32 | "deliverEndTime": "1969-12-31T21:18:00Z", 33 | "deliverTime": 1, 34 | "deleteFlg": "0", 35 | "createTime": "2015-11-12T06:19:16Z", 36 | "createrId": "9319beca-d317-4a7b-9cdf-207a3cb68bef", 37 | "updateTime": "2015-11-12T06:20:23Z", 38 | "updaterId": "9319beca-d317-4a7b-9cdf-207a3cb68bef" 39 | } 40 | } 41 | } 42 | ] -------------------------------------------------------------------------------- /data-aggregate-spring/src/test/resources/spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 4.0.0 6 | 7 | com.github.middleware 8 | data-aggregate-parent 9 | pom 10 | 1.0 11 | 12 | data-aggregate-core 13 | data-aggregate-spring 14 | data-aggregate-spring-boot-starter 15 | 16 | 17 | data-aggregate-parent 18 | 19 | 20 | UTF-8 21 | 1.8 22 | 1.8 23 | 1.1.0 24 | 25 | 26 | 27 | 28 | 29 | com.google.guava 30 | guava 31 | 23.0 32 | 33 | 34 | org.yaml 35 | snakeyaml 36 | 1.21 37 | 38 | 39 | org.springframework 40 | spring-core 41 | 4.3.9.RELEASE 42 | 43 | 44 | org.springframework 45 | spring-context 46 | 4.3.9.RELEASE 47 | 48 | 49 | org.springframework 50 | spring-aop 51 | 4.3.9.RELEASE 52 | 53 | 54 | org.springframework 55 | spring-aspects 56 | 4.3.9.RELEASE 57 | 58 | 59 | org.slf4j 60 | slf4j-api 61 | 1.7.25 62 | 63 | 64 | ch.qos.logback 65 | logback-classic 66 | 1.0.11 67 | 68 | 69 | io.reactivex.rxjava2 70 | rxjava 71 | 2.2.0 72 | 73 | 74 | org.javatuples 75 | javatuples 76 | 1.2 77 | 78 | 79 | cglib 80 | cglib 81 | 3.2.7 82 | 83 | 84 | org.projectlombok 85 | lombok 86 | 1.16.22 87 | provided 88 | 89 | 90 | junit 91 | junit 92 | 4.12 93 | test 94 | 95 | 96 | org.springframework 97 | spring-test 98 | 4.3.9.RELEASE 99 | test 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | org.projectlombok 108 | lombok-maven-plugin 109 | 1.16.22.0 110 | 111 | 112 | 113 | 114 | 115 | 116 | snapshots 117 | http://192.168.1.180:8091/nexus/content/repositories/snapshots 118 | 119 | 120 | releases 121 | http://192.168.1.180:8091/nexus/content/repositories/releases 122 | 123 | 124 | 125 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # 数据聚合组件 2 | 3 | 标签(空格分隔): 服务化 代码重构 数据聚合 4 | 5 | [TOC] 目录 6 | 7 | --- 8 | # 项目背景 9 | 随着服务化越来越多,单个VO或BO属性拆分之痛已成为业务系统日益突出的问题。大量重复的代码逻辑都是用来处理依赖(查询方面的数据聚合操作),而通讯方式通常都是rest-http。 10 | 11 | # 功能特性 12 | - [x] 多数据源支持:springBean和普通类(理论上包含http-eureka、esb) 13 | - [x] 后置填充(目标方法执行后介入) 14 | - [x] 单VO及List支持 15 | - [x] 并发填充支持 16 | - [x] List开启性能优化 17 | - [x] 接入方的参数传递支持Item模式(VO提供的Field)和Session模式(目标方法中提供) 18 | - [x] 解决强弱依赖问题,弱依赖(如果请求服务发生错误,忽略错误,不进行结果集填充)强依赖(任何一属性填充失败快速失败) 19 | - [x] 自动转化及手动转换; 20 | - [x] 本地缓存支持(有限的缓存),未缓存目标方法的业务数据 21 | 22 | ## 约束 23 | 1.多个数据项同时依赖一个服务的数据,为了性能,建议将这几个数据项封装为一个新的VO,避免多次填充 24 | 2.它不是一个服务编排,而是数据依赖解析服务 25 | 26 | ## 尚且未支持 27 | 1.数据填充目前仅支持一层依赖结构(比如:Order中属性Product,Product中也有@AggregateField注解,它不会对Product再做填充处理) 28 | 2.表达式支持 29 | 30 | # 使用说明 31 | ## 聚合标志说明 32 | ```java 33 | public @interface AggregeEnable { 34 | /** 35 | * 开启并行填充 36 | * 37 | * @return 38 | */ 39 | boolean parallel() default false; 40 | } 41 | public @interface AggregeField { 42 | /** 43 | * 远程或本地服务,服务于单VO 44 | * 45 | * @return 46 | */ 47 | AggregeProxy proxy() default @AggregeProxy(enable = false); 48 | 49 | /** 50 | * 开启性能优化(批量问题),执行顺序是batchProxy->proxy 51 | * 52 | * @return 53 | */ 54 | AggregeBatchProxy batchProxy() default @AggregeBatchProxy; 55 | 56 | /** 57 | * 是否忽略错误 58 | * 59 | * @return 60 | */ 61 | boolean ignoreError() default false; 62 | } 63 | public @interface AggregeProxy { 64 | /** 65 | * 是否启用 66 | * 67 | * @return 68 | */ 69 | boolean enable() default true; 70 | 71 | /** 72 | * 目标服务名 73 | * 名称以#开头,代表从当前IOC中获取,否则类全名,如下: 74 | * #omsProductServcie 75 | * com.github.oms.contract.ProductServcie 76 | * 77 | * @return 78 | */ 79 | String name() default ""; 80 | 81 | /** 82 | * 调用方法 83 | * 84 | * @return 85 | */ 86 | String method() default ""; 87 | 88 | /** 89 | * 查询值 90 | * 91 | * @return 92 | */ 93 | AggregeProxyArg[] params() default {}; 94 | 95 | /** 96 | * 是否缓存 97 | * 98 | * @return 99 | */ 100 | @Deprecated 101 | boolean cache() default false; 102 | 103 | /** 104 | * @return 105 | */ 106 | Class resolver() default NothingResponseResolver.class; 107 | } 108 | public @interface AggregeProxyArg { 109 | /** 110 | * 参数获取模式 111 | * 112 | * @return 113 | */ 114 | ArgGetMode argGetMode() default ArgGetMode.item; 115 | 116 | /** 117 | * contract的参数名 118 | * 119 | * @return 120 | */ 121 | @Deprecated 122 | String paramName() default ""; 123 | 124 | /** 125 | * @return 126 | */ 127 | String paramValue() default ""; 128 | 129 | /** 130 | * 为vo的属性名或session中的key 131 | * 132 | * @return 133 | */ 134 | String key() default ""; 135 | } 136 | public @interface AggregeBatchProxy { 137 | /** 138 | * @return 139 | */ 140 | AggregeProxy list() default @AggregeProxy(enable = false); 141 | 142 | /** 143 | * 144 | * @return 145 | */ 146 | AggregeProxy item() default @AggregeProxy(enable = false); 147 | } 148 | ``` 149 | ## spring3.x环境 150 | ```xml 151 | 152 | com.github.middleware 153 | data-aggregate-spring 154 | 1.0.0 155 | 156 | ``` 157 | 更多示例,请参考[快速开始](data-aggregate-spring/src/test/java/com/github/middleware/aggregate/QuickStart_test.java) 158 | ```java 159 | @ToString 160 | @Getter 161 | @Setter 162 | public class Order { 163 | private Integer id; 164 | private String orderNo; 165 | private Integer orderSourceType; 166 | @AggregeField(proxy = @AggregeProxy(name = "com.github.middleware.aggregate.example.GlobalDictionaryCode", method = "getDictValue", params = {@AggregeProxyArg(paramValue = "orderSource"), @AggregeProxyArg(key = "orderSourceType")})) 167 | private String orderSource; 168 | private Integer addressId; 169 | @AggregeField(batchProxy = @AggregeBatchProxy(list = @AggregeProxy(name = "#addressRepository", method = "getAddressByIds", params = {@AggregeProxyArg(argGetMode = ArgGetMode.item, key = "addressId")}), 170 | item = @AggregeProxy(name = "#addressRepository", method = "getAddressById2", params = {@AggregeProxyArg(argGetMode = ArgGetMode.batch), @AggregeProxyArg(argGetMode = ArgGetMode.item, key = "addressId")}))) 171 | private Address address; 172 | private List productIds; 173 | @AggregeField(proxy = @AggregeProxy(name = "#productService", method = "listByIds", params = {@AggregeProxyArg(key = "productIds", paramName = "ids")}), batchProxy = @AggregeBatchProxy( 174 | list = @AggregeProxy(name = "#productService", method = "listByIds", params = {@AggregeProxyArg(key = "productIds")}), 175 | item = @AggregeProxy(name = "#productService", method = "listByIds2", params = {@AggregeProxyArg(argGetMode = ArgGetMode.batch), @AggregeProxyArg(key = "productIds")}))) 176 | private List products; 177 | 178 | public Order(int id) { 179 | this.id = id; 180 | } 181 | } 182 | @Service 183 | public class OrderService { 184 | 185 | @AggregeEnable 186 | public Order getOrder(int id) { 187 | Order order = new Order(id); 188 | order.setProductIds(Lists.newArrayList(1)); 189 | order.setOrderSourceType(1); 190 | AggregeContext.getContext().setAttachment("addressId", 2); 191 | return order; 192 | } 193 | @AggregeEnable(parallel = true) 194 | public List getOrders() { 195 | Order order = new Order(2); 196 | AggregeContext.getContext().setAttachment("addressId", 2); 197 | order.setOrderSourceType(1); 198 | Order order2 = new Order(3); 199 | order2.setOrderSourceType(2); 200 | return Lists.newArrayList(order, order2); 201 | } 202 | } 203 | ``` 204 | 配置说明: 205 | 1. data-aggrege.yml为框架配置文件 206 | 2. spring.xml 为配置加载类 207 | 208 | ## spring boot环境 209 | ### 1.Maven添加依赖 210 | ```xml 211 | 212 | com.github.middleware 213 | data-aggregate-spring-boot-starter 214 | 1.0.0 215 | 216 | ``` 217 | ### 2.启动类加注解 218 | @EnableDataAggregate 219 | ### 3.application.yml配置 220 | ```html 221 | github: 222 | aggregate: 223 | clzMetasCacheSize: 10000 224 | responseResolverCacheSize: 1000 225 | proxyMethodCacheSize: 10000 226 | maxBlockTimeout: 30000 227 | corePoolSize: 6 228 | keepAliveTime: 500 229 | workQueueSize: 800 230 | ``` 231 | --------------------------------------------------------------------------------