├── faas文档.docx ├── .gitignore ├── runtime ├── src │ ├── .DS_Store │ ├── test │ │ ├── .DS_Store │ │ ├── resources │ │ │ ├── META-INF │ │ │ │ └── services │ │ │ │ │ ├── com.tianxiao.faas.runtime.Executor │ │ │ │ │ └── com.tianxiao.faas.runtime.processor.BeanDefinitionsAfterProcessor │ │ │ └── GroovyCode1.txt │ │ └── java │ │ │ └── GroovyTest.java │ └── main │ │ ├── resources │ │ └── META-INF │ │ │ └── services │ │ │ ├── com.tianxiao.faas.runtime.Executor │ │ │ └── com.tianxiao.faas.runtime.processor.BeanDefinitionsAfterProcessor │ │ └── java │ │ └── com │ │ └── tianxiao │ │ └── faas │ │ └── runtime │ │ ├── package-info.java │ │ ├── context │ │ ├── FaaSContext.java │ │ └── FaaSContextHolder.java │ │ ├── groovy │ │ ├── GroovyASMClassLoader.java │ │ ├── GroovyClassLoaderHolder.java │ │ ├── processor │ │ │ └── PropertyBeanDefinitionsAfterProcessor.java │ │ ├── GroovyExecutor.java │ │ └── SimpleCompilerConfiguration.java │ │ ├── processor │ │ ├── manager │ │ │ ├── BeanDefinitionsProcessorManager.java │ │ │ └── ServiceLoaderBeanDefinitionsProcessorManager.java │ │ └── BeanDefinitionsAfterProcessor.java │ │ ├── annotation │ │ └── Property.java │ │ ├── FaaSBeanFactory.java │ │ ├── FaaSContainer.java │ │ ├── Executor.java │ │ ├── BeanDefinitionsProcessorManagerFactory.java │ │ ├── qlexpress │ │ └── QLExpressTest.java │ │ ├── ExecutorFactory.java │ │ └── ExecutorContext.java └── pom.xml ├── container ├── src │ └── main │ │ └── java │ │ └── com │ │ └── tianxiao │ │ └── faas │ │ └── container │ │ ├── package-info.java │ │ ├── enums │ │ └── RPCType.java │ │ ├── bean │ │ ├── UserBean.java │ │ └── DubboApplicationConfig.java │ │ ├── annotation │ │ ├── DataSourceResource.java │ │ └── DubboReference.java │ │ ├── config │ │ └── BeanConfig.java │ │ ├── processor │ │ ├── manager │ │ │ └── SpringBeanDefinitionsProcessorManager.java │ │ ├── SpringBeanDefinitionsAfterProcessor.java │ │ └── DubboReferenceBeanDefinitionsAfterProcessor.java │ │ └── invoker │ │ └── DubboServiceInvoker.java └── pom.xml ├── application ├── src │ └── main │ │ ├── java │ │ └── com │ │ │ └── tianxiao │ │ │ └── faas │ │ │ ├── application │ │ │ ├── package-info.java │ │ │ ├── config │ │ │ │ ├── FaaSRegistryConfiguration.java │ │ │ │ ├── DubboConfiguration.java │ │ │ │ └── DataSourceConfig.java │ │ │ ├── web │ │ │ │ ├── Tests.java │ │ │ │ ├── Test.java │ │ │ │ ├── FaaSController.java │ │ │ │ └── TestController.java │ │ │ ├── handler │ │ │ │ └── FaaSExecuteHandler.java │ │ │ └── runner │ │ │ │ └── FaaSPublishRefreshRunner.java │ │ │ └── FaaSApplication.java │ │ └── resources │ │ └── application-dev.properties └── pom.xml ├── common ├── src │ └── main │ │ └── java │ │ └── com │ │ └── tianxiao │ │ └── faas │ │ └── common │ │ ├── exception │ │ ├── package-info.java │ │ ├── biz │ │ │ ├── BizException.java │ │ │ └── LockedException.java │ │ ├── runtime │ │ │ ├── ExecuteException.java │ │ │ ├── SameBeanException.java │ │ │ ├── CompileException.java │ │ │ └── BeanDefinitionsAfterProcessorException.java │ │ ├── container │ │ │ └── InvokerException.java │ │ └── ParamAccessException.java │ │ ├── enums │ │ ├── ExecutorType.java │ │ ├── context │ │ │ └── Environment.java │ │ └── biz │ │ │ ├── FaaSServiceLanguageEnum.java │ │ │ └── FaaSServiceStatusEnum.java │ │ ├── constants │ │ └── ContainerConstants.java │ │ ├── util │ │ ├── ObjectUtils.java │ │ ├── ThreadPoolsFactory.java │ │ ├── IpUtils.java │ │ ├── StringUtils.java │ │ ├── NamedThreadFactory.java │ │ └── NamedThreadPools.java │ │ ├── asm │ │ ├── LoopCounter.java │ │ └── LoopCheckClassVisitor.java │ │ ├── JSONResult.java │ │ └── execute │ │ └── CodeShell.java └── pom.xml ├── biz ├── src │ └── main │ │ └── java │ │ └── com │ │ └── tianxiao │ │ └── faas │ │ └── biz │ │ ├── component │ │ └── FaaSAspectComponent.java │ │ ├── domain │ │ ├── event │ │ │ ├── DomainEvent.java │ │ │ └── PublishEvent.java │ │ ├── aggregate │ │ │ └── FaaSAggregate.java │ │ └── FaaSServiceDomain.java │ │ ├── infrastructure │ │ ├── publisher │ │ │ ├── EventPublisher.java │ │ │ └── SpringEventPublisher.java │ │ ├── handler │ │ │ └── FaaSDomainEventHandler.java │ │ └── repositories │ │ │ └── FaaSServiceRepository.java │ │ ├── aspect │ │ ├── context │ │ │ ├── FaaSAspectContext.java │ │ │ └── FaaSAspectDefaultContext.java │ │ ├── AspectOrder.java │ │ ├── system │ │ │ ├── CurrentLimitingAspect.java │ │ │ ├── CacheAspect.java │ │ │ ├── StatisticsAspect.java │ │ │ └── ContextAspect.java │ │ └── FaaSAspect.java │ │ ├── publisher │ │ ├── FaaSPublisher.java │ │ └── FaaSRedisPublisher.java │ │ ├── registry │ │ └── FaaSRegistry.java │ │ ├── factory │ │ ├── FaaSAggregateFactory.java │ │ └── FaaSServiceDomainFactory.java │ │ ├── command │ │ └── FaaSServiceSaveCommand.java │ │ └── service │ │ └── FaaSServiceCommandService.java └── pom.xml ├── api ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── tianxiao │ └── faas │ └── api │ └── param │ └── FaaSServiceSaveParam.java ├── console ├── src │ └── main │ │ ├── java │ │ └── com │ │ │ └── tianxiao │ │ │ └── faas │ │ │ ├── console │ │ │ ├── config │ │ │ │ ├── FaaSRegistryConfiguration.java │ │ │ │ ├── DubboConfiguration.java │ │ │ │ └── DataSourceConfig.java │ │ │ └── web │ │ │ │ └── FaaSServiceWriteController.java │ │ │ └── FaaSConsoleApplication.java │ │ └── resources │ │ └── application.properties └── pom.xml ├── SECURITY.md ├── sql └── sql ├── mapper ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── tianxiao │ │ └── faas │ │ └── mapper │ │ └── dao │ │ └── FaaSServiceModelMapper.java │ └── resources │ └── mybatis │ └── generatorConfig.xml ├── .github └── workflows │ └── codeql-analysis.yml ├── CODE_OF_CONDUCT.md ├── README.md └── pom.xml /faas文档.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tianxiao-zp/wuzhu-FaaS/HEAD/faas文档.docx -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # IDEA files 2 | *.idea 3 | *.iml 4 | 5 | # java class files 6 | target/ 7 | -------------------------------------------------------------------------------- /runtime/src/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tianxiao-zp/wuzhu-FaaS/HEAD/runtime/src/.DS_Store -------------------------------------------------------------------------------- /container/src/main/java/com/tianxiao/faas/container/package-info.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.container; -------------------------------------------------------------------------------- /application/src/main/java/com/tianxiao/faas/application/package-info.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.application; -------------------------------------------------------------------------------- /runtime/src/test/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tianxiao-zp/wuzhu-FaaS/HEAD/runtime/src/test/.DS_Store -------------------------------------------------------------------------------- /common/src/main/java/com/tianxiao/faas/common/exception/package-info.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.common.exception; -------------------------------------------------------------------------------- /runtime/src/main/resources/META-INF/services/com.tianxiao.faas.runtime.Executor: -------------------------------------------------------------------------------- 1 | com.tianxiao.faas.runtime.groovy.GroovyExecutor -------------------------------------------------------------------------------- /runtime/src/test/resources/META-INF/services/com.tianxiao.faas.runtime.Executor: -------------------------------------------------------------------------------- 1 | com.tianxiao.faas.runtime.groovy.GroovyExecutor -------------------------------------------------------------------------------- /common/src/main/java/com/tianxiao/faas/common/enums/ExecutorType.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.common.enums; 2 | 3 | public enum ExecutorType { 4 | GROOVY; 5 | } 6 | -------------------------------------------------------------------------------- /common/src/main/java/com/tianxiao/faas/common/enums/context/Environment.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.common.enums.context; 2 | 3 | public enum Environment { 4 | ONLINE; 5 | } 6 | -------------------------------------------------------------------------------- /runtime/src/main/resources/META-INF/services/com.tianxiao.faas.runtime.processor.BeanDefinitionsAfterProcessor: -------------------------------------------------------------------------------- 1 | com.tianxiao.faas.runtime.groovy.processor.PropertyBeanDefinitionsAfterProcessor -------------------------------------------------------------------------------- /runtime/src/test/resources/META-INF/services/com.tianxiao.faas.runtime.processor.BeanDefinitionsAfterProcessor: -------------------------------------------------------------------------------- 1 | com.tianxiao.faas.runtime.groovy.processor.PropertyBeanDefinitionsAfterProcessor -------------------------------------------------------------------------------- /runtime/src/main/java/com/tianxiao/faas/runtime/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * class:package-info 3 | * desc:TODO 4 | * create time :2020/3/25 10:54 上午 5 | * author:tianxiao 6 | */ 7 | package com.tianxiao.faas.runtime; -------------------------------------------------------------------------------- /container/src/main/java/com/tianxiao/faas/container/enums/RPCType.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.container.enums; 2 | 3 | public enum RPCType { 4 | 5 | DUBBO; 6 | public static final String DUBBO_TYPE = "DUBBO"; 7 | } 8 | -------------------------------------------------------------------------------- /common/src/main/java/com/tianxiao/faas/common/constants/ContainerConstants.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.common.constants; 2 | 3 | /** 4 | * 容器层常量 5 | */ 6 | public class ContainerConstants { 7 | 8 | public static final String UNDER_LINE = "_"; 9 | } 10 | -------------------------------------------------------------------------------- /runtime/src/test/resources/GroovyCode1.txt: -------------------------------------------------------------------------------- 1 | 2 | import com.tianxiao.faas.container.bean.UserBean; 3 | public class Test { 4 | 5 | private UserBean userBean; 6 | 7 | public Object test(String name) { 8 | return userBean.getUserName(name); 9 | } 10 | } -------------------------------------------------------------------------------- /biz/src/main/java/com/tianxiao/faas/biz/component/FaaSAspectComponent.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.biz.component; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | /** 6 | * 切面组件 7 | */ 8 | @Component 9 | public class FaaSAspectComponent { 10 | 11 | 12 | } 13 | -------------------------------------------------------------------------------- /biz/src/main/java/com/tianxiao/faas/biz/domain/event/DomainEvent.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.biz.domain.event; 2 | 3 | import java.io.Serializable; 4 | 5 | public class DomainEvent implements Serializable { 6 | private static final long serialVersionUID = 8542535898456393163L; 7 | } 8 | -------------------------------------------------------------------------------- /biz/src/main/java/com/tianxiao/faas/biz/infrastructure/publisher/EventPublisher.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.biz.infrastructure.publisher; 2 | 3 | 4 | import com.tianxiao.faas.biz.domain.event.DomainEvent; 5 | 6 | public interface EventPublisher { 7 | 8 | void publishEvent(DomainEvent domainEvent); 9 | } 10 | -------------------------------------------------------------------------------- /runtime/src/main/java/com/tianxiao/faas/runtime/context/FaaSContext.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.runtime.context; 2 | 3 | import com.tianxiao.faas.common.enums.context.Environment; 4 | 5 | public interface FaaSContext { 6 | 7 | /** 8 | * 获取环境变量 9 | * @return 10 | */ 11 | Environment getEnv(); 12 | } 13 | -------------------------------------------------------------------------------- /container/src/main/java/com/tianxiao/faas/container/bean/UserBean.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.container.bean; 2 | 3 | import org.springframework.stereotype.Service; 4 | 5 | /** 6 | * 测试的bean 7 | */ 8 | @Service 9 | public class UserBean { 10 | 11 | public String getUserName(String name) { 12 | return name; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /runtime/src/main/java/com/tianxiao/faas/runtime/groovy/GroovyASMClassLoader.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.runtime.groovy; 2 | 3 | import groovy.lang.GroovyClassLoader; 4 | 5 | public class GroovyASMClassLoader extends GroovyClassLoader { 6 | 7 | public GroovyASMClassLoader() { 8 | super(Thread.currentThread().getContextClassLoader(), new SimpleCompilerConfiguration()); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /runtime/src/main/java/com/tianxiao/faas/runtime/processor/manager/BeanDefinitionsProcessorManager.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.runtime.processor.manager; 2 | 3 | import com.tianxiao.faas.runtime.processor.BeanDefinitionsAfterProcessor; 4 | 5 | import java.util.List; 6 | 7 | public interface BeanDefinitionsProcessorManager { 8 | List getAfterProcessors(); 9 | } 10 | -------------------------------------------------------------------------------- /common/src/main/java/com/tianxiao/faas/common/util/ObjectUtils.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.common.util; 2 | 3 | import com.tianxiao.faas.common.exception.ParamAccessException; 4 | 5 | public class ObjectUtils { 6 | 7 | public static void checkNull(Object obj, String errorMsg) { 8 | if (obj == null) { 9 | throw new ParamAccessException(errorMsg); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /runtime/src/main/java/com/tianxiao/faas/runtime/processor/BeanDefinitionsAfterProcessor.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.runtime.processor; 2 | 3 | import com.tianxiao.faas.common.exception.runtime.BeanDefinitionsAfterProcessorException; 4 | 5 | public interface BeanDefinitionsAfterProcessor { 6 | 7 | void process(Object object) throws BeanDefinitionsAfterProcessorException; 8 | 9 | int order(); 10 | } 11 | -------------------------------------------------------------------------------- /runtime/src/main/java/com/tianxiao/faas/runtime/annotation/Property.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.runtime.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target({ElementType.FIELD}) 10 | public @interface Property { 11 | String value() default ""; 12 | } 13 | -------------------------------------------------------------------------------- /biz/src/main/java/com/tianxiao/faas/biz/aspect/context/FaaSAspectContext.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.biz.aspect.context; 2 | 3 | import com.tianxiao.faas.biz.domain.FaaSServiceDomain; 4 | 5 | import java.util.List; 6 | 7 | public interface FaaSAspectContext { 8 | /** 9 | * 参数名 10 | * @return 11 | */ 12 | List params(); 13 | 14 | /** 15 | * 服务 16 | * @return 17 | */ 18 | FaaSServiceDomain service(); 19 | } 20 | -------------------------------------------------------------------------------- /common/src/main/java/com/tianxiao/faas/common/util/ThreadPoolsFactory.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.common.util; 2 | 3 | import java.util.concurrent.ExecutorService; 4 | 5 | public class ThreadPoolsFactory { 6 | 7 | private static ExecutorService messageHandlerPoll = NamedThreadPools.newFixedThreadPool(NamedThreadPools.ioPoolSize(), "io-handle-thread"); 8 | 9 | public static ExecutorService getIoThreadPoll() { 10 | return messageHandlerPoll; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /biz/src/main/java/com/tianxiao/faas/biz/aspect/AspectOrder.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.biz.aspect; 2 | 3 | public interface AspectOrder { 4 | final static int MAX_ORDER = Integer.MAX_VALUE; 5 | 6 | final static int CACHE_ORDER = Integer.MAX_VALUE - 10; 7 | 8 | final static int CURRENT_LIMITING_ORDER = Integer.MAX_VALUE - 9; 9 | 10 | final static int STATISTICS_ORDER = Integer.MAX_VALUE - 8; 11 | 12 | final static int CONTEXT_ORDER = Integer.MAX_VALUE - 7; 13 | } 14 | -------------------------------------------------------------------------------- /common/src/main/java/com/tianxiao/faas/common/util/IpUtils.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.common.util; 2 | 3 | import java.net.InetAddress; 4 | import java.net.UnknownHostException; 5 | 6 | public class IpUtils { 7 | 8 | public static String getLocalHostAddress() { 9 | InetAddress addr = null; 10 | try { 11 | addr = InetAddress.getLocalHost(); 12 | } catch (UnknownHostException e) { 13 | } 14 | return addr.getHostAddress(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /biz/src/main/java/com/tianxiao/faas/biz/publisher/FaaSPublisher.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.biz.publisher; 2 | 3 | import java.util.List; 4 | 5 | // 服务的注册中心 6 | public interface FaaSPublisher { 7 | // 注册服务ip 8 | void register(String ip); 9 | 10 | // 服务下线/重启 11 | void offline(String ip); 12 | 13 | // 获取所有服务 14 | List servers(); 15 | 16 | // 发布服务 17 | void publish(String serviceName); 18 | 19 | // 根据注册中心地址及服务刷新本地脚本缓存 20 | void refreshCache(); 21 | } 22 | -------------------------------------------------------------------------------- /runtime/src/main/java/com/tianxiao/faas/runtime/context/FaaSContextHolder.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.runtime.context; 2 | 3 | public final class FaaSContextHolder { 4 | private final static ThreadLocal contexts = new ThreadLocal<>(); 5 | 6 | public static void put(FaaSContext context) { 7 | contexts.set(context); 8 | } 9 | 10 | public static void remove() { 11 | contexts.remove(); 12 | } 13 | 14 | public static FaaSContext get() { 15 | return contexts.get(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /api/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | FaaS 7 | com.tianxiao 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | api 13 | 14 | 15 | -------------------------------------------------------------------------------- /container/src/main/java/com/tianxiao/faas/container/annotation/DataSourceResource.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.container.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target({ElementType.FIELD, ElementType.METHOD}) 10 | public @interface DataSourceResource { 11 | 12 | /** 13 | * 数据库名称 14 | * @return 15 | */ 16 | String dataSource() default ""; 17 | } 18 | -------------------------------------------------------------------------------- /runtime/src/main/java/com/tianxiao/faas/runtime/FaaSBeanFactory.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.runtime; 2 | 3 | import java.util.Map; 4 | import java.util.concurrent.ConcurrentHashMap; 5 | 6 | public final class FaaSBeanFactory { 7 | 8 | private final static Map beans = new ConcurrentHashMap<>(); 9 | 10 | public static Object getBean(String beanName) { 11 | Object o = beans.get(beanName); 12 | return o; 13 | } 14 | 15 | public static void cache(String beanName, Object bean) { 16 | beans.put(beanName, bean); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /runtime/src/main/java/com/tianxiao/faas/runtime/groovy/GroovyClassLoaderHolder.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.runtime.groovy; 2 | 3 | import groovy.lang.GroovyClassLoader; 4 | 5 | /** 6 | * groovy class loader 单例持有者 7 | * 懒加载单例模式 8 | */ 9 | public class GroovyClassLoaderHolder { 10 | 11 | private GroovyClassLoaderHolder() { 12 | } 13 | 14 | public static GroovyClassLoader getInstance() { 15 | return Instance.loader; 16 | } 17 | 18 | private static class Instance { 19 | private static GroovyClassLoader loader = new GroovyASMClassLoader(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /console/src/main/java/com/tianxiao/faas/console/config/FaaSRegistryConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.console.config; 2 | 3 | import com.tianxiao.faas.biz.publisher.FaaSPublisher; 4 | import com.tianxiao.faas.biz.registry.FaaSRegistry; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | 8 | @Configuration 9 | public class FaaSRegistryConfiguration { 10 | 11 | @Bean(initMethod = "init", destroyMethod = "destroy") 12 | public FaaSRegistry registry(FaaSPublisher publisher) { 13 | return new FaaSRegistry(publisher); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /application/src/main/java/com/tianxiao/faas/application/config/FaaSRegistryConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.application.config; 2 | 3 | import com.tianxiao.faas.biz.publisher.FaaSPublisher; 4 | import com.tianxiao.faas.biz.registry.FaaSRegistry; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | 8 | @Configuration 9 | public class FaaSRegistryConfiguration { 10 | 11 | @Bean(initMethod = "init", destroyMethod = "destroy") 12 | public FaaSRegistry registry(FaaSPublisher publisher) { 13 | return new FaaSRegistry(publisher); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /biz/src/main/java/com/tianxiao/faas/biz/registry/FaaSRegistry.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.biz.registry; 2 | 3 | import com.tianxiao.faas.biz.publisher.FaaSPublisher; 4 | import com.tianxiao.faas.common.util.IpUtils; 5 | 6 | public class FaaSRegistry { 7 | private FaaSPublisher faaSPublisher; 8 | 9 | public FaaSRegistry(FaaSPublisher faaSPublisher) { 10 | this.faaSPublisher = faaSPublisher; 11 | } 12 | 13 | public void init() { 14 | faaSPublisher.register(IpUtils.getLocalHostAddress()); 15 | } 16 | 17 | public void destroy() { 18 | faaSPublisher.offline(IpUtils.getLocalHostAddress()); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /biz/src/main/java/com/tianxiao/faas/biz/infrastructure/publisher/SpringEventPublisher.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.biz.infrastructure.publisher; 2 | 3 | 4 | import com.tianxiao.faas.biz.domain.event.DomainEvent; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.context.ApplicationContext; 7 | import org.springframework.stereotype.Component; 8 | 9 | @Component 10 | public class SpringEventPublisher implements EventPublisher { 11 | @Autowired 12 | private ApplicationContext applicationContext; 13 | @Override 14 | public void publishEvent(DomainEvent domainEvent) { 15 | applicationContext.publishEvent(domainEvent); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Use this section to tell people about which versions of your project are 6 | currently being supported with security updates. 7 | 8 | | Version | Supported | 9 | | ------- | ------------------ | 10 | | 5.1.x | :white_check_mark: | 11 | | 5.0.x | :x: | 12 | | 4.0.x | :white_check_mark: | 13 | | < 4.0 | :x: | 14 | 15 | ## Reporting a Vulnerability 16 | 17 | Use this section to tell people how to report a vulnerability. 18 | 19 | Tell them where to go, how often they can expect to get an update on a 20 | reported vulnerability, what to expect if the vulnerability is accepted or 21 | declined, etc. 22 | -------------------------------------------------------------------------------- /common/src/main/java/com/tianxiao/faas/common/exception/biz/BizException.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.common.exception.biz; 2 | 3 | public class BizException extends RuntimeException { 4 | 5 | public BizException() { 6 | } 7 | 8 | public BizException(String message) { 9 | super(message); 10 | } 11 | 12 | public BizException(String message, Throwable cause) { 13 | super(message, cause); 14 | } 15 | 16 | public BizException(Throwable cause) { 17 | super(cause); 18 | } 19 | 20 | public BizException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { 21 | super(message, cause, enableSuppression, writableStackTrace); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /console/src/main/java/com/tianxiao/faas/FaaSConsoleApplication.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas; 2 | 3 | import org.springframework.boot.autoconfigure.SpringBootApplication; 4 | import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; 5 | import org.springframework.boot.builder.SpringApplicationBuilder; 6 | import org.springframework.context.ConfigurableApplicationContext; 7 | 8 | @SpringBootApplication(exclude = DataSourceAutoConfiguration.class) 9 | public class FaaSConsoleApplication { 10 | 11 | public static void main(String[] args) { 12 | ConfigurableApplicationContext ctx = new SpringApplicationBuilder(FaaSConsoleApplication.class).profiles("dev") 13 | .build(args).run(args); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /biz/src/main/java/com/tianxiao/faas/biz/aspect/system/CurrentLimitingAspect.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.biz.aspect.system; 2 | 3 | import com.tianxiao.faas.biz.aspect.AspectOrder; 4 | import com.tianxiao.faas.biz.aspect.FaaSAspect; 5 | import com.tianxiao.faas.biz.aspect.context.FaaSAspectContext; 6 | import org.springframework.stereotype.Component; 7 | 8 | /** 9 | * 限流切面 10 | * 根据 11 | * @see StatisticsAspect 12 | * 统计的性能指标数据进行限流 13 | */ 14 | @Component 15 | public class CurrentLimitingAspect implements FaaSAspect { 16 | @Override 17 | public int order() { 18 | return AspectOrder.CURRENT_LIMITING_ORDER; 19 | } 20 | 21 | @Override 22 | public AspectObject before(FaaSAspectContext context) { 23 | return null; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /application/src/main/java/com/tianxiao/faas/application/web/Tests.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.application.web; 2 | import java.util.Map; 3 | import java.util.Set; 4 | 5 | public class Tests { 6 | public String execute(Map map) { 7 | StringBuilder result = new StringBuilder(); 8 | 9 | Set strings = map.keySet(); 10 | for (String key : strings) { 11 | result.append(key + "|").append(map.get(key)).append("-"); 12 | } 13 | User user = new User(); 14 | user.sayHello(); 15 | 16 | while (true) { 17 | System.out.println(1); 18 | } 19 | 20 | } 21 | 22 | public static class User { 23 | public void sayHello() { 24 | System.out.println("hello"); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /runtime/src/main/java/com/tianxiao/faas/runtime/FaaSContainer.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.runtime; 2 | 3 | import com.tianxiao.faas.runtime.processor.manager.ServiceLoaderBeanDefinitionsProcessorManager; 4 | 5 | public class FaaSContainer { 6 | private final static FaaSContainer faasContainer = new FaaSContainer(); 7 | 8 | private FaaSContainer() {} 9 | 10 | public static FaaSContainer getInstance() { 11 | return faasContainer; 12 | } 13 | 14 | public void start() { 15 | ServiceLoaderBeanDefinitionsProcessorManager.init(); 16 | ExecutorFactory.getInstance().init(); 17 | } 18 | 19 | public void close() { 20 | ServiceLoaderBeanDefinitionsProcessorManager.destroy(); 21 | ExecutorFactory.getInstance().destroy(); 22 | } 23 | 24 | 25 | } 26 | -------------------------------------------------------------------------------- /application/src/main/java/com/tianxiao/faas/FaaSApplication.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas; 2 | 3 | import org.springframework.boot.autoconfigure.SpringBootApplication; 4 | import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; 5 | import org.springframework.boot.builder.SpringApplicationBuilder; 6 | import org.springframework.context.ConfigurableApplicationContext; 7 | import org.springframework.scheduling.annotation.EnableAsync; 8 | 9 | @SpringBootApplication(exclude = DataSourceAutoConfiguration.class) 10 | @EnableAsync 11 | public class FaaSApplication { 12 | 13 | public static void main(String[] args) { 14 | ConfigurableApplicationContext ctx = new SpringApplicationBuilder(FaaSApplication.class).profiles("dev") 15 | .build(args).run(args); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /biz/src/main/java/com/tianxiao/faas/biz/aspect/system/CacheAspect.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.biz.aspect.system; 2 | 3 | import com.tianxiao.faas.biz.aspect.AspectOrder; 4 | import com.tianxiao.faas.biz.aspect.FaaSAspect; 5 | import com.tianxiao.faas.biz.aspect.context.FaaSAspectContext; 6 | import org.springframework.stereotype.Component; 7 | 8 | /** 9 | * 缓存切面 10 | */ 11 | @Component 12 | public class CacheAspect implements FaaSAspect { 13 | @Override 14 | public int order() { 15 | return AspectOrder.CACHE_ORDER; 16 | } 17 | 18 | @Override 19 | public AspectObject before(FaaSAspectContext context) { 20 | return null; 21 | } 22 | 23 | @Override 24 | public AspectObject after(FaaSAspectContext context, Object result) { 25 | return null; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /biz/src/main/java/com/tianxiao/faas/biz/domain/event/PublishEvent.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.biz.domain.event; 2 | 3 | import com.tianxiao.faas.biz.domain.FaaSServiceDomain; 4 | 5 | public class PublishEvent extends DomainEvent { 6 | private static final long serialVersionUID = -8981012085416105475L; 7 | 8 | /** 9 | * 服务领域模型 10 | */ 11 | private FaaSServiceDomain serviceDomain; 12 | 13 | public PublishEvent(FaaSServiceDomain serviceDomain) { 14 | this.serviceDomain = serviceDomain; 15 | } 16 | 17 | public PublishEvent() { 18 | } 19 | 20 | public FaaSServiceDomain getServiceDomain() { 21 | return serviceDomain; 22 | } 23 | 24 | public void setServiceDomain(FaaSServiceDomain serviceDomain) { 25 | this.serviceDomain = serviceDomain; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /common/src/main/java/com/tianxiao/faas/common/exception/runtime/ExecuteException.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.common.exception.runtime; 2 | 3 | public class ExecuteException extends Exception { 4 | private static final long serialVersionUID = 520068454824264723L; 5 | 6 | public ExecuteException() { 7 | } 8 | 9 | public ExecuteException(String message) { 10 | super(message); 11 | } 12 | 13 | public ExecuteException(String message, Throwable cause) { 14 | super(message, cause); 15 | } 16 | 17 | public ExecuteException(Throwable cause) { 18 | super(cause); 19 | } 20 | 21 | public ExecuteException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { 22 | super(message, cause, enableSuppression, writableStackTrace); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /common/src/main/java/com/tianxiao/faas/common/exception/container/InvokerException.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.common.exception.container; 2 | 3 | public class InvokerException extends RuntimeException { 4 | private static final long serialVersionUID = -1667147854600585999L; 5 | 6 | public InvokerException() { 7 | } 8 | 9 | public InvokerException(String message) { 10 | super(message); 11 | } 12 | 13 | public InvokerException(String message, Throwable cause) { 14 | super(message, cause); 15 | } 16 | 17 | public InvokerException(Throwable cause) { 18 | super(cause); 19 | } 20 | 21 | public InvokerException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { 22 | super(message, cause, enableSuppression, writableStackTrace); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /common/src/main/java/com/tianxiao/faas/common/exception/runtime/SameBeanException.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.common.exception.runtime; 2 | 3 | public class SameBeanException extends RuntimeException { 4 | private static final long serialVersionUID = -1849875823471460894L; 5 | 6 | public SameBeanException() { 7 | } 8 | 9 | public SameBeanException(String message) { 10 | super(message); 11 | } 12 | 13 | public SameBeanException(String message, Throwable cause) { 14 | super(message, cause); 15 | } 16 | 17 | public SameBeanException(Throwable cause) { 18 | super(cause); 19 | } 20 | 21 | public SameBeanException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { 22 | super(message, cause, enableSuppression, writableStackTrace); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /common/src/main/java/com/tianxiao/faas/common/exception/runtime/CompileException.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.common.exception.runtime; 2 | 3 | /** 4 | * 编译异常 5 | */ 6 | public class CompileException extends Exception { 7 | private static final long serialVersionUID = -2773804049674140436L; 8 | 9 | public CompileException() { 10 | } 11 | 12 | public CompileException(String message) { 13 | super(message); 14 | } 15 | 16 | public CompileException(String message, Throwable cause) { 17 | super(message, cause); 18 | } 19 | 20 | public CompileException(Throwable cause) { 21 | super(cause); 22 | } 23 | 24 | public CompileException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { 25 | super(message, cause, enableSuppression, writableStackTrace); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /container/src/main/java/com/tianxiao/faas/container/annotation/DubboReference.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.container.annotation; 2 | 3 | import com.tianxiao.faas.container.enums.RPCType; 4 | import static java.lang.annotation.ElementType.FIELD; 5 | import static java.lang.annotation.ElementType.METHOD; 6 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 7 | 8 | import java.lang.annotation.Retention; 9 | import java.lang.annotation.Target; 10 | 11 | @Target({FIELD, METHOD}) 12 | @Retention(RUNTIME) 13 | public @interface DubboReference { 14 | /** 15 | * 协议名称 16 | * @return 17 | */ 18 | String protocol() default "dubbo"; 19 | 20 | String rpcType() default RPCType.DUBBO_TYPE; 21 | 22 | String interfaceName(); 23 | 24 | String group(); 25 | 26 | String version() default ""; 27 | 28 | int timeout() default 3000; 29 | } 30 | -------------------------------------------------------------------------------- /runtime/src/main/java/com/tianxiao/faas/runtime/Executor.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.runtime; 2 | 3 | import com.tianxiao.faas.common.exception.runtime.CompileException; 4 | import com.tianxiao.faas.common.exception.runtime.ExecuteException; 5 | import com.tianxiao.faas.runtime.processor.manager.BeanDefinitionsProcessorManager; 6 | 7 | /** 8 | * 代码执行器 9 | * @author tianxiao 10 | */ 11 | 12 | public interface Executor { 13 | 14 | /** 15 | * 代码编译 16 | * @param code 17 | */ 18 | Object compile(ExecutorContext executeContext) throws CompileException; 19 | 20 | /** 21 | * 代码执行 22 | * @param executeContext 23 | * @return 24 | */ 25 | Object execute(ExecutorContext executeContext) throws ExecuteException; 26 | 27 | /** 28 | * 获取执行器名称 29 | * 根据该名称 30 | * @return 31 | */ 32 | String type(); 33 | } 34 | -------------------------------------------------------------------------------- /biz/src/main/java/com/tianxiao/faas/biz/infrastructure/handler/FaaSDomainEventHandler.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.biz.infrastructure.handler; 2 | 3 | import com.tianxiao.faas.biz.domain.FaaSServiceDomain; 4 | import com.tianxiao.faas.biz.domain.event.PublishEvent; 5 | import com.tianxiao.faas.biz.publisher.FaaSPublisher; 6 | import org.springframework.stereotype.Component; 7 | import org.springframework.transaction.event.TransactionalEventListener; 8 | 9 | import javax.annotation.Resource; 10 | 11 | @Component 12 | public class FaaSDomainEventHandler { 13 | @Resource 14 | private FaaSPublisher faaSPublisher; 15 | 16 | @TransactionalEventListener 17 | public void handlePublishEvent(PublishEvent publishEvent) { 18 | FaaSServiceDomain serviceDomain = publishEvent.getServiceDomain(); 19 | faaSPublisher.publish(serviceDomain.getServiceName()); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /common/src/main/java/com/tianxiao/faas/common/exception/ParamAccessException.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.common.exception; 2 | 3 | /** 4 | * 入参异常 5 | */ 6 | public class ParamAccessException extends RuntimeException { 7 | private static final long serialVersionUID = -541917991749060377L; 8 | 9 | public ParamAccessException() { 10 | } 11 | 12 | public ParamAccessException(String message) { 13 | super(message); 14 | } 15 | 16 | public ParamAccessException(String message, Throwable cause) { 17 | super(message, cause); 18 | } 19 | 20 | public ParamAccessException(Throwable cause) { 21 | super(cause); 22 | } 23 | 24 | public ParamAccessException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { 25 | super(message, cause, enableSuppression, writableStackTrace); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /biz/src/main/java/com/tianxiao/faas/biz/aspect/context/FaaSAspectDefaultContext.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.biz.aspect.context; 2 | 3 | import com.tianxiao.faas.biz.domain.FaaSServiceDomain; 4 | 5 | import java.util.List; 6 | 7 | public class FaaSAspectDefaultContext implements FaaSAspectContext { 8 | 9 | private List params; 10 | 11 | private FaaSServiceDomain faaSServiceDomain; 12 | 13 | public FaaSAspectDefaultContext() { 14 | } 15 | 16 | public FaaSAspectDefaultContext(List params, FaaSServiceDomain faaSServiceDomain) { 17 | this.params = params; 18 | this.faaSServiceDomain = faaSServiceDomain; 19 | } 20 | 21 | @Override 22 | public List params() { 23 | return this.params; 24 | } 25 | 26 | @Override 27 | public FaaSServiceDomain service() { 28 | return this.faaSServiceDomain; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /application/src/main/resources/application-dev.properties: -------------------------------------------------------------------------------- 1 | spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver 2 | spring.datasource.url=jdbc:mysql://rdsxt5l78bid42x9ddylc832.mysql.rds.aliyuncs.com:3306/yt_reconciliation?characterEncoding=UTF-8 3 | spring.datasource.username=yangtuojia001 4 | spring.datasource.password= 5 | 6 | mybatis.typeAliasesPackage=com.tianxiao.faas.mapper.model 7 | mybatis.faas.mapper-locations=classpath:mapper/*Mapper.xml 8 | 9 | server.port=8888 10 | 11 | dubbo.app.name=faas 12 | dubbo.app.owner=tianxiao 13 | dubbo.protocol.port=28889 14 | dubbo.register.address=zookeeper://test-zk.yangtuojia.com:2184?backup=test-zk.yangtuojia.com:2185,test-zk.yangtuojia.com:2186 15 | dubbo.register.timeout=3000 16 | 17 | spring.redis.host=r-bp12fe59fd823b44.redis.rds.aliyuncs.com 18 | spring.redis.password= 19 | spring.redis.port=6379 20 | spring.redis.jedis.pool.max-active=8 21 | spring.redis.database=3 -------------------------------------------------------------------------------- /common/src/main/java/com/tianxiao/faas/common/util/StringUtils.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.common.util; 2 | 3 | public final class StringUtils { 4 | public static final String EMPTY = ""; 5 | 6 | private StringUtils() { 7 | } 8 | 9 | public static boolean isEmpty(String str) { 10 | if (str == null || EMPTY.equals(str.toLowerCase())) { 11 | return true; 12 | } 13 | return false; 14 | } 15 | 16 | public static boolean isNotEmpty(String str) { 17 | return !isEmpty(str); 18 | } 19 | 20 | /** 21 | * 首字母转小写 22 | * @param str 23 | * @return 24 | */ 25 | public static String firstCharLowerCase(String str) { 26 | if (str == null) { 27 | return null; 28 | } 29 | char[]chars = str.toCharArray(); 30 | 31 | chars[0] += 32; 32 | str = String.valueOf(chars); 33 | return str; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /console/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=8080 2 | server.env=dev 3 | 4 | spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver 5 | spring.datasource.url=jdbc:mysql://rdsxt5l78bid42x9ddylc832.mysql.rds.aliyuncs.com:3306/yt_reconciliation?characterEncoding=UTF-8 6 | spring.datasource.username=yangtuojia001 7 | spring.datasource.password= 8 | 9 | mybatis.typeAliasesPackage=com.tianxiao.faas.mapper.model 10 | mybatis.faas.mapper-locations=classpath:mapper/*Mapper.xml 11 | 12 | 13 | 14 | dubbo.app.name=faas 15 | dubbo.app.owner=tianxiao 16 | dubbo.protocol.port=28889 17 | dubbo.register.address=zookeeper://test-zk.yangtuojia.com:2184?backup=test-zk.yangtuojia.com:2185,test-zk.yangtuojia.com:2186 18 | dubbo.register.timeout=3000 19 | 20 | spring.redis.host=r-bp12fe59fd823b44.redis.rds.aliyuncs.com 21 | spring.redis.password= 22 | spring.redis.port=6379 23 | spring.redis.jedis.pool.max-active=8 24 | spring.redis.database=3 -------------------------------------------------------------------------------- /container/src/main/java/com/tianxiao/faas/container/config/BeanConfig.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.container.config; 2 | 3 | import com.tianxiao.faas.runtime.ExecutorFactory; 4 | import com.tianxiao.faas.runtime.processor.manager.BeanDefinitionsProcessorManager; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.context.annotation.DependsOn; 8 | 9 | @Configuration 10 | public class BeanConfig { 11 | 12 | @DependsOn({"springBeanDefinitionsProcessorManager"}) 13 | @Bean(initMethod = "init", destroyMethod = "destroy") 14 | public ExecutorFactory faaSContainer(BeanDefinitionsProcessorManager beanDefinitionsProcessorManager) { 15 | ExecutorFactory instance = ExecutorFactory.getInstance(); 16 | instance.setBeanDefinitionsProcessorManager(beanDefinitionsProcessorManager); 17 | return instance; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /biz/src/main/java/com/tianxiao/faas/biz/aspect/system/StatisticsAspect.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.biz.aspect.system; 2 | 3 | import com.tianxiao.faas.biz.aspect.AspectOrder; 4 | import com.tianxiao.faas.biz.aspect.FaaSAspect; 5 | import com.tianxiao.faas.biz.aspect.context.FaaSAspectContext; 6 | import org.springframework.stereotype.Component; 7 | 8 | import java.util.Map; 9 | import java.util.concurrent.ConcurrentHashMap; 10 | import java.util.concurrent.atomic.AtomicLong; 11 | 12 | /** 13 | * 数据统计切面 14 | * 用来统计接口的qps,rt等性能指标 15 | */ 16 | @Component 17 | public class StatisticsAspect implements FaaSAspect { 18 | private static final Map qps = new ConcurrentHashMap<>(); 19 | 20 | @Override 21 | public int order() { 22 | return AspectOrder.STATISTICS_ORDER; 23 | } 24 | 25 | @Override 26 | public AspectObject before(FaaSAspectContext context) { 27 | return null; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /runtime/src/main/java/com/tianxiao/faas/runtime/BeanDefinitionsProcessorManagerFactory.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.runtime; 2 | 3 | import com.tianxiao.faas.runtime.processor.manager.BeanDefinitionsProcessorManager; 4 | 5 | public final class BeanDefinitionsProcessorManagerFactory { 6 | 7 | private static final BeanDefinitionsProcessorManagerFactory factory = new BeanDefinitionsProcessorManagerFactory(); 8 | 9 | public void init(BeanDefinitionsProcessorManager beanDefinitionsProcessorManager) { 10 | this.beanDefinitionsProcessorManager = beanDefinitionsProcessorManager; 11 | } 12 | 13 | public static BeanDefinitionsProcessorManagerFactory getInstance() { 14 | return factory; 15 | } 16 | 17 | private BeanDefinitionsProcessorManager beanDefinitionsProcessorManager; 18 | 19 | public BeanDefinitionsProcessorManager getManager() { 20 | return beanDefinitionsProcessorManager; 21 | } 22 | 23 | 24 | } 25 | -------------------------------------------------------------------------------- /common/src/main/java/com/tianxiao/faas/common/exception/runtime/BeanDefinitionsAfterProcessorException.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.common.exception.runtime; 2 | 3 | public class BeanDefinitionsAfterProcessorException extends Exception { 4 | private static final long serialVersionUID = -119324811768332640L; 5 | 6 | public BeanDefinitionsAfterProcessorException() { 7 | } 8 | 9 | public BeanDefinitionsAfterProcessorException(String message) { 10 | super(message); 11 | } 12 | 13 | public BeanDefinitionsAfterProcessorException(String message, Throwable cause) { 14 | super(message, cause); 15 | } 16 | 17 | public BeanDefinitionsAfterProcessorException(Throwable cause) { 18 | super(cause); 19 | } 20 | 21 | public BeanDefinitionsAfterProcessorException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { 22 | super(message, cause, enableSuppression, writableStackTrace); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /common/src/main/java/com/tianxiao/faas/common/enums/biz/FaaSServiceLanguageEnum.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.common.enums.biz; 2 | 3 | import com.tianxiao.faas.common.enums.ExecutorType; 4 | 5 | public enum FaaSServiceLanguageEnum { 6 | JAVA(0, ExecutorType.GROOVY), 7 | GROOVY(1, ExecutorType.GROOVY); 8 | 9 | private int language; 10 | 11 | private ExecutorType executorType; 12 | 13 | FaaSServiceLanguageEnum(int language, ExecutorType executorType) { 14 | this.language = language; 15 | this.executorType = executorType; 16 | } 17 | 18 | public int getLanguage() { 19 | return language; 20 | } 21 | 22 | public ExecutorType getExecutorType() { 23 | return executorType; 24 | } 25 | 26 | public static FaaSServiceLanguageEnum get(int language) { 27 | for (FaaSServiceLanguageEnum en : values()) { 28 | if (language == en.getLanguage()) { 29 | return en; 30 | } 31 | } 32 | return null; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /sql/sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `t_services` ( 2 | `id` int(11) NOT NULL, 3 | `service_name` varchar(120) NOT NULL COMMENT '服务名', 4 | `service_desc` varchar(250) NOT NULL COMMENT '服务描述', 5 | `over_time` int(11) DEFAULT NULL COMMENT '超时时间', 6 | `max_qps` int(11) DEFAULT NULL COMMENT '最大qps', 7 | `script` text NOT NULL COMMENT '脚本内容', 8 | `language` int(11) NOT NULL DEFAULT '0' COMMENT '语言, 0 java', 9 | `creator` varchar(60) NOT NULL COMMENT '创建者', 10 | `version` int(11) NOT NULL COMMENT '版本', 11 | `status` varchar(45) NOT NULL COMMENT '状态,0 编写中 1保存 2线下发布 3 预发发布 4 线上发布 5 历史版本(不可编辑)', 12 | `cache_time` int(11) NOT NULL DEFAULT '-1' COMMENT '缓存时长', 13 | `modifier` varchar(60) NOT NULL COMMENT '修改者', 14 | `group` varchar(45) NOT NULL COMMENT '分组', 15 | `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, 16 | `edit_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 17 | `is_deleted` int(11) NOT NULL DEFAULT '0' COMMENT '是否删除 1删除 0 正常' 18 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='服务'; 19 | -------------------------------------------------------------------------------- /common/src/main/java/com/tianxiao/faas/common/exception/biz/LockedException.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.common.exception.biz; 2 | 3 | public class LockedException extends RuntimeException { 4 | private String editor; 5 | 6 | public LockedException(String message, String editor) { 7 | super(message); 8 | this.editor = editor; 9 | } 10 | 11 | public LockedException(String message, Throwable cause, String editor) { 12 | super(message, cause); 13 | this.editor = editor; 14 | } 15 | 16 | public LockedException(Throwable cause, String editor) { 17 | super(cause); 18 | this.editor = editor; 19 | } 20 | 21 | public LockedException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, String editor) { 22 | super(message, cause, enableSuppression, writableStackTrace); 23 | this.editor = editor; 24 | } 25 | 26 | public String getEditor() { 27 | return editor; 28 | } 29 | 30 | public void setEditor(String editor) { 31 | this.editor = editor; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /container/src/main/java/com/tianxiao/faas/container/processor/manager/SpringBeanDefinitionsProcessorManager.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.container.processor.manager; 2 | 3 | import com.tianxiao.faas.runtime.processor.BeanDefinitionsAfterProcessor; 4 | import com.tianxiao.faas.runtime.processor.manager.BeanDefinitionsProcessorManager; 5 | import org.springframework.stereotype.Component; 6 | 7 | import javax.annotation.Resource; 8 | import java.util.List; 9 | 10 | @Component 11 | public class SpringBeanDefinitionsProcessorManager implements BeanDefinitionsProcessorManager { 12 | @Resource 13 | private List processors; 14 | @Override 15 | public List getAfterProcessors() { 16 | if (processors == null) { 17 | return null; 18 | } 19 | processors.sort((o1, o2) -> { 20 | int i = o1.order() - o2.order(); 21 | if (i >= 0) { 22 | return -1; 23 | } else { 24 | return 1; 25 | } 26 | }); 27 | return processors; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /biz/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | FaaS 7 | com.tianxiao 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | biz 13 | 14 | 15 | 16 | com.tianxiao 17 | container 18 | 19 | 20 | com.tianxiao 21 | mapper 22 | 23 | 24 | com.tianxiao 25 | api 26 | 27 | 28 | com.tianxiao 29 | common 30 | 31 | 32 | -------------------------------------------------------------------------------- /console/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | FaaS 7 | com.tianxiao 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | console 13 | 14 | 15 | 16 | com.tianxiao 17 | biz 18 | 19 | 20 | org.springframework.boot 21 | spring-boot-starter-web 22 | 23 | 24 | 25 | 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-maven-plugin 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /application/src/main/java/com/tianxiao/faas/application/handler/FaaSExecuteHandler.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.application.handler; 2 | 3 | import com.tianxiao.faas.biz.domain.FaaSServiceDomain; 4 | import com.tianxiao.faas.biz.domain.aggregate.FaaSAggregate; 5 | import com.tianxiao.faas.biz.factory.FaaSAggregateFactory; 6 | import com.tianxiao.faas.biz.infrastructure.repositories.FaaSServiceRepository; 7 | import com.tianxiao.faas.common.enums.biz.FaaSServiceStatusEnum; 8 | import org.springframework.stereotype.Component; 9 | import reactor.core.publisher.Mono; 10 | 11 | import javax.annotation.Resource; 12 | import java.util.List; 13 | 14 | @Component 15 | public class FaaSExecuteHandler { 16 | @Resource 17 | private FaaSServiceRepository faaSServiceRepository; 18 | @Resource 19 | private FaaSAggregateFactory faaSAggregateFactory; 20 | 21 | public Mono executeByServiceName(String name, FaaSServiceStatusEnum faaSServiceStatusEnum, List params){ 22 | FaaSServiceDomain domain = faaSServiceRepository.get(name, faaSServiceStatusEnum); 23 | FaaSAggregate faaSAggregate = faaSAggregateFactory.build(domain); 24 | return Mono.justOrEmpty(faaSAggregate.execute(params)); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /runtime/src/main/java/com/tianxiao/faas/runtime/qlexpress/QLExpressTest.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.runtime.qlexpress; 2 | 3 | import com.ql.util.express.DefaultContext; 4 | import com.ql.util.express.ExpressRunner; 5 | 6 | public class QLExpressTest { 7 | 8 | public static void main(String[] args) throws Exception { 9 | ExpressRunner runner = new ExpressRunner(); 10 | DefaultContext context = new DefaultContext(); 11 | context.put("a",1); 12 | context.put("b",2); 13 | context.put("c",3); 14 | String express = "a+b*c"; 15 | Object r = runner.execute(express, context, null, true, false); 16 | System.out.println(r); 17 | 18 | 19 | runner.addOperatorWithAlias("如果", "if",null); 20 | runner.addOperatorWithAlias("则", "then",null); 21 | runner.addOperatorWithAlias("否则", "else",null); 22 | 23 | context.clear(); 24 | context.put("语文", 88); 25 | context.put("数学", 99); 26 | context.put("英语", 95); 27 | String exp = "如果 (语文+数学+英语>270) 则 {return 1;} 否则 {return 0;}"; 28 | Object execute = runner.execute(exp, context, null, false, false, null); 29 | System.out.printf(execute.toString()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /container/src/main/java/com/tianxiao/faas/container/bean/DubboApplicationConfig.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.container.bean; 2 | 3 | import org.apache.dubbo.config.ApplicationConfig; 4 | import org.apache.dubbo.config.ConfigCenterConfig; 5 | import org.apache.dubbo.config.RegistryConfig; 6 | 7 | public class DubboApplicationConfig { 8 | 9 | private ApplicationConfig applicationConfig; 10 | 11 | private RegistryConfig registryConfig; 12 | 13 | private ConfigCenterConfig configCenterConfig; 14 | 15 | public ConfigCenterConfig getConfigCenterConfig() { 16 | return configCenterConfig; 17 | } 18 | 19 | public void setConfigCenterConfig(ConfigCenterConfig configCenterConfig) { 20 | this.configCenterConfig = configCenterConfig; 21 | } 22 | 23 | public ApplicationConfig getApplicationConfig() { 24 | return applicationConfig; 25 | } 26 | 27 | public void setApplicationConfig(ApplicationConfig applicationConfig) { 28 | this.applicationConfig = applicationConfig; 29 | } 30 | 31 | public RegistryConfig getRegistryConfig() { 32 | return registryConfig; 33 | } 34 | 35 | public void setRegistryConfig(RegistryConfig registryConfig) { 36 | this.registryConfig = registryConfig; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /container/src/main/java/com/tianxiao/faas/container/invoker/DubboServiceInvoker.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.container.invoker; 2 | 3 | import com.tianxiao.faas.common.exception.container.InvokerException; 4 | import org.apache.dubbo.rpc.service.GenericService; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * dubbo接口的调用类 10 | */ 11 | public class DubboServiceInvoker { 12 | private GenericService genericService; 13 | 14 | public DubboServiceInvoker(GenericService genericService) { 15 | this.genericService = genericService; 16 | } 17 | 18 | public Object invoke(String method, List parameterTypes, List args) { 19 | try { 20 | if (genericService != null) { 21 | String[] params = null; 22 | if (parameterTypes != null) { 23 | params = new String[parameterTypes.size()]; 24 | for (int i = 0; i < parameterTypes.size(); i++) { 25 | params[i] = parameterTypes.get(i); 26 | } 27 | } 28 | return genericService.$invoke(method, params, args.toArray()); 29 | } 30 | } catch (Exception e) { 31 | throw new InvokerException(e); 32 | } 33 | return null; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /common/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | com.tianxiao 7 | FaaS 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | common 13 | 14 | 15 | 16 | org.ow2.asm 17 | asm 18 | 19 | 20 | org.slf4j 21 | slf4j-api 22 | 23 | 24 | com.google.guava 25 | guava 26 | 27 | 28 | com.alibaba 29 | fastjson 30 | 31 | 32 | org.apache.commons 33 | commons-lang3 34 | 35 | 36 | -------------------------------------------------------------------------------- /biz/src/main/java/com/tianxiao/faas/biz/factory/FaaSAggregateFactory.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.biz.factory; 2 | 3 | import com.tianxiao.faas.biz.aspect.FaaSAspect; 4 | import com.tianxiao.faas.biz.domain.FaaSServiceDomain; 5 | import com.tianxiao.faas.biz.domain.aggregate.FaaSAggregate; 6 | import com.tianxiao.faas.runtime.ExecutorFactory; 7 | import org.springframework.stereotype.Component; 8 | 9 | import javax.annotation.Resource; 10 | import java.util.List; 11 | import java.util.stream.Collectors; 12 | 13 | @Component 14 | public class FaaSAggregateFactory { 15 | @Resource 16 | private ExecutorFactory executorFactory; 17 | @Resource 18 | private List faaSAspectList; 19 | 20 | public FaaSAggregate build(FaaSServiceDomain domain) { 21 | if (domain == null) { 22 | return null; 23 | } 24 | List faaSAspects = null; 25 | if (faaSAspectList != null) { 26 | faaSAspects = faaSAspectList.stream() 27 | .sorted((o1, o2) -> o1.order() > o2.order() ? 1 : -1).collect(Collectors.toList()); 28 | } 29 | return FaaSAggregate.Builder.builder() 30 | .executorFactory(executorFactory) 31 | .faaSAspectList(faaSAspects) 32 | .faaSServiceDomain(domain) 33 | .build(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /application/src/main/java/com/tianxiao/faas/application/runner/FaaSPublishRefreshRunner.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.application.runner; 2 | 3 | import com.tianxiao.faas.biz.publisher.FaaSPublisher; 4 | 5 | import com.tianxiao.faas.common.util.NamedThreadPools; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.boot.CommandLineRunner; 9 | import org.springframework.stereotype.Component; 10 | 11 | import javax.annotation.Resource; 12 | import java.util.concurrent.ExecutorService; 13 | 14 | 15 | @Component 16 | /** 17 | * 用于刷新本地脚本编译后的缓存 18 | */ 19 | public class FaaSPublishRefreshRunner implements CommandLineRunner { 20 | private static Logger log = LoggerFactory.getLogger(FaaSPublishRefreshRunner.class); 21 | @Resource 22 | private FaaSPublisher faaSPublisher; 23 | ExecutorService kafkaListenerPoll = NamedThreadPools.newFixedThreadPool(1, "faaSPublishRefresh-thread"); 24 | 25 | @Override 26 | public void run(String... args) throws Exception { 27 | kafkaListenerPoll.submit((Runnable) () -> { 28 | while (true) { 29 | try { 30 | faaSPublisher.refreshCache(); 31 | Thread.sleep(10000L); 32 | } catch (Exception e) { 33 | log.error("refreshCache-error", e); 34 | } 35 | } 36 | }); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /application/src/main/java/com/tianxiao/faas/application/web/Test.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.application.web; 2 | 3 | import java.util.concurrent.Callable; 4 | import java.util.concurrent.ExecutionException; 5 | import java.util.concurrent.ExecutorService; 6 | import java.util.concurrent.Executors; 7 | import java.util.concurrent.Future; 8 | import java.util.concurrent.TimeUnit; 9 | import java.util.concurrent.TimeoutException; 10 | 11 | public class Test implements Callable { 12 | private int a,b; 13 | 14 | public Test(int a, int b) { 15 | this.a = a; 16 | this.b = b; 17 | } 18 | 19 | @Override 20 | public Integer call() throws Exception { 21 | Integer result = a + b; 22 | while (result > 0) { 23 | Thread.sleep(1000L); 24 | System.out.println(result); 25 | } 26 | return result; 27 | } 28 | 29 | public static void main(String[] args) throws InterruptedException, ExecutionException { 30 | ExecutorService executor = Executors.newSingleThreadExecutor(); 31 | //JDK目前为止返回的都是FutureTask的实例 32 | Future future = executor.submit(new Test(1, 2)); 33 | try { 34 | Integer result = future.get(5, TimeUnit.SECONDS);// 只有当future的状态是已完成时(future.isDone() = true),get()方法才会返回 35 | System.out.println(result); 36 | } catch (TimeoutException e) { 37 | System.out.println(e); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /application/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | FaaS 7 | com.tianxiao 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | application 13 | 14 | 15 | 16 | org.springframework.boot 17 | spring-boot-starter-web 18 | 19 | 20 | com.tianxiao 21 | biz 22 | 23 | 24 | org.springframework.boot 25 | spring-boot-starter-webflux 26 | 27 | 28 | 29 | 30 | 1.8 31 | 32 | 33 | 34 | 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-maven-plugin 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /biz/src/main/java/com/tianxiao/faas/biz/aspect/system/ContextAspect.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.biz.aspect.system; 2 | 3 | import com.tianxiao.faas.biz.aspect.AspectOrder; 4 | import com.tianxiao.faas.biz.aspect.FaaSAspect; 5 | import com.tianxiao.faas.biz.aspect.context.FaaSAspectContext; 6 | import com.tianxiao.faas.common.enums.biz.FaaSServiceStatusEnum; 7 | import com.tianxiao.faas.common.enums.context.Environment; 8 | import com.tianxiao.faas.runtime.context.FaaSContextHolder; 9 | import org.springframework.stereotype.Component; 10 | 11 | @Component 12 | public class ContextAspect implements FaaSAspect { 13 | @Override 14 | public int order() { 15 | return AspectOrder.CONTEXT_ORDER; 16 | } 17 | 18 | @Override 19 | public AspectObject before(FaaSAspectContext context) { 20 | if (context != null && context.service() != null) { 21 | if (context.service().getStatus() == FaaSServiceStatusEnum.ONLINE.getStatus()) { 22 | FaaSContextHolder.put(() -> Environment.ONLINE); 23 | } 24 | } 25 | return null; 26 | } 27 | 28 | @Override 29 | public AspectObject after(FaaSAspectContext context, Object result) { 30 | if (context != null && context.service() != null) { 31 | if (context.service().getStatus() == FaaSServiceStatusEnum.ONLINE.getStatus()) { 32 | FaaSContextHolder.remove(); 33 | } 34 | } 35 | return null; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /runtime/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | com.tianxiao 7 | FaaS 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | 13 | runtime 14 | 15 | 16 | 17 | org.codehaus.groovy 18 | groovy 19 | 20 | 21 | com.alibaba 22 | QLExpress 23 | 24 | 25 | com.tianxiao 26 | common 27 | 28 | 29 | 30 | 31 | 32 | 33 | org.apache.maven.plugins 34 | maven-compiler-plugin 35 | 3.8.1 36 | 37 | 1.8 38 | 1.8 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /runtime/src/main/java/com/tianxiao/faas/runtime/processor/manager/ServiceLoaderBeanDefinitionsProcessorManager.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.runtime.processor.manager; 2 | 3 | import com.tianxiao.faas.runtime.processor.BeanDefinitionsAfterProcessor; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Iterator; 7 | import java.util.List; 8 | import java.util.ServiceLoader; 9 | 10 | public class ServiceLoaderBeanDefinitionsProcessorManager implements BeanDefinitionsProcessorManager { 11 | private final static List processors = new ArrayList<>(); 12 | public static void init() { 13 | ServiceLoader beforeProcessors = ServiceLoader.load(BeanDefinitionsAfterProcessor.class); 14 | if (beforeProcessors != null) { 15 | Iterator iterator = beforeProcessors.iterator(); 16 | while (iterator.hasNext()) { 17 | BeanDefinitionsAfterProcessor next = iterator.next(); 18 | processors.add(next); 19 | } 20 | processors.sort((o1, o2) -> { 21 | int i = o1.order() - o2.order(); 22 | if (i >= 0) { 23 | return -1; 24 | } else { 25 | return 1; 26 | } 27 | }); 28 | } 29 | } 30 | 31 | public static void destroy() { 32 | processors.clear(); 33 | } 34 | 35 | public List getAfterProcessors() { 36 | return processors; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /common/src/main/java/com/tianxiao/faas/common/enums/biz/FaaSServiceStatusEnum.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.common.enums.biz; 2 | 3 | import com.google.common.collect.Lists; 4 | 5 | import java.util.List; 6 | 7 | public enum FaaSServiceStatusEnum { 8 | WRITING(0, "编写中"), 9 | SAVE(1, "开发环境"), 10 | OFFLINE(2, "线下发布"), 11 | PRE(3, "预发发布"), 12 | ONLINE(4, "线上发布"), 13 | HISTORY_VERSION(5, "历史版本"), 14 | ABANDON(6, "下线/废弃"); 15 | 16 | private static final List FINAL_STATUS = Lists.newArrayList(FaaSServiceStatusEnum.ONLINE, FaaSServiceStatusEnum.HISTORY_VERSION); 17 | 18 | private int status; 19 | 20 | private String desc; 21 | 22 | FaaSServiceStatusEnum(int status, String desc) { 23 | this.status = status; 24 | this.desc = desc; 25 | } 26 | 27 | public int getStatus() { 28 | return status; 29 | } 30 | 31 | public String getDesc() { 32 | return desc; 33 | } 34 | 35 | public static FaaSServiceStatusEnum get(Integer status) { 36 | if (status == null) { 37 | return null; 38 | } 39 | for (FaaSServiceStatusEnum statusEnum : values()) { 40 | if (status.equals(statusEnum.getStatus())) { 41 | return statusEnum; 42 | } 43 | } 44 | return null; 45 | } 46 | 47 | public static boolean canModified(Integer status) { 48 | FaaSServiceStatusEnum statusEnum = get(status); 49 | return !FINAL_STATUS.contains(statusEnum); 50 | } 51 | 52 | public static boolean canModified(FaaSServiceStatusEnum status) { 53 | return !FINAL_STATUS.contains(status); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /biz/src/main/java/com/tianxiao/faas/biz/aspect/FaaSAspect.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.biz.aspect; 2 | 3 | import com.tianxiao.faas.biz.aspect.context.FaaSAspectContext; 4 | 5 | /** 6 | * FaaS切面设计 7 | */ 8 | public interface FaaSAspect { 9 | 10 | /** 11 | * 顺序 12 | * @return 13 | */ 14 | int order(); 15 | 16 | /** 17 | * 前置切面 18 | * @param context 19 | * @return 20 | */ 21 | default AspectObject before(FaaSAspectContext context) { 22 | return null; 23 | }; 24 | 25 | /** 26 | * 后置切面 27 | * @param context 28 | * @return 29 | */ 30 | default AspectObject after(FaaSAspectContext context, Object result) { 31 | return null; 32 | } 33 | 34 | public static class AspectObject { 35 | private Object object; 36 | 37 | private boolean isReturn; 38 | 39 | private Throwable throwable; 40 | 41 | public AspectObject() { 42 | } 43 | 44 | public AspectObject(Object object, boolean isReturn) { 45 | this.object = object; 46 | this.isReturn = isReturn; 47 | } 48 | 49 | public Object getObject() { 50 | return object; 51 | } 52 | 53 | public void setObject(Object object) { 54 | this.object = object; 55 | } 56 | 57 | public boolean isReturn() { 58 | return isReturn; 59 | } 60 | 61 | public void setReturn(boolean aReturn) { 62 | isReturn = aReturn; 63 | } 64 | 65 | public Throwable getThrowable() { 66 | return throwable; 67 | } 68 | 69 | public void setThrowable(Throwable throwable) { 70 | this.throwable = throwable; 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /runtime/src/main/java/com/tianxiao/faas/runtime/groovy/processor/PropertyBeanDefinitionsAfterProcessor.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.runtime.groovy.processor; 2 | 3 | import com.tianxiao.faas.common.exception.runtime.BeanDefinitionsAfterProcessorException; 4 | import com.tianxiao.faas.runtime.annotation.Property; 5 | import com.tianxiao.faas.runtime.processor.BeanDefinitionsAfterProcessor; 6 | 7 | import java.lang.reflect.Field; 8 | 9 | public class PropertyBeanDefinitionsAfterProcessor implements BeanDefinitionsAfterProcessor { 10 | 11 | public void process(Object object) throws BeanDefinitionsAfterProcessorException { 12 | if (object == null) { 13 | return; 14 | } 15 | Field[] declaredFields = object.getClass().getDeclaredFields(); 16 | if (declaredFields == null || declaredFields.length <= 0) { 17 | return; 18 | } 19 | for (Field field : declaredFields) { 20 | field.setAccessible(true); 21 | Property annotation = field.getAnnotation(Property.class); 22 | if (annotation != null) { 23 | String value = annotation.value(); 24 | try { 25 | Class type = field.getType(); 26 | if (String.class.equals(type)) { 27 | field.set(object, value); 28 | } else if (int.class.equals(type)) { 29 | field.set(object, Integer.valueOf(value).intValue()); 30 | } 31 | 32 | } catch (IllegalAccessException e) { 33 | throw new BeanDefinitionsAfterProcessorException(e); 34 | } 35 | } 36 | } 37 | } 38 | 39 | public int order() { 40 | return 0; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /common/src/main/java/com/tianxiao/faas/common/asm/LoopCounter.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.common.asm; 2 | 3 | import java.util.Map; 4 | import java.util.concurrent.ConcurrentHashMap; 5 | 6 | /** 7 | * @author jianmiao.xu 8 | * @date 2020/10/17 9 | */ 10 | public class LoopCounter { 11 | 12 | private static final ThreadLocal threadLocal = new ThreadLocal<>(); 13 | 14 | // 单循环最大循环次数 15 | public static final long singleLoopMax = 1000; 16 | 17 | /** 18 | * 检测循环体执行次数,如果执行次数超出设定的阈值,则抛出异常 19 | */ 20 | public static void incr(String label) { 21 | 22 | // 判断线程执行是否被中止 23 | if (Thread.interrupted()) { 24 | throw new RuntimeException(new InterruptedException("Thread execution has been interrupted!")); 25 | } 26 | 27 | // 检查循环执行次数是否超出上限 28 | ThreadLocalCounter threadLocalCounter = threadLocal.get(); 29 | if (threadLocalCounter != null) { 30 | long incrLabel = threadLocalCounter.incrLabel(label); 31 | if (incrLabel > singleLoopMax) { 32 | throw new RuntimeException("Loop count exceed limit " + singleLoopMax); 33 | } 34 | } else { 35 | threadLocal.set(new ThreadLocalCounter()); 36 | } 37 | } 38 | 39 | // 标记类 40 | private static final class ThreadLocalCounter { 41 | 42 | // 记录每个label计数的次数 43 | private Map labelCounter = new ConcurrentHashMap<>(); 44 | 45 | // 计数器+1 46 | long incrLabel(String label) { 47 | Long counter = labelCounter.get(label); 48 | if (counter == null) { 49 | labelCounter.put(label, 1L); 50 | return 1; 51 | } 52 | labelCounter.put(label, ++counter); 53 | return counter; 54 | } 55 | 56 | // 计数器清零 57 | void clearLabel() { 58 | this.labelCounter.clear(); 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /runtime/src/main/java/com/tianxiao/faas/runtime/ExecutorFactory.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.runtime; 2 | 3 | import com.tianxiao.faas.common.enums.ExecutorType; 4 | import com.tianxiao.faas.runtime.processor.manager.ServiceLoaderBeanDefinitionsProcessorManager; 5 | import com.tianxiao.faas.runtime.processor.manager.BeanDefinitionsProcessorManager; 6 | 7 | import java.util.HashMap; 8 | import java.util.Iterator; 9 | import java.util.Map; 10 | import java.util.ServiceLoader; 11 | 12 | public class ExecutorFactory { 13 | 14 | private final static ExecutorFactory factory = new ExecutorFactory(); 15 | 16 | private BeanDefinitionsProcessorManager beanDefinitionsProcessorManager; 17 | 18 | private static final Map executorMap = new HashMap(); 19 | 20 | public static ExecutorFactory getInstance() { 21 | return factory; 22 | } 23 | 24 | public void init() { 25 | if (beanDefinitionsProcessorManager == null) { 26 | beanDefinitionsProcessorManager = new ServiceLoaderBeanDefinitionsProcessorManager(); 27 | } 28 | BeanDefinitionsProcessorManagerFactory.getInstance().init(beanDefinitionsProcessorManager); 29 | ServiceLoader load = ServiceLoader.load(Executor.class); 30 | Iterator iterator = load.iterator(); 31 | while (iterator.hasNext()) { 32 | Executor next = iterator.next(); 33 | executorMap.put(next.type(), next); 34 | } 35 | } 36 | 37 | public void setBeanDefinitionsProcessorManager(BeanDefinitionsProcessorManager beanDefinitionsProcessorManager) { 38 | this.beanDefinitionsProcessorManager = beanDefinitionsProcessorManager; 39 | } 40 | 41 | public void destroy() { 42 | executorMap.clear(); 43 | } 44 | 45 | public Executor getExecutor(ExecutorType type) { 46 | Executor executor = executorMap.get(type.name()); 47 | return executor; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /runtime/src/main/java/com/tianxiao/faas/runtime/ExecutorContext.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.runtime; 2 | 3 | import java.io.Serializable; 4 | import java.util.List; 5 | 6 | /** 7 | * 执行器上下文 8 | * @author tianxiao 9 | */ 10 | public class ExecutorContext implements Serializable { 11 | private static final long serialVersionUID = 2342150565826329476L; 12 | 13 | /** 14 | * 代码 15 | */ 16 | private String code; 17 | 18 | /** 19 | * 方法名 20 | * 可不填写 21 | */ 22 | private String methodName; 23 | 24 | /** 25 | * 方法入参 26 | */ 27 | private List params; 28 | 29 | /** 30 | * 是否是debug,即没有缓存 31 | */ 32 | private boolean debug; 33 | 34 | /** 35 | * 超时时间,毫秒级 36 | * 默认值3秒 37 | */ 38 | private long timeout; 39 | 40 | /** 41 | * 服务名称 42 | */ 43 | private String serviceName; 44 | 45 | public String getCode() { 46 | return code; 47 | } 48 | 49 | public void setCode(String code) { 50 | this.code = code; 51 | } 52 | 53 | public String getMethodName() { 54 | return methodName; 55 | } 56 | 57 | public void setMethodName(String methodName) { 58 | this.methodName = methodName; 59 | } 60 | 61 | public List getParams() { 62 | return params; 63 | } 64 | 65 | public void setParams(List params) { 66 | this.params = params; 67 | } 68 | 69 | public boolean getDebug() { 70 | return debug; 71 | } 72 | 73 | public void setDebug(boolean debug) { 74 | this.debug = debug; 75 | } 76 | 77 | public long getTimeout() { 78 | return timeout; 79 | } 80 | 81 | public void setTimeout(long timeout) { 82 | this.timeout = timeout; 83 | } 84 | 85 | public String getServiceName() { 86 | return serviceName; 87 | } 88 | 89 | public void setServiceName(String serviceName) { 90 | this.serviceName = serviceName; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /console/src/main/java/com/tianxiao/faas/console/config/DubboConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.console.config; 2 | 3 | import com.tianxiao.faas.container.bean.DubboApplicationConfig; 4 | import org.apache.dubbo.config.ApplicationConfig; 5 | import org.apache.dubbo.config.ConfigCenterConfig; 6 | import org.apache.dubbo.config.RegistryConfig; 7 | import org.springframework.beans.factory.annotation.Value; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Configuration; 10 | 11 | @Configuration 12 | public class DubboConfiguration { 13 | @Value("${dubbo.app.name}") 14 | private String appName; 15 | @Value("${dubbo.app.owner}") 16 | private String owner; 17 | @Value("${dubbo.register.address}") 18 | private String registerAddress; 19 | @Value("${dubbo.protocol.port}") 20 | private int port; 21 | @Value("${dubbo.register.timeout}") 22 | private int timeout; 23 | //@Value("${dubbo.group}") 24 | private String group; 25 | 26 | @Bean 27 | public DubboApplicationConfig dubboApplicationConfig() { 28 | DubboApplicationConfig dubboApplicationConfig = new DubboApplicationConfig(); 29 | ApplicationConfig applicationConfig = new ApplicationConfig(); 30 | applicationConfig.setName(appName); 31 | applicationConfig.setOwner(owner); 32 | dubboApplicationConfig.setApplicationConfig(applicationConfig); 33 | RegistryConfig registryConfig = new RegistryConfig(); 34 | registryConfig.setPort(port); 35 | registryConfig.setAddress(registerAddress); 36 | registryConfig.setTimeout(timeout); 37 | registryConfig.setGroup(group); 38 | dubboApplicationConfig.setRegistryConfig(registryConfig); 39 | 40 | ConfigCenterConfig configCenterConfig = new ConfigCenterConfig(); 41 | configCenterConfig.setAddress(registerAddress); 42 | configCenterConfig.setTimeout(Long.valueOf(timeout + "")); 43 | dubboApplicationConfig.setConfigCenterConfig(configCenterConfig); 44 | return dubboApplicationConfig; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /application/src/main/java/com/tianxiao/faas/application/config/DubboConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.application.config; 2 | 3 | import com.tianxiao.faas.container.bean.DubboApplicationConfig; 4 | import org.apache.dubbo.config.ApplicationConfig; 5 | import org.apache.dubbo.config.ConfigCenterConfig; 6 | import org.apache.dubbo.config.RegistryConfig; 7 | import org.springframework.beans.factory.annotation.Value; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Configuration; 10 | 11 | @Configuration 12 | public class DubboConfiguration { 13 | @Value("${dubbo.app.name}") 14 | private String appName; 15 | @Value("${dubbo.app.owner}") 16 | private String owner; 17 | @Value("${dubbo.register.address}") 18 | private String registerAddress; 19 | @Value("${dubbo.protocol.port}") 20 | private int port; 21 | @Value("${dubbo.register.timeout}") 22 | private int timeout; 23 | //@Value("${dubbo.group}") 24 | private String group; 25 | 26 | @Bean 27 | public DubboApplicationConfig dubboApplicationConfig() { 28 | DubboApplicationConfig dubboApplicationConfig = new DubboApplicationConfig(); 29 | ApplicationConfig applicationConfig = new ApplicationConfig(); 30 | applicationConfig.setName(appName); 31 | applicationConfig.setOwner(owner); 32 | dubboApplicationConfig.setApplicationConfig(applicationConfig); 33 | RegistryConfig registryConfig = new RegistryConfig(); 34 | registryConfig.setPort(port); 35 | registryConfig.setAddress(registerAddress); 36 | registryConfig.setTimeout(timeout); 37 | registryConfig.setGroup(group); 38 | dubboApplicationConfig.setRegistryConfig(registryConfig); 39 | 40 | ConfigCenterConfig configCenterConfig = new ConfigCenterConfig(); 41 | configCenterConfig.setAddress(registerAddress); 42 | configCenterConfig.setTimeout(Long.valueOf(timeout + "")); 43 | dubboApplicationConfig.setConfigCenterConfig(configCenterConfig); 44 | return dubboApplicationConfig; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /common/src/main/java/com/tianxiao/faas/common/asm/LoopCheckClassVisitor.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.common.asm; 2 | 3 | 4 | import org.objectweb.asm.ClassVisitor; 5 | import org.objectweb.asm.Label; 6 | import org.objectweb.asm.MethodVisitor; 7 | import org.objectweb.asm.Opcodes; 8 | 9 | /** 10 | * @author jianmiao.xu 11 | * @date 2020/10/17 12 | */ 13 | public class LoopCheckClassVisitor extends ClassVisitor implements Opcodes { 14 | 15 | public LoopCheckClassVisitor(ClassVisitor cv) { 16 | super(ASM5, cv); 17 | } 18 | 19 | @Override 20 | public void visit(int version, int access, String name, String signature, 21 | String superName, String[] interfaces) { 22 | cv.visit(version, access, name, signature, superName, interfaces); 23 | } 24 | 25 | @Override 26 | public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { 27 | MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions); 28 | // 跳过构造方法 29 | if (!name.equals("") && mv != null) { 30 | mv = new MyMethodVisitor(mv); 31 | } 32 | return mv; 33 | } 34 | 35 | // 针对方法增强 36 | class MyMethodVisitor extends MethodVisitor implements Opcodes { 37 | 38 | public MyMethodVisitor(MethodVisitor mv) { 39 | super(Opcodes.ASM5, mv); 40 | } 41 | 42 | @Override 43 | public void visitJumpInsn(int opcode, 44 | Label label) { 45 | if (opcode == Opcodes.GOTO && label != null) { 46 | // 在goto指令前插入计数器执行,统计循环体执行次数 47 | this.visitLdcInsn(label.toString()); 48 | this.visitMethodInsn(Opcodes.INVOKESTATIC, 49 | "com/tianxiao/faas/common/asm/LoopCounter", 50 | "incr", 51 | "(Ljava/lang/String;)V", 52 | false); 53 | } 54 | super.visitJumpInsn(opcode, label); 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /console/src/main/java/com/tianxiao/faas/console/config/DataSourceConfig.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.console.config; 2 | 3 | import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder; 4 | import org.apache.ibatis.session.SqlSessionFactory; 5 | import org.mybatis.spring.SqlSessionFactoryBean; 6 | import org.mybatis.spring.annotation.MapperScan; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.boot.context.properties.ConfigurationProperties; 9 | import org.springframework.context.annotation.Bean; 10 | import org.springframework.context.annotation.Configuration; 11 | import org.springframework.context.annotation.Primary; 12 | import org.springframework.core.env.Environment; 13 | import org.springframework.core.io.support.PathMatchingResourcePatternResolver; 14 | import org.springframework.jdbc.datasource.DataSourceTransactionManager; 15 | 16 | import javax.sql.DataSource; 17 | 18 | @Configuration 19 | @MapperScan(basePackages = {"com.tianxiao.faas.mapper.dao"}, sqlSessionFactoryRef = "sqlSessionFactory") 20 | public class DataSourceConfig { 21 | @Autowired 22 | private Environment env; 23 | 24 | @Bean(name = "dataSource") 25 | @ConfigurationProperties(prefix = "spring.datasource") 26 | public DataSource initDataSource() { 27 | return DruidDataSourceBuilder.create().build(); 28 | } 29 | 30 | @Bean(name = "transactionManager") 31 | @Primary 32 | public DataSourceTransactionManager transactionManager(DataSource dataSource) { 33 | return new DataSourceTransactionManager(dataSource); 34 | } 35 | 36 | @Bean(name = "sqlSessionFactory") 37 | @Primary 38 | public SqlSessionFactory initSqlSessionFactory(DataSource dataSource) throws Exception { 39 | final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); 40 | sessionFactory.setDataSource(dataSource); 41 | sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver() 42 | .getResources(env.getProperty("mybatis.faas.mapper-locations"))); 43 | return sessionFactory.getObject(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /application/src/main/java/com/tianxiao/faas/application/config/DataSourceConfig.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.application.config; 2 | 3 | import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder; 4 | import org.apache.ibatis.session.SqlSessionFactory; 5 | import org.mybatis.spring.SqlSessionFactoryBean; 6 | import org.mybatis.spring.annotation.MapperScan; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.boot.context.properties.ConfigurationProperties; 9 | import org.springframework.context.annotation.Bean; 10 | import org.springframework.context.annotation.Configuration; 11 | import org.springframework.context.annotation.Primary; 12 | import org.springframework.core.env.Environment; 13 | import org.springframework.core.io.support.PathMatchingResourcePatternResolver; 14 | import org.springframework.jdbc.datasource.DataSourceTransactionManager; 15 | 16 | import javax.sql.DataSource; 17 | 18 | @Configuration 19 | @MapperScan(basePackages = {"com.tianxiao.faas.mapper.dao"}, sqlSessionFactoryRef = "sqlSessionFactory") 20 | public class DataSourceConfig { 21 | @Autowired 22 | private Environment env; 23 | 24 | @Bean(name = "dataSource") 25 | @ConfigurationProperties(prefix = "spring.datasource") 26 | public DataSource initDataSource() { 27 | return DruidDataSourceBuilder.create().build(); 28 | } 29 | 30 | @Bean(name = "transactionManager") 31 | @Primary 32 | public DataSourceTransactionManager transactionManager(DataSource dataSource) { 33 | return new DataSourceTransactionManager(dataSource); 34 | } 35 | 36 | @Bean(name = "sqlSessionFactory") 37 | @Primary 38 | public SqlSessionFactory initSqlSessionFactory(DataSource dataSource) throws Exception { 39 | final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); 40 | sessionFactory.setDataSource(dataSource); 41 | String property = env.getProperty("mybatis.faas.mapper-locations"); 42 | sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver() 43 | .getResources(property)); 44 | return sessionFactory.getObject(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /common/src/main/java/com/tianxiao/faas/common/util/NamedThreadFactory.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-2020, Michael Yang 杨福海 (fuhai999@gmail.com). 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.tianxiao.faas.common.util; 17 | 18 | import java.util.concurrent.ThreadFactory; 19 | import java.util.concurrent.atomic.AtomicInteger; 20 | 21 | /** 22 | * tianxiao 23 | */ 24 | public class NamedThreadFactory implements ThreadFactory { 25 | protected static final AtomicInteger POOL_COUNTER = new AtomicInteger(1); 26 | protected final AtomicInteger mThreadCounter; 27 | protected final String mPrefix; 28 | protected final boolean mDaemon; 29 | protected final ThreadGroup mGroup; 30 | 31 | public NamedThreadFactory() { 32 | this("pool-" + POOL_COUNTER.getAndIncrement(), false); 33 | } 34 | 35 | public NamedThreadFactory(String prefix) { 36 | this(prefix, false); 37 | } 38 | 39 | public NamedThreadFactory(String prefix, boolean daemon) { 40 | this.mThreadCounter = new AtomicInteger(1); 41 | this.mPrefix = prefix + "-thread-"; 42 | this.mDaemon = daemon; 43 | SecurityManager s = System.getSecurityManager(); 44 | this.mGroup = s == null ? Thread.currentThread().getThreadGroup() : s.getThreadGroup(); 45 | } 46 | 47 | @Override 48 | public Thread newThread(Runnable runnable) { 49 | String name = this.mPrefix + this.mThreadCounter.getAndIncrement(); 50 | Thread ret = new Thread(this.mGroup, runnable, name, 0L); 51 | ret.setDaemon(this.mDaemon); 52 | return ret; 53 | } 54 | 55 | public ThreadGroup getThreadGroup() { 56 | return this.mGroup; 57 | } 58 | } -------------------------------------------------------------------------------- /container/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | com.tianxiao 7 | FaaS 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | container 13 | 14 | 15 | 16 | org.springframework 17 | spring-context 18 | 19 | 20 | com.tianxiao 21 | common 22 | 23 | 24 | com.tianxiao 25 | runtime 26 | 27 | 28 | log4j 29 | log4j 30 | 31 | 32 | 33 | 34 | org.apache.dubbo 35 | dubbo 36 | 37 | 38 | org.apache.dubbo 39 | dubbo-dependencies-zookeeper 40 | pom 41 | 42 | 43 | log4j 44 | log4j 45 | 46 | 47 | slf4j-log4j12 48 | org.slf4j 49 | 50 | 51 | 52 | 53 | org.springframework 54 | spring-jdbc 55 | 56 | 57 | com.google.guava 58 | guava 59 | 60 | 61 | -------------------------------------------------------------------------------- /mapper/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | FaaS 7 | com.tianxiao 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | mapper 13 | 14 | 15 | 16 | mysql 17 | mysql-connector-java 18 | 19 | 20 | org.springframework.boot 21 | spring-boot-starter-jdbc 22 | 23 | 24 | org.mybatis.spring.boot 25 | mybatis-spring-boot-starter 26 | 27 | 28 | com.alibaba 29 | druid-spring-boot-starter 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-starter-data-redis 34 | 35 | 36 | 37 | 38 | 39 | 40 | org.mybatis.generator 41 | mybatis-generator-maven-plugin 42 | 1.3.5 43 | 44 | 45 | mysql 46 | mysql-connector-java 47 | 8.0.28 48 | 49 | 50 | 51 | 52 | ${basedir}/src/main/resources/mybatis/generatorConfig.xml 53 | true 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /runtime/src/test/java/GroovyTest.java: -------------------------------------------------------------------------------- 1 | import com.tianxiao.faas.common.enums.ExecutorType; 2 | import com.tianxiao.faas.common.enums.context.Environment; 3 | import com.tianxiao.faas.common.exception.runtime.CompileException; 4 | import com.tianxiao.faas.common.exception.runtime.ExecuteException; 5 | import com.tianxiao.faas.runtime.Executor; 6 | import com.tianxiao.faas.runtime.ExecutorContext; 7 | import com.tianxiao.faas.runtime.ExecutorFactory; 8 | import com.tianxiao.faas.runtime.FaaSContainer; 9 | import com.tianxiao.faas.runtime.context.FaaSContext; 10 | import com.tianxiao.faas.runtime.context.FaaSContextHolder; 11 | 12 | import java.util.ArrayList; 13 | 14 | /** 15 | * class:GroovyTest 16 | * desc: 17 | * create time :2020/3/25 10:58 上午 18 | * author:tianxiao 19 | */ 20 | public class GroovyTest { 21 | public static void main(String[] args) throws ExecuteException, CompileException { 22 | String code = "import com.tianxiao.faas.runtime.annotation.Property;\n" + 23 | "\n" + 24 | "public class Test {\n" + 25 | " @Property(\"11\")" + 26 | " private int age;\n" + 27 | "\n" + 28 | " public Object test(String name) {\n" + 29 | " return \"test, my name is \" + name + \" and age is \" + age;\n" + 30 | " }\n" + 31 | "}"; 32 | // 容器初始化 33 | FaaSContainer.getInstance().start(); 34 | // 根据执行器类型获取执行器 35 | Executor executor = ExecutorFactory.getInstance().getExecutor(ExecutorType.GROOVY); 36 | // 构建执行上下文 37 | ExecutorContext executeContext = new ExecutorContext(); 38 | // 设置代码 39 | executeContext.setCode(code); 40 | // 设置调用方法 41 | executeContext.setMethodName("test"); 42 | executeContext.setServiceName("test"); 43 | // 代码编译,并初始化bean(对象) 44 | FaaSContextHolder.put(() -> Environment.ONLINE); 45 | executor.compile(executeContext); 46 | // 设置方法入参 47 | ArrayList params = new ArrayList<>(); 48 | params.add("zhang san"); 49 | executeContext.setParams(params); 50 | // 方法执行,并获取执行结果 51 | Object execute = executor.execute(executeContext); 52 | System.out.println(execute); 53 | // 容器关闭 54 | FaaSContainer.getInstance().close(); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /application/src/main/java/com/tianxiao/faas/application/web/FaaSController.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.application.web; 2 | 3 | import com.google.common.collect.Lists; 4 | import com.tianxiao.faas.application.handler.FaaSExecuteHandler; 5 | import com.tianxiao.faas.common.enums.biz.FaaSServiceStatusEnum; 6 | import org.apache.ibatis.annotations.Param; 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.web.bind.annotation.RestController; 9 | import org.springframework.web.context.request.RequestContextHolder; 10 | import org.springframework.web.context.request.ServletRequestAttributes; 11 | import reactor.core.publisher.Mono; 12 | 13 | import javax.annotation.Resource; 14 | import javax.servlet.http.HttpServletRequest; 15 | import java.util.Map; 16 | 17 | @RestController 18 | public class FaaSController { 19 | @Resource 20 | private FaaSExecuteHandler faaSExecuteHandler; 21 | 22 | @GetMapping(value = "/executeOnOfferLine") 23 | public Mono executeOnOfferLine(@Param("serviceName") String serviceName) { 24 | HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest(); 25 | Map parameterMap = request.getParameterMap(); 26 | return faaSExecuteHandler.executeByServiceName(serviceName, FaaSServiceStatusEnum.OFFLINE, Lists.newArrayList(parameterMap)); 27 | } 28 | 29 | @GetMapping(value = "/executeOnLine") 30 | public Mono executeOnLine(@Param("serviceName") String serviceName) { 31 | HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest(); 32 | Map parameterMap = request.getParameterMap(); 33 | return faaSExecuteHandler.executeByServiceName(serviceName, FaaSServiceStatusEnum.ONLINE, Lists.newArrayList(parameterMap)); 34 | } 35 | 36 | @GetMapping(value = "/executeOnPre") 37 | public Mono executeOnPre(@Param("serviceName") String serviceName) { 38 | HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest(); 39 | Map parameterMap = request.getParameterMap(); 40 | return faaSExecuteHandler.executeByServiceName(serviceName, FaaSServiceStatusEnum.PRE, Lists.newArrayList(parameterMap)); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ master ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ master ] 20 | schedule: 21 | - cron: '39 6 * * 5' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'java' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 37 | # Learn more about CodeQL language support at https://git.io/codeql-language-support 38 | 39 | steps: 40 | - name: Checkout repository 41 | uses: actions/checkout@v2 42 | 43 | # Initializes the CodeQL tools for scanning. 44 | - name: Initialize CodeQL 45 | uses: github/codeql-action/init@v1 46 | with: 47 | languages: ${{ matrix.language }} 48 | # If you wish to specify custom queries, you can do so here or in a config file. 49 | # By default, queries listed here will override any specified in a config file. 50 | # Prefix the list here with "+" to use these queries and those in the config file. 51 | # queries: ./path/to/local/query, your-org/your-repo/queries@main 52 | 53 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 54 | # If this step fails, then you should remove it and run the build manually (see below) 55 | - name: Autobuild 56 | uses: github/codeql-action/autobuild@v1 57 | 58 | # ℹ️ Command-line programs to run using the OS shell. 59 | # 📚 https://git.io/JvXDl 60 | 61 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines 62 | # and modify them (or add more) to build your code if your project 63 | # uses a compiled language 64 | 65 | #- run: | 66 | # make bootstrap 67 | # make release 68 | 69 | - name: Perform CodeQL Analysis 70 | uses: github/codeql-action/analyze@v1 71 | -------------------------------------------------------------------------------- /container/src/main/java/com/tianxiao/faas/container/processor/SpringBeanDefinitionsAfterProcessor.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.container.processor; 2 | 3 | import com.tianxiao.faas.common.exception.runtime.BeanDefinitionsAfterProcessorException; 4 | import com.tianxiao.faas.common.util.StringUtils; 5 | import com.tianxiao.faas.runtime.processor.BeanDefinitionsAfterProcessor; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.context.ApplicationContext; 8 | import org.springframework.stereotype.Component; 9 | 10 | import javax.annotation.Resource; 11 | import java.lang.reflect.Field; 12 | 13 | @Component 14 | public class SpringBeanDefinitionsAfterProcessor implements BeanDefinitionsAfterProcessor { 15 | @Resource 16 | private ApplicationContext applicationContext; 17 | 18 | @Override 19 | public void process(Object object) throws BeanDefinitionsAfterProcessorException { 20 | if (object == null) { 21 | return; 22 | } 23 | Field[] declaredFields = object.getClass().getDeclaredFields(); 24 | if (declaredFields == null || declaredFields.length <= 0) { 25 | return; 26 | } 27 | for (Field field : declaredFields) { 28 | field.setAccessible(true); 29 | Resource resource = field.getAnnotation(Resource.class); 30 | Autowired autowired = field.getAnnotation(Autowired.class); 31 | if (resource != null) { 32 | String name = resource.name(); 33 | if (name == null || StringUtils.isEmpty(name)) { 34 | name = StringUtils.firstCharLowerCase(field.getName()); 35 | } 36 | try { 37 | Object bean = applicationContext.getBean(name); 38 | field.set(object, bean); 39 | } catch (IllegalAccessException e) { 40 | throw new BeanDefinitionsAfterProcessorException(e); 41 | } 42 | } else if (autowired != null) { 43 | try { 44 | boolean required = autowired.required(); 45 | Class type = field.getType(); 46 | Object bean = applicationContext.getBean(type); 47 | if (required && bean == null) { 48 | throw new BeanDefinitionsAfterProcessorException(type.getName() + " is required"); 49 | } 50 | field.set(object, bean); 51 | } catch (IllegalAccessException e) { 52 | throw new BeanDefinitionsAfterProcessorException(e); 53 | } 54 | } 55 | } 56 | } 57 | 58 | @Override 59 | public int order() { 60 | return 0; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /api/src/main/java/com/tianxiao/faas/api/param/FaaSServiceSaveParam.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.api.param; 2 | 3 | import java.io.Serializable; 4 | 5 | public class FaaSServiceSaveParam implements Serializable { 6 | private static final long serialVersionUID = 6003778990863781482L; 7 | 8 | private Integer id; 9 | 10 | private String serviceName; 11 | 12 | private String serviceDesc; 13 | 14 | private int overTime; 15 | 16 | private int maxQps; 17 | 18 | private String script; 19 | 20 | private int language; 21 | 22 | private String modifier; 23 | 24 | private String group; 25 | 26 | private int status; 27 | 28 | private int cacheTime; 29 | 30 | public Integer getId() { 31 | return id; 32 | } 33 | 34 | public void setId(Integer id) { 35 | this.id = id; 36 | } 37 | 38 | public String getServiceName() { 39 | return serviceName; 40 | } 41 | 42 | public void setServiceName(String serviceName) { 43 | this.serviceName = serviceName; 44 | } 45 | 46 | public String getServiceDesc() { 47 | return serviceDesc; 48 | } 49 | 50 | public void setServiceDesc(String serviceDesc) { 51 | this.serviceDesc = serviceDesc; 52 | } 53 | 54 | public int getOverTime() { 55 | return overTime; 56 | } 57 | 58 | public void setOverTime(int overTime) { 59 | this.overTime = overTime; 60 | } 61 | 62 | public int getMaxQps() { 63 | return maxQps; 64 | } 65 | 66 | public void setMaxQps(int maxQps) { 67 | this.maxQps = maxQps; 68 | } 69 | 70 | public String getScript() { 71 | return script; 72 | } 73 | 74 | public void setScript(String script) { 75 | this.script = script; 76 | } 77 | 78 | public int getLanguage() { 79 | return language; 80 | } 81 | 82 | public void setLanguage(int language) { 83 | this.language = language; 84 | } 85 | 86 | public String getModifier() { 87 | return modifier; 88 | } 89 | 90 | public void setModifier(String modifier) { 91 | this.modifier = modifier; 92 | } 93 | 94 | public String getGroup() { 95 | return group; 96 | } 97 | 98 | public void setGroup(String group) { 99 | this.group = group; 100 | } 101 | 102 | public int getStatus() { 103 | return status; 104 | } 105 | 106 | public void setStatus(int status) { 107 | this.status = status; 108 | } 109 | 110 | public int getCacheTime() { 111 | return cacheTime; 112 | } 113 | 114 | public void setCacheTime(int cacheTime) { 115 | this.cacheTime = cacheTime; 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /biz/src/main/java/com/tianxiao/faas/biz/command/FaaSServiceSaveCommand.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.biz.command; 2 | 3 | import java.io.Serializable; 4 | 5 | public class FaaSServiceSaveCommand implements Serializable { 6 | private static final long serialVersionUID = 6003778990863781482L; 7 | 8 | private Integer id; 9 | 10 | private String serviceName; 11 | 12 | private String serviceDesc; 13 | 14 | private int overTime; 15 | 16 | private int maxQps; 17 | 18 | private String script; 19 | 20 | private int language; 21 | 22 | private String modifier; 23 | 24 | private String group; 25 | 26 | private int status; 27 | 28 | private int cacheTime; 29 | 30 | private int version; 31 | 32 | public Integer getId() { 33 | return id; 34 | } 35 | 36 | public void setId(Integer id) { 37 | this.id = id; 38 | } 39 | 40 | public String getServiceName() { 41 | return serviceName; 42 | } 43 | 44 | public void setServiceName(String serviceName) { 45 | this.serviceName = serviceName; 46 | } 47 | 48 | public String getServiceDesc() { 49 | return serviceDesc; 50 | } 51 | 52 | public void setServiceDesc(String serviceDesc) { 53 | this.serviceDesc = serviceDesc; 54 | } 55 | 56 | public int getOverTime() { 57 | return overTime; 58 | } 59 | 60 | public void setOverTime(int overTime) { 61 | this.overTime = overTime; 62 | } 63 | 64 | public int getMaxQps() { 65 | return maxQps; 66 | } 67 | 68 | public void setMaxQps(int maxQps) { 69 | this.maxQps = maxQps; 70 | } 71 | 72 | public String getScript() { 73 | return script; 74 | } 75 | 76 | public void setScript(String script) { 77 | this.script = script; 78 | } 79 | 80 | public int getLanguage() { 81 | return language; 82 | } 83 | 84 | public void setLanguage(int language) { 85 | this.language = language; 86 | } 87 | 88 | public String getModifier() { 89 | return modifier; 90 | } 91 | 92 | public void setModifier(String modifier) { 93 | this.modifier = modifier; 94 | } 95 | 96 | public String getGroup() { 97 | return group; 98 | } 99 | 100 | public void setGroup(String group) { 101 | this.group = group; 102 | } 103 | 104 | public int getStatus() { 105 | return status; 106 | } 107 | 108 | public void setStatus(int status) { 109 | this.status = status; 110 | } 111 | 112 | public int getCacheTime() { 113 | return cacheTime; 114 | } 115 | 116 | public void setCacheTime(int cacheTime) { 117 | this.cacheTime = cacheTime; 118 | } 119 | 120 | public int getVersion() { 121 | return version; 122 | } 123 | 124 | public void setVersion(int version) { 125 | this.version = version; 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /common/src/main/java/com/tianxiao/faas/common/util/NamedThreadPools.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.common.util; 2 | 3 | import java.util.concurrent.ArrayBlockingQueue; 4 | import java.util.concurrent.ExecutorService; 5 | import java.util.concurrent.ScheduledExecutorService; 6 | import java.util.concurrent.ScheduledThreadPoolExecutor; 7 | import java.util.concurrent.SynchronousQueue; 8 | import java.util.concurrent.ThreadFactory; 9 | import java.util.concurrent.ThreadPoolExecutor; 10 | import java.util.concurrent.TimeUnit; 11 | 12 | /** 13 | * tianxiao 14 | */ 15 | public class NamedThreadPools { 16 | 17 | public static ExecutorService newFixedThreadPool(int nThreads, String name) { 18 | return newFixedThreadPool(nThreads, new NamedThreadFactory(name)); 19 | } 20 | 21 | 22 | public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) { 23 | return new ThreadPoolExecutor(nThreads, nThreads, 24 | 0L, TimeUnit.MILLISECONDS, 25 | new ArrayBlockingQueue<>(150), 26 | threadFactory); 27 | } 28 | 29 | 30 | public static ExecutorService newCachedThreadPool(String name) { 31 | return newCachedThreadPool(new NamedThreadFactory(name)); 32 | } 33 | 34 | 35 | public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) { 36 | return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 37 | 60L, TimeUnit.SECONDS, 38 | new SynchronousQueue(), 39 | threadFactory); 40 | } 41 | 42 | 43 | public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize, String name) { 44 | return newScheduledThreadPool(corePoolSize, new NamedThreadFactory(name)); 45 | } 46 | 47 | 48 | public static ScheduledExecutorService newScheduledThreadPool( 49 | int corePoolSize, ThreadFactory threadFactory) { 50 | return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory); 51 | } 52 | 53 | /** 54 | * Each tasks blocks 90% of the time, and works only 10% of its 55 | * lifetime. That is, I/O intensive pool 56 | * @return io intensive Thread pool size 57 | */ 58 | public static int ioPoolSize() { 59 | double blockingCoefficient = 0.9; 60 | return poolSize(blockingCoefficient); 61 | } 62 | 63 | /** 64 | * 65 | * Number of threads = Number of Available Cores / (1 - Blocking 66 | * Coefficient) where the blocking coefficient is between 0 and 1. 67 | * 68 | * A computation-intensive task has a blocking coefficient of 0, whereas an 69 | * IO-intensive task has a value close to 1, 70 | * so we don't have to worry about the value reaching 1. 71 | * @param blockingCoefficient the coefficient 72 | * @return Thread pool size 73 | */ 74 | public static int poolSize(double blockingCoefficient) { 75 | int numberOfCores = Runtime.getRuntime().availableProcessors(); 76 | int poolSize = (int) (numberOfCores / (1 - blockingCoefficient)); 77 | return poolSize; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /mapper/src/main/java/com/tianxiao/faas/mapper/dao/FaaSServiceModelMapper.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.mapper.dao; 2 | 3 | import com.tianxiao.faas.mapper.model.FaaSServiceModel; 4 | import com.tianxiao.faas.mapper.model.FaaSServiceModelExample; 5 | import java.util.List; 6 | import org.apache.ibatis.annotations.Param; 7 | 8 | public interface FaaSServiceModelMapper { 9 | /** 10 | * This method was generated by MyBatis Generator. 11 | * This method corresponds to the database table t_services 12 | * 13 | * @mbg.generated Thu Dec 17 11:25:31 CST 2020 14 | */ 15 | long countByExample(FaaSServiceModelExample example); 16 | 17 | /** 18 | * This method was generated by MyBatis Generator. 19 | * This method corresponds to the database table t_services 20 | * 21 | * @mbg.generated Thu Dec 17 11:25:31 CST 2020 22 | */ 23 | int deleteByExample(FaaSServiceModelExample example); 24 | 25 | /** 26 | * This method was generated by MyBatis Generator. 27 | * This method corresponds to the database table t_services 28 | * 29 | * @mbg.generated Thu Dec 17 11:25:31 CST 2020 30 | */ 31 | int insert(FaaSServiceModel record); 32 | 33 | /** 34 | * This method was generated by MyBatis Generator. 35 | * This method corresponds to the database table t_services 36 | * 37 | * @mbg.generated Thu Dec 17 11:25:31 CST 2020 38 | */ 39 | int insertSelective(FaaSServiceModel record); 40 | 41 | /** 42 | * This method was generated by MyBatis Generator. 43 | * This method corresponds to the database table t_services 44 | * 45 | * @mbg.generated Thu Dec 17 11:25:31 CST 2020 46 | */ 47 | List selectByExampleWithBLOBs(FaaSServiceModelExample example); 48 | 49 | /** 50 | * This method was generated by MyBatis Generator. 51 | * This method corresponds to the database table t_services 52 | * 53 | * @mbg.generated Thu Dec 17 11:25:31 CST 2020 54 | */ 55 | List selectByExample(FaaSServiceModelExample example); 56 | 57 | /** 58 | * This method was generated by MyBatis Generator. 59 | * This method corresponds to the database table t_services 60 | * 61 | * @mbg.generated Thu Dec 17 11:25:31 CST 2020 62 | */ 63 | int updateByExampleSelective(@Param("record") FaaSServiceModel record, @Param("example") FaaSServiceModelExample example); 64 | 65 | /** 66 | * This method was generated by MyBatis Generator. 67 | * This method corresponds to the database table t_services 68 | * 69 | * @mbg.generated Thu Dec 17 11:25:31 CST 2020 70 | */ 71 | int updateByExampleWithBLOBs(@Param("record") FaaSServiceModel record, @Param("example") FaaSServiceModelExample example); 72 | 73 | /** 74 | * This method was generated by MyBatis Generator. 75 | * This method corresponds to the database table t_services 76 | * 77 | * @mbg.generated Thu Dec 17 11:25:31 CST 2020 78 | */ 79 | int updateByExample(@Param("record") FaaSServiceModel record, @Param("example") FaaSServiceModelExample example); 80 | } -------------------------------------------------------------------------------- /biz/src/main/java/com/tianxiao/faas/biz/publisher/FaaSRedisPublisher.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.biz.publisher; 2 | 3 | import com.tianxiao.faas.biz.domain.FaaSServiceDomain; 4 | import com.tianxiao.faas.biz.domain.aggregate.FaaSAggregate; 5 | import com.tianxiao.faas.biz.factory.FaaSAggregateFactory; 6 | import com.tianxiao.faas.biz.infrastructure.repositories.FaaSServiceRepository; 7 | import com.tianxiao.faas.common.enums.biz.FaaSServiceStatusEnum; 8 | import com.tianxiao.faas.common.util.IpUtils; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.core.env.Environment; 11 | import org.springframework.data.redis.core.RedisTemplate; 12 | import org.springframework.stereotype.Service; 13 | 14 | import javax.annotation.Resource; 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | import java.util.Set; 18 | 19 | @Service 20 | public class FaaSRedisPublisher implements FaaSPublisher { 21 | @Resource 22 | private RedisTemplate redisTemplate; 23 | @Autowired 24 | private Environment env; 25 | @Resource 26 | private FaaSServiceRepository faaSServiceRepository; 27 | @Resource 28 | private FaaSAggregateFactory faaSAggregateFactory; 29 | 30 | private String register_cache_key = "faaS_register_cache_"; 31 | 32 | private String publish_cache_key = "faaS_publish_cache_"; 33 | 34 | 35 | @Override 36 | public void register(String ip) { 37 | redisTemplate.opsForSet().add(getEnvKey(register_cache_key), ip); 38 | } 39 | 40 | @Override 41 | public void offline(String ip) { 42 | redisTemplate.opsForSet().remove(getEnvKey(register_cache_key), ip); 43 | } 44 | 45 | @Override 46 | public List servers() { 47 | Set members = redisTemplate.opsForSet().members(getEnvKey(register_cache_key)); 48 | return new ArrayList<>(members); 49 | } 50 | 51 | @Override 52 | public void publish(String serviceName) { 53 | List servers = this.servers(); 54 | if (servers == null) { 55 | return; 56 | } 57 | for (String server : servers) { 58 | redisTemplate.opsForSet().add(getEnvKey(publish_cache_key) + server, serviceName); 59 | } 60 | } 61 | 62 | @Override 63 | public void refreshCache() { 64 | Set members = redisTemplate.opsForSet().members(getEnvKey(publish_cache_key) + IpUtils.getLocalHostAddress()); 65 | if (members == null) { 66 | return; 67 | } 68 | for (String server : members) { 69 | FaaSServiceDomain domain = faaSServiceRepository.get(server, FaaSServiceStatusEnum.ONLINE); 70 | if (domain == null) { 71 | continue; 72 | } 73 | FaaSAggregate faaSAggregate = faaSAggregateFactory.build(domain); 74 | faaSAggregate.refresh(); 75 | redisTemplate.opsForSet().remove(getEnvKey(publish_cache_key) + IpUtils.getLocalHostAddress(), server); 76 | } 77 | } 78 | 79 | private String getEnvKey(String key) { 80 | String envString = env.getProperty("server.env"); 81 | return key + envString; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /biz/src/main/java/com/tianxiao/faas/biz/infrastructure/repositories/FaaSServiceRepository.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.biz.infrastructure.repositories; 2 | 3 | import com.tianxiao.faas.biz.domain.FaaSServiceDomain; 4 | import com.tianxiao.faas.biz.factory.FaaSServiceDomainFactory; 5 | import com.tianxiao.faas.common.enums.biz.FaaSServiceStatusEnum; 6 | import com.tianxiao.faas.common.exception.ParamAccessException; 7 | import com.tianxiao.faas.mapper.dao.FaaSServiceModelMapper; 8 | import com.tianxiao.faas.mapper.model.FaaSServiceModel; 9 | import com.tianxiao.faas.mapper.model.FaaSServiceModelExample; 10 | import org.springframework.stereotype.Repository; 11 | import org.springframework.util.CollectionUtils; 12 | 13 | import javax.annotation.Resource; 14 | import java.util.Date; 15 | import java.util.List; 16 | 17 | @Repository 18 | public class FaaSServiceRepository { 19 | 20 | @Resource 21 | private FaaSServiceModelMapper faaSServiceModelMapper; 22 | @Resource 23 | private FaaSServiceDomainFactory faaSServiceDomainFactory; 24 | 25 | public boolean save(FaaSServiceDomain faaSServiceDomain) { 26 | if (faaSServiceDomain == null) { 27 | throw new ParamAccessException("服务模型不能为空"); 28 | } 29 | FaaSServiceModel faaSServiceModel = faaSServiceDomainFactory.build(faaSServiceDomain); 30 | 31 | Integer id = faaSServiceDomain.getId(); 32 | int line = 0; 33 | if (id == null || id <= 0) { 34 | faaSServiceModel.setCreator(faaSServiceDomain.getModifier()); 35 | line =faaSServiceModelMapper.insertSelective(faaSServiceModel); 36 | faaSServiceDomain.setId(faaSServiceModel.getId()); 37 | } else { 38 | int version = faaSServiceDomain.getVersion(); 39 | faaSServiceModel.setId(id); 40 | faaSServiceModel.setEditTime(new Date()); 41 | faaSServiceModel.setVersion(version + 1); 42 | faaSServiceDomain.setVersion(faaSServiceModel.getVersion()); 43 | FaaSServiceModelExample faaSServiceModelExample = new FaaSServiceModelExample(); 44 | faaSServiceModelExample.createCriteria().andIdEqualTo(id).andVersionEqualTo(version); 45 | line = faaSServiceModelMapper.updateByExampleSelective(faaSServiceModel, faaSServiceModelExample); 46 | } 47 | return line > 0; 48 | } 49 | 50 | public FaaSServiceDomain get(String serviceName, FaaSServiceStatusEnum faaSServiceStatusEnum) { 51 | FaaSServiceModelExample example = new FaaSServiceModelExample(); 52 | example.createCriteria().andServiceNameEqualTo(serviceName).andStatusEqualTo(faaSServiceStatusEnum.getStatus()); 53 | List faaSServiceModels = faaSServiceModelMapper.selectByExample(example); 54 | if (CollectionUtils.isEmpty(faaSServiceModels)) { 55 | return null; 56 | } 57 | return faaSServiceDomainFactory.build(faaSServiceModels.get(0)); 58 | } 59 | 60 | public FaaSServiceDomain get(Integer id) { 61 | FaaSServiceModelExample example = new FaaSServiceModelExample(); 62 | example.createCriteria().andIdEqualTo(id); 63 | List faaSServiceModels = faaSServiceModelMapper.selectByExample(example); 64 | if (CollectionUtils.isEmpty(faaSServiceModels)) { 65 | return null; 66 | } 67 | return faaSServiceDomainFactory.build(faaSServiceModels.get(0)); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /application/src/main/java/com/tianxiao/faas/application/web/TestController.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.application.web; 2 | 3 | import com.google.common.collect.Lists; 4 | import com.google.common.collect.Maps; 5 | import com.tianxiao.faas.common.enums.ExecutorType; 6 | import com.tianxiao.faas.common.exception.runtime.ExecuteException; 7 | import com.tianxiao.faas.container.bean.UserBean; 8 | import com.tianxiao.faas.runtime.Executor; 9 | import com.tianxiao.faas.runtime.ExecutorContext; 10 | import com.tianxiao.faas.runtime.ExecutorFactory; 11 | import org.springframework.web.bind.annotation.RequestMapping; 12 | import org.springframework.web.bind.annotation.RequestParam; 13 | import org.springframework.web.bind.annotation.RestController; 14 | 15 | import javax.annotation.Resource; 16 | 17 | @RestController 18 | public class TestController { 19 | @Resource 20 | private ExecutorFactory executorFactory; 21 | private com.tianxiao.faas.container.bean.UserBean UserBean; 22 | 23 | @RequestMapping("/test") 24 | public Object test(@RequestParam String code, @RequestParam String method) throws ExecuteException { 25 | Executor executor = executorFactory.getExecutor(ExecutorType.GROOVY); 26 | ExecutorContext executeContext = new ExecutorContext(); 27 | executeContext.setCode(code); 28 | executeContext.setDebug(true); 29 | executeContext.setMethodName(method); 30 | Object execute = executor.execute(executeContext); 31 | 32 | return execute; 33 | } 34 | 35 | public static void main(String[] args) throws ExecuteException { 36 | String code = "package com.tianxiao.faas.application.web;\n" + 37 | "import java.util.Map;\n" + 38 | "import java.util.Set;\n" + 39 | "\n" + 40 | "public class Tests {\n" + 41 | " public String execute(Map map) {\n" + 42 | " StringBuilder result = new StringBuilder();\n" + 43 | "\n" + 44 | " Set strings = map.keySet();\n" + 45 | " for (String key : strings) {\n" + 46 | " result.append(key + \"|\").append(map.get(key)).append(\"-\");\n" + 47 | " }\n" + 48 | " User user = new User();\n" + 49 | " user.sayHello();\n" + 50 | "\n" + 51 | " while (true) {\n" + 52 | " System.out.println(1);\n" + 53 | " }\n" + 54 | "\n" + 55 | " }\n" + 56 | "\n" + 57 | " public static class User {\n" + 58 | " public void sayHello() {\n" + 59 | " System.out.println(\"hello\");\n" + 60 | " }\n" + 61 | " }\n" + 62 | "}"; 63 | ExecutorFactory executorFactory = ExecutorFactory.getInstance(); 64 | executorFactory.init(); 65 | Executor executor = executorFactory.getExecutor(ExecutorType.GROOVY); 66 | ExecutorContext executeContext = new ExecutorContext(); 67 | executeContext.setCode(code); 68 | executeContext.setDebug(true); 69 | 70 | executeContext.setParams(Lists.newArrayList(Maps.newHashMap())); 71 | executeContext.setMethodName("execute"); 72 | Object execute = executor.execute(executeContext); 73 | System.out.println(execute); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at 465996346@qq.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /biz/src/main/java/com/tianxiao/faas/biz/factory/FaaSServiceDomainFactory.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.biz.factory; 2 | 3 | import com.tianxiao.faas.biz.command.FaaSServiceSaveCommand; 4 | import com.tianxiao.faas.biz.domain.FaaSServiceDomain; 5 | import com.tianxiao.faas.biz.infrastructure.publisher.EventPublisher; 6 | import com.tianxiao.faas.mapper.model.FaaSServiceModel; 7 | import com.tianxiao.faas.runtime.ExecutorFactory; 8 | import org.springframework.stereotype.Component; 9 | 10 | import javax.annotation.Resource; 11 | import java.util.Date; 12 | 13 | @Component 14 | public class FaaSServiceDomainFactory { 15 | @Resource 16 | private EventPublisher eventPublisher; 17 | @Resource 18 | private ExecutorFactory executorFactory; 19 | 20 | public FaaSServiceDomain build(FaaSServiceSaveCommand command) { 21 | if (command == null) { 22 | return null; 23 | } 24 | return FaaSServiceDomain.Builder.builder() 25 | .serviceName(command.getServiceName()) 26 | .serviceDesc(command.getServiceDesc()) 27 | .script(command.getScript()) 28 | .overTime(command.getOverTime()) 29 | .maxQps(command.getMaxQps()) 30 | .modifier(command.getModifier()) 31 | .language(command.getLanguage()) 32 | .group(command.getGroup()) 33 | .id(command.getId()) 34 | .version(command.getVersion()) 35 | .executorFactory(executorFactory) 36 | .eventPublisher(eventPublisher) 37 | .cacheTime(command.getCacheTime()) 38 | .build(); 39 | } 40 | 41 | public FaaSServiceDomain build(FaaSServiceModel faaSServiceModel) { 42 | if (faaSServiceModel == null) { 43 | return null; 44 | } 45 | return FaaSServiceDomain.Builder.builder().cacheTime(faaSServiceModel.getCacheTime()) 46 | .eventPublisher(eventPublisher) 47 | .executorFactory(executorFactory) 48 | .group(faaSServiceModel.getGroup()) 49 | .id(faaSServiceModel.getId()) 50 | .language(faaSServiceModel.getLanguage()) 51 | .maxQps(faaSServiceModel.getMaxQps()) 52 | .modifier(faaSServiceModel.getModifier()) 53 | .overTime(faaSServiceModel.getOverTime()) 54 | .script(faaSServiceModel.getScript()) 55 | .serviceDesc(faaSServiceModel.getServiceDesc()) 56 | .serviceName(faaSServiceModel.getServiceName()) 57 | .status(faaSServiceModel.getStatus()) 58 | .version(faaSServiceModel.getVersion()) 59 | .build(); 60 | } 61 | 62 | public FaaSServiceModel build(FaaSServiceDomain faaSServiceDomain) { 63 | if (faaSServiceDomain == null) { 64 | return null; 65 | } 66 | FaaSServiceModel faaSServiceModel = new FaaSServiceModel(); 67 | faaSServiceModel.setCacheTime(faaSServiceDomain.getCacheTime()); 68 | faaSServiceModel.setCreateTime(new Date()); 69 | faaSServiceModel.setGroup(faaSServiceDomain.getGroup()); 70 | faaSServiceModel.setIsDeleted(0); 71 | faaSServiceModel.setId(faaSServiceDomain.getId()); 72 | faaSServiceModel.setLanguage(faaSServiceDomain.getLanguage()); 73 | faaSServiceModel.setMaxQps(faaSServiceDomain.getMaxQps()); 74 | faaSServiceModel.setModifier(faaSServiceDomain.getModifier()); 75 | faaSServiceModel.setOverTime(faaSServiceDomain.getOverTime()); 76 | faaSServiceModel.setScript(faaSServiceDomain.getScript()); 77 | faaSServiceModel.setServiceDesc(faaSServiceDomain.getServiceDesc()); 78 | faaSServiceModel.setServiceName(faaSServiceDomain.getServiceName()); 79 | faaSServiceModel.setStatus(faaSServiceDomain.getStatus()); 80 | faaSServiceModel.setVersion(faaSServiceDomain.getVersion()); 81 | return faaSServiceModel; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /common/src/main/java/com/tianxiao/faas/common/JSONResult.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.common; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.alibaba.fastjson.serializer.SerializerFeature; 5 | 6 | import java.io.Serializable; 7 | 8 | public class JSONResult implements Serializable { 9 | private static final long serialVersionUID = -7539749553868932437L; 10 | 11 | private String message; 12 | private boolean isSuccess; 13 | private Object data; 14 | private int pageNo; 15 | private int pageSize; 16 | private int totalCount; 17 | private int totalPage; 18 | 19 | public String getMessage() { 20 | return message; 21 | } 22 | 23 | public void setMessage(String message) { 24 | this.message = message; 25 | } 26 | 27 | public boolean getIsSuccess() { 28 | return isSuccess; 29 | } 30 | 31 | public void setIsSuccess(boolean success) { 32 | isSuccess = success; 33 | } 34 | 35 | public Object getData() { 36 | return data; 37 | } 38 | 39 | public void setData(Object data) { 40 | this.data = data; 41 | } 42 | 43 | public int getPageNo() { 44 | return pageNo; 45 | } 46 | 47 | public void setPageNo(int pageNo) { 48 | this.pageNo = pageNo; 49 | } 50 | 51 | public int getPageSize() { 52 | return pageSize; 53 | } 54 | 55 | public void setPageSize(int pageSize) { 56 | this.pageSize = pageSize; 57 | } 58 | 59 | public int getTotalCount() { 60 | return totalCount; 61 | } 62 | 63 | public void setTotalCount(int totalCount) { 64 | this.totalCount = totalCount; 65 | } 66 | 67 | public int getTotalPage() { 68 | return totalPage; 69 | } 70 | 71 | public void setTotalPage(int totalPage) { 72 | this.totalPage = totalPage; 73 | } 74 | 75 | @Override 76 | public String toString() { 77 | return JSON.toJSONString(this); 78 | } 79 | 80 | public static final class Builder { 81 | private String message; 82 | private boolean isSuccess; 83 | private Object data; 84 | private int pageNo; 85 | private int pageSize; 86 | private int totalCount; 87 | private int totalPage; 88 | 89 | private Builder() { 90 | } 91 | 92 | public static Builder builder() { 93 | return new Builder(); 94 | } 95 | 96 | public Builder message(String message) { 97 | this.message = message; 98 | return this; 99 | } 100 | 101 | public Builder isSuccess(boolean isSuccess) { 102 | this.isSuccess = isSuccess; 103 | return this; 104 | } 105 | 106 | public Builder data(Object data) { 107 | this.data = data; 108 | return this; 109 | } 110 | 111 | public Builder pageNo(int pageNo) { 112 | this.pageNo = pageNo; 113 | return this; 114 | } 115 | 116 | public Builder pageSize(int pageSize) { 117 | this.pageSize = pageSize; 118 | return this; 119 | } 120 | 121 | public Builder totalCount(int totalCount) { 122 | this.totalCount = totalCount; 123 | return this; 124 | } 125 | 126 | public Builder totalPage(int totalPage) { 127 | this.totalPage = totalPage; 128 | return this; 129 | } 130 | 131 | public JSONResult build() { 132 | JSONResult jSONResult = new JSONResult(); 133 | jSONResult.setMessage(message); 134 | jSONResult.setIsSuccess(isSuccess); 135 | jSONResult.setData(data); 136 | jSONResult.setPageNo(pageNo); 137 | jSONResult.setPageSize(pageSize); 138 | jSONResult.setTotalCount(totalCount); 139 | jSONResult.setTotalPage(totalPage); 140 | return jSONResult; 141 | } 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /runtime/src/main/java/com/tianxiao/faas/runtime/groovy/GroovyExecutor.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.runtime.groovy; 2 | 3 | import com.tianxiao.faas.common.enums.ExecutorType; 4 | import com.tianxiao.faas.common.enums.context.Environment; 5 | import com.tianxiao.faas.common.exception.runtime.BeanDefinitionsAfterProcessorException; 6 | import com.tianxiao.faas.common.exception.runtime.CompileException; 7 | import com.tianxiao.faas.common.exception.runtime.ExecuteException; 8 | import com.tianxiao.faas.common.util.ObjectUtils; 9 | import com.tianxiao.faas.common.util.StringUtils; 10 | import com.tianxiao.faas.runtime.BeanDefinitionsProcessorManagerFactory; 11 | import com.tianxiao.faas.runtime.Executor; 12 | import com.tianxiao.faas.runtime.ExecutorContext; 13 | import com.tianxiao.faas.runtime.FaaSBeanFactory; 14 | import com.tianxiao.faas.runtime.context.FaaSContext; 15 | import com.tianxiao.faas.runtime.context.FaaSContextHolder; 16 | import com.tianxiao.faas.runtime.processor.BeanDefinitionsAfterProcessor; 17 | import groovy.lang.GroovyClassLoader; 18 | import groovy.lang.GroovyObject; 19 | import org.codehaus.groovy.control.CompilationFailedException; 20 | 21 | import java.util.List; 22 | 23 | public class GroovyExecutor implements Executor { 24 | 25 | public Object compile(ExecutorContext executeContext) throws CompileException { 26 | GroovyClassLoader instance = GroovyClassLoaderHolder.getInstance(); 27 | Class parseClass = null; 28 | GroovyObject object; 29 | try { 30 | String code = executeContext.getCode(); 31 | String serviceName = executeContext.getServiceName(); 32 | final boolean debug = executeContext.getDebug(); 33 | if (debug) { 34 | parseClass = instance.parseClass(code); 35 | object = assemblyBean(parseClass); 36 | } else { 37 | if (StringUtils.isEmpty(serviceName)) { 38 | throw new CompileException("服务名称不能为空"); 39 | } 40 | Object bean = FaaSBeanFactory.getBean(serviceName); 41 | if (bean != null && (bean instanceof GroovyObject)) { 42 | object = (GroovyObject) bean; 43 | } else { 44 | parseClass = instance.parseClass(code); 45 | object = assemblyBean(parseClass); 46 | cache(serviceName, object); 47 | } 48 | } 49 | } catch (CompilationFailedException e) { 50 | throw new CompileException(e); 51 | } catch (IllegalAccessException e) { 52 | throw new CompileException(e); 53 | } catch (InstantiationException e) { 54 | throw new CompileException(e); 55 | } catch (BeanDefinitionsAfterProcessorException e) { 56 | throw new CompileException(e); 57 | } 58 | return object; 59 | } 60 | 61 | private void cache(String serviceName, GroovyObject object) { 62 | FaaSContext faaSContext = FaaSContextHolder.get(); 63 | if (faaSContext != null && faaSContext.getEnv() == Environment.ONLINE) { 64 | FaaSBeanFactory.cache(serviceName, object); 65 | } 66 | } 67 | 68 | public Object execute(ExecutorContext executeContext) throws ExecuteException { 69 | ObjectUtils.checkNull(executeContext, "executor context require not null"); 70 | String methodName = executeContext.getMethodName(); 71 | List params = executeContext.getParams(); 72 | try { 73 | GroovyObject object; 74 | Object result = null; 75 | object = (GroovyObject) compile(executeContext); 76 | if (object != null) { 77 | result = object.invokeMethod(methodName, params.toArray()); 78 | } 79 | return result; 80 | } catch (CompileException e) { 81 | throw new ExecuteException(e); 82 | } 83 | } 84 | 85 | /** 86 | * 创建并组装bean 87 | * @param parseClass 88 | * @return 89 | * @throws InstantiationException 90 | * @throws IllegalAccessException 91 | * @throws BeanDefinitionsAfterProcessorException 92 | */ 93 | private GroovyObject assemblyBean(Class parseClass) throws InstantiationException, IllegalAccessException, BeanDefinitionsAfterProcessorException { 94 | GroovyObject object = (GroovyObject) parseClass.newInstance(); 95 | List processors = BeanDefinitionsProcessorManagerFactory.getInstance() 96 | .getManager() 97 | .getAfterProcessors(); 98 | if (processors != null) { 99 | for (BeanDefinitionsAfterProcessor processor : processors) { 100 | processor.process(object); 101 | } 102 | } 103 | return object; 104 | } 105 | 106 | public String type() { 107 | return ExecutorType.GROOVY.name(); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # wuzhu-FaaS 2 | 3 | 该项目旨在提供一种faas的解决方案,目前已经开发好了底层代码,可以运行groovy脚本及java脚本。 4 | 底层是采用groovy引擎来执行。 5 | 后续会持续更新。 6 | 7 | 有简单的设计文档faas文档.docx,也有一些后续的简单规划。 8 | 目前切面的基本设计已经开发完成,缓存、限流、脚本执行统计切面还没有实现。 9 | 10 | GroovyExecutor 11 | 执行器里面是有本地缓存的,为防止编译导致的性能损耗。如果正式上线需要考虑分布式刷新缓存的问题, 12 | 可以通过zk、redis做缓存刷新操作,这里不能简单的就把脚本编译好的类/对象存入redis中,这里有序列化的问题,还是需要利用本地缓存, 13 | 通过通知的方式把本地缓存刷入. 14 | 目前分布式刷新缓存问题基于redis的方案已经实现,具体实现见:com.tianxiao.faas.biz.publisher.FaaSPublisher 15 | 设计方案:https://www.yuque.com/wuyan-jkoan/kb/wl8fb2 16 | 17 | 系统已经实现了脚本死循环检测机制,LoopCounter 类中限制了脚本中的循环次数,目前限制为1000次,超过就会抛出异常。 18 | 实现原理,参考:https://www.yuque.com/markylumin/ikl7q2/gyqc2o 19 | 20 | 目前已经投入使用的公司: 21 | 22 | 海派客-对账系统,使用内核container及其依赖,发布和开发页面是海拍客单独实现。 23 | 24 | 360云盘-连接器系统,使用container内核实现外部系统对接及消息推送对接 25 | 26 | dubbo配置如下: 27 | ``` 28 | dubbo.app.name=faas 29 | dubbo.app.owner=tianxiao 30 | dubbo.protocol.port=28889 31 | dubbo.register.address=配置自己zk地址 32 | dubbo.register.timeout=3000 33 | ``` 34 | 下面是一个dubbo 泛化调用的例子: 35 | ``` 36 | import com.google.common.collect.Lists; 37 | import com.tianxiao.faas.container.annotation.DubboReference; 38 | import com.tianxiao.faas.container.invoker.DubboServiceInvoker; 39 | 40 | import java.util.HashMap; 41 | import java.util.Map; 42 | 43 | public class Test { 44 | @DubboReference(interfaceName = "com.***.***.***.api.borrow..***", 45 | group = "20200427-tianxiao-himoney") 46 | private DubboServiceInvoker dubboServiceInvoker; 47 | 48 | public Object test() { 49 | Map result = new HashMap<>(); 50 | final Object queryToReturn = dubboServiceInvoker.invoke("queryToReturn", Lists.newArrayList("java.lang.String"), Lists.newArrayList("1d004107e0ed4013b86dbfd604406e16")); 51 | result.put("result", queryToReturn); 52 | return result; 53 | } 54 | } 55 | ``` 56 | 1. FaaSApplication 启动应用 57 | 2. 调用localhost:8888/test?code=上面的脚本&method=脚本里面的方法 58 | 3. 发送请求即可,这样就可以脚本的形式调用dubbo接口 59 | 60 | 下面是一个普通调用例子: 61 | ``` 62 | public class GroovyTest { 63 | public static void main(String[] args) throws ExecuteException { 64 | String code = "package com.tianxiao.faas.application.web;\n" + 65 | "\n" + 66 | "import com.tianxiao.faas.container.bean.UserBean;\n" + 67 | "\n" + 68 | "public class Test {\n" + 69 | "\n" + 70 | "\n" + 71 | " public Object test(UserBean name) {\n" + 72 | " String userName = name.getUserName(\"1\");\n" + 73 | " return userName;\n" + 74 | " }\n" + 75 | "}\n"; 76 | ExecutorFactory executorFactory = ExecutorFactory.getInstance(); 77 | executorFactory.init(); 78 | Executor executor = executorFactory.getExecutor(ExecutorType.GROOVY); 79 | ExecutorContext executeContext = new ExecutorContext(); 80 | executeContext.setCode(code); 81 | executeContext.setDebug(true); 82 | 83 | executeContext.setParams(Lists.newArrayList(new UserBean())); 84 | executeContext.setMethodName("test"); 85 | Object execute = executor.execute(executeContext); 86 | System.out.println(execute); 87 | } 88 | } 89 | ``` 90 | 这里code,可以是网络传输来的脚本,可以是存储在数据库的脚本,可以是文件读取的脚本。 91 | 92 | 使用spring 容器的例子: 93 | ``` 94 | String code = 95 | "import com.tianxiao.faas.container.bean.UserBean;" + 96 | "import com.ql.util.express.DefaultContext;" + 97 | "import com.ql.util.express.ExpressRunner;" + 98 | "import javax.annotation.Resource;" + 99 | "import org.springframework.beans.factory.annotation.Autowired" + 100 | "public class Test {" + 101 | " @Autowired" + 102 | " private UserBean userBean;" + 103 | " public String test(String name) {" + 104 | " ExpressRunner runner = new ExpressRunner();\n" + 105 | " DefaultContext context = new DefaultContext();\n" + 106 | " context.put(\"a\",1);\n" + 107 | " context.put(\"b\",2);\n" + 108 | " context.put(\"c\",3);\n" + 109 | " String express = \"a+b*c\";\n" + 110 | " Object r = runner.execute(express, context, null, true, false);\n" + 111 | " System.out.println(r); " + 112 | " return userBean.getUserName(name);\n" + 113 | " }\n" + 114 | "}\n"; 115 | Executor executor = executorFactory.getExecutor(ExecutorType.GROOVY); 116 | ExecutorContext executeContext = new ExecutorContext(); 117 | executeContext.setCode(code); 118 | executeContext.setMethodName("test"); 119 | executeContext.setParams("zhang san"); 120 | Object execute = executor.execute(executeContext); 121 | ``` 122 | 123 | -------------------------------------------------------------------------------- /common/src/main/java/com/tianxiao/faas/common/execute/CodeShell.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.common.execute; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | import java.util.concurrent.ArrayBlockingQueue; 9 | import java.util.concurrent.ExecutionException; 10 | import java.util.concurrent.ExecutorService; 11 | import java.util.concurrent.Future; 12 | import java.util.concurrent.ThreadFactory; 13 | import java.util.concurrent.ThreadPoolExecutor; 14 | import java.util.concurrent.TimeUnit; 15 | import java.util.concurrent.TimeoutException; 16 | import java.util.concurrent.atomic.AtomicInteger; 17 | 18 | public class CodeShell { 19 | private static final Logger logger = LoggerFactory.getLogger(CodeShell.class); 20 | private ExecutorService executorService; 21 | 22 | private int corePoolSize; 23 | 24 | private int maxPoolSize; 25 | 26 | private int queueSize; 27 | 28 | public void init() { 29 | corePoolSize = corePoolSize <= 0 ? 20 : corePoolSize; 30 | maxPoolSize = maxPoolSize <= 0 ? 100 : maxPoolSize; 31 | queueSize = queueSize <= 0 ? 50 : queueSize; 32 | executorService = new ThreadPoolExecutor(corePoolSize, maxPoolSize, 33 | 0L, TimeUnit.MILLISECONDS, 34 | new ArrayBlockingQueue<>(queueSize), 35 | new CodeShellThreadFactory()); 36 | } 37 | 38 | public void destroy() { 39 | executorService.shutdown(); 40 | } 41 | 42 | public List invoke(DataSource dataSource) { 43 | return invoke(0, dataSource); 44 | } 45 | 46 | public List invoke(int timeout, DataSource dataSource) { 47 | if (dataSource == null) { 48 | return null; 49 | } 50 | List callers = dataSource.getCallers(); 51 | if (callers == null || callers.size() <= 0) { 52 | return null; 53 | } 54 | List results = new ArrayList<>(); 55 | List> futures = new ArrayList<>(); 56 | for (Caller caller : callers) { 57 | Future submit = executorService.submit(() -> caller.call()); 58 | futures.add(submit); 59 | } 60 | for (Future future : futures) { 61 | try { 62 | if (timeout <= 0) { 63 | results.add(future.get()); 64 | } else { 65 | results.add(future.get(timeout, TimeUnit.SECONDS)); 66 | } 67 | } catch (InterruptedException e) { 68 | results.add(null); 69 | logger.error("code-shell-invoker-error", e); 70 | } catch (ExecutionException e) { 71 | results.add(null); 72 | logger.error("code-shell-invoker-error", e); 73 | } catch (TimeoutException e) { 74 | results.add(null); 75 | logger.error("code-shell-invoker-error", e); 76 | } 77 | } 78 | return results; 79 | } 80 | 81 | public int getCorePoolSize() { 82 | return corePoolSize; 83 | } 84 | 85 | public void setCorePoolSize(int corePoolSize) { 86 | this.corePoolSize = corePoolSize; 87 | } 88 | 89 | public int getMaxPoolSize() { 90 | return maxPoolSize; 91 | } 92 | 93 | public void setMaxPoolSize(int maxPoolSize) { 94 | this.maxPoolSize = maxPoolSize; 95 | } 96 | 97 | public int getQueueSize() { 98 | return queueSize; 99 | } 100 | 101 | public void setQueueSize(int queueSize) { 102 | this.queueSize = queueSize; 103 | } 104 | 105 | public static class DataSource { 106 | private List callers; 107 | 108 | public static DataSource builder() { 109 | return new DataSource(); 110 | } 111 | 112 | public DataSource add(Caller caller) { 113 | if (callers == null) { 114 | callers = new ArrayList<>(); 115 | } 116 | callers.add(caller); 117 | return this; 118 | } 119 | 120 | public List getCallers() { 121 | return callers; 122 | } 123 | } 124 | 125 | public interface Caller { 126 | Object call(); 127 | } 128 | 129 | static class CodeShellThreadFactory implements ThreadFactory { 130 | protected static final AtomicInteger POOL_COUNTER = new AtomicInteger(1); 131 | protected final AtomicInteger mThreadCounter; 132 | protected final String mPrefix; 133 | protected final boolean mDaemon; 134 | protected final ThreadGroup mGroup; 135 | 136 | public CodeShellThreadFactory() { 137 | this("CodeShell-pool-" + POOL_COUNTER.getAndIncrement(), false); 138 | } 139 | 140 | public CodeShellThreadFactory(String prefix, boolean daemon) { 141 | this.mThreadCounter = new AtomicInteger(1); 142 | this.mPrefix = prefix + "-thread-"; 143 | this.mDaemon = daemon; 144 | SecurityManager s = System.getSecurityManager(); 145 | this.mGroup = s == null ? Thread.currentThread().getThreadGroup() : s.getThreadGroup(); 146 | } 147 | @Override 148 | public Thread newThread(Runnable runnable) { 149 | String name = this.mPrefix + this.mThreadCounter.getAndIncrement(); 150 | Thread ret = new Thread(this.mGroup, runnable, name, 0L); 151 | ret.setDaemon(this.mDaemon); 152 | return ret; 153 | } 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /biz/src/main/java/com/tianxiao/faas/biz/service/FaaSServiceCommandService.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.biz.service; 2 | 3 | import com.tianxiao.faas.biz.command.FaaSServiceSaveCommand; 4 | import com.tianxiao.faas.biz.domain.FaaSServiceDomain; 5 | import com.tianxiao.faas.biz.factory.FaaSServiceDomainFactory; 6 | import com.tianxiao.faas.biz.infrastructure.repositories.FaaSServiceRepository; 7 | import com.tianxiao.faas.common.enums.biz.FaaSServiceStatusEnum; 8 | import com.tianxiao.faas.common.exception.ParamAccessException; 9 | import com.tianxiao.faas.common.exception.biz.BizException; 10 | import com.tianxiao.faas.common.exception.biz.LockedException; 11 | import org.springframework.stereotype.Service; 12 | import org.springframework.transaction.annotation.Transactional; 13 | 14 | import javax.annotation.Resource; 15 | 16 | @Service 17 | public class FaaSServiceCommandService { 18 | @Resource 19 | private FaaSServiceRepository faaSServiceRepository; 20 | @Resource 21 | private FaaSServiceDomainFactory faaSServiceDomainFactory; 22 | 23 | public FaaSServiceDomain edit(Integer id, String modifier) { 24 | if (id == null || id <= 0) { 25 | throw new ParamAccessException("id 不能为空"); 26 | } 27 | FaaSServiceDomain faaSServiceDomain = faaSServiceRepository.get(id); 28 | if (faaSServiceDomain == null) { 29 | return null; 30 | } 31 | FaaSServiceDomain domain = faaSServiceRepository.get(faaSServiceDomain.getServiceName(), FaaSServiceStatusEnum.WRITING); 32 | if (domain != null) { 33 | if (domain.getStatus() == FaaSServiceStatusEnum.WRITING.getStatus() && !domain.getModifier().equalsIgnoreCase(modifier)) { 34 | throw new LockedException("该脚本正在被编辑", domain.getModifier()); 35 | } 36 | return domain; 37 | } 38 | faaSServiceDomain.edited(modifier); 39 | boolean save = faaSServiceRepository.save(faaSServiceDomain); 40 | if (!save) { 41 | throw new BizException("获取信息失败,请重试"); 42 | } 43 | return faaSServiceDomain; 44 | } 45 | 46 | @Transactional(rollbackFor = Throwable.class) 47 | public boolean save(FaaSServiceSaveCommand command) { 48 | if (command == null) { 49 | throw new ParamAccessException("参数不能为空"); 50 | } 51 | FaaSServiceDomain faaSServiceDomain = faaSServiceDomainFactory.build(command); 52 | if (faaSServiceDomain == null) { 53 | throw new BizException("系统异常"); 54 | } 55 | faaSServiceDomain.save(); 56 | return faaSServiceRepository.save(faaSServiceDomain); 57 | } 58 | 59 | @Transactional(rollbackFor = Throwable.class) 60 | public boolean offlinePublish(Integer id) { 61 | FaaSServiceDomain faaSServiceDomain = faaSServiceRepository.get(id); 62 | faaSServiceDomain.offlinePublish(); 63 | return faaSServiceRepository.save(faaSServiceDomain); 64 | } 65 | 66 | @Transactional(rollbackFor = Throwable.class) 67 | public boolean prePublish(Integer id) { 68 | FaaSServiceDomain faaSServiceDomain = faaSServiceRepository.get(id); 69 | if (faaSServiceDomain.getStatus() == FaaSServiceStatusEnum.PRE.getStatus()) { 70 | throw new BizException("该服务已经处于预发状态"); 71 | } 72 | faaSServiceDomain.prePublish(); 73 | FaaSServiceDomain current = faaSServiceRepository.get(faaSServiceDomain.getServiceName(), FaaSServiceStatusEnum.PRE); 74 | if (current != null) { 75 | // 把当前预发的服务,复制掉当前信息,然后将当前预发的转为线下 76 | current.copy(faaSServiceDomain); 77 | current.offlinePublish(); 78 | boolean save = faaSServiceRepository.save(current); 79 | if (!save) { 80 | return false; 81 | } 82 | } 83 | return faaSServiceRepository.save(faaSServiceDomain); 84 | } 85 | 86 | /** 87 | * 发布 88 | * 比如发布id为1 89 | * 当前如果线上没有服务,则只需要把当前的id=1的服务状态改为发布状态就ok了。 90 | * 如果线上已经存在服务了,则需要把线上的服务归档,并把id=1的服务状态改为发布状态 91 | * save方法里面已经是乐观更新了。 92 | * @param id 93 | * @return 94 | */ 95 | @Transactional(rollbackFor = Throwable.class) 96 | public boolean online(Integer id) { 97 | FaaSServiceDomain faaSServiceDomain = faaSServiceRepository.get(id); 98 | faaSServiceDomain.publish(); 99 | FaaSServiceDomain current = faaSServiceRepository.get(faaSServiceDomain.getServiceName(), FaaSServiceStatusEnum.ONLINE); 100 | if (current != null) { 101 | current.archive(); 102 | boolean save = faaSServiceRepository.save(current); 103 | if (!save) { 104 | return false; 105 | } 106 | } 107 | FaaSServiceDomain domain = new FaaSServiceDomain(); 108 | domain.copy(faaSServiceDomain); 109 | domain.setStatus(FaaSServiceStatusEnum.PRE.getStatus()); 110 | faaSServiceRepository.save(domain); 111 | return faaSServiceRepository.save(faaSServiceDomain); 112 | } 113 | 114 | /** 115 | * 回滚 116 | * 原服务归档,目标服务发布 117 | * @param id 118 | * @param toId 119 | * @return 120 | */ 121 | @Transactional(rollbackFor = Throwable.class) 122 | public boolean rollback(Integer id, Integer toId) { 123 | FaaSServiceDomain from = faaSServiceRepository.get(id); 124 | FaaSServiceDomain to = faaSServiceRepository.get(toId); 125 | from.archive(); 126 | to.publish(); 127 | boolean save = faaSServiceRepository.save(from); 128 | boolean save1 = faaSServiceRepository.save(to); 129 | return save && save1; 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /mapper/src/main/resources/mybatis/generatorConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 26 | 28 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 39 | 40 | 41 | 42 | 43 | 48 | 50 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 76 | 77 |
78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 |
91 |
92 | -------------------------------------------------------------------------------- /console/src/main/java/com/tianxiao/faas/console/web/FaaSServiceWriteController.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.console.web; 2 | 3 | import com.tianxiao.faas.biz.command.FaaSServiceSaveCommand; 4 | import com.tianxiao.faas.biz.domain.FaaSServiceDomain; 5 | import com.tianxiao.faas.biz.factory.FaaSServiceDomainFactory; 6 | import com.tianxiao.faas.biz.service.FaaSServiceCommandService; 7 | import com.tianxiao.faas.common.JSONResult; 8 | import com.tianxiao.faas.common.exception.ParamAccessException; 9 | import com.tianxiao.faas.common.exception.biz.BizException; 10 | import com.tianxiao.faas.common.exception.biz.LockedException; 11 | import org.springframework.web.bind.annotation.RequestMapping; 12 | import org.springframework.web.bind.annotation.RequestParam; 13 | import org.springframework.web.bind.annotation.RestController; 14 | 15 | import javax.annotation.Resource; 16 | 17 | @RestController 18 | public class FaaSServiceWriteController { 19 | @Resource 20 | private FaaSServiceCommandService faaSServiceCommandService; 21 | @Resource 22 | private FaaSServiceDomainFactory faaSServiceDomainFactory; 23 | 24 | 25 | @RequestMapping("/api/faas/service/edit") 26 | public String edit(@RequestParam("id")Integer id) { 27 | FaaSServiceDomain faaSServiceDomain; 28 | JSONResult result = null; 29 | try { 30 | faaSServiceDomain = faaSServiceCommandService.edit(id, "tianxiao"); 31 | result = JSONResult.Builder.builder().isSuccess(true).data(faaSServiceDomainFactory.build(faaSServiceDomain)).build(); 32 | } catch (ParamAccessException e) { 33 | result = JSONResult.Builder.builder().isSuccess(false).message(e.getMessage()).build(); 34 | } catch (BizException e) { 35 | result = JSONResult.Builder.builder().isSuccess(false).message(e.getMessage()).build(); 36 | } catch (LockedException e) { 37 | result = JSONResult.Builder.builder().isSuccess(false).message(e.getMessage()).build(); 38 | } 39 | return result.toString(); 40 | } 41 | 42 | @RequestMapping("/api/faas/service/save") 43 | public String save(FaaSServiceSaveCommand param) { 44 | JSONResult result = null; 45 | try { 46 | boolean save = faaSServiceCommandService.save(param); 47 | String tips = save ? "保存成功" : "保存失败,请刷新重试"; 48 | result =JSONResult.Builder.builder().data(save).isSuccess(save).message(tips).build(); 49 | } catch (ParamAccessException e) { 50 | result =JSONResult.Builder.builder().isSuccess(false).message(e.getMessage()).build(); 51 | } catch (BizException e) { 52 | result =JSONResult.Builder.builder().isSuccess(false).message(e.getMessage()).build(); 53 | } 54 | return result.toString(); 55 | } 56 | 57 | @RequestMapping("/api/faas/service/offline") 58 | public String offlinePublish(@RequestParam("id") Integer id) { 59 | JSONResult result = null; 60 | try { 61 | boolean success = faaSServiceCommandService.offlinePublish(id); 62 | result = JSONResult.Builder.builder().isSuccess(true).data(success).build(); 63 | } catch (ParamAccessException e) { 64 | result = JSONResult.Builder.builder().isSuccess(false).message(e.getMessage()).build(); 65 | } catch (BizException e) { 66 | result = JSONResult.Builder.builder().isSuccess(false).message(e.getMessage()).build(); 67 | } catch (LockedException e) { 68 | result = JSONResult.Builder.builder().isSuccess(false).message(e.getMessage()).build(); 69 | } 70 | return result.toString(); 71 | } 72 | 73 | @RequestMapping("/api/faas/service/publish/pre") 74 | public String prePublish(@RequestParam("id") Integer id) { 75 | JSONResult result = null; 76 | try { 77 | boolean success = faaSServiceCommandService.prePublish(id); 78 | result = JSONResult.Builder.builder().isSuccess(true).data(success).build(); 79 | } catch (ParamAccessException e) { 80 | result = JSONResult.Builder.builder().isSuccess(false).message(e.getMessage()).build(); 81 | } catch (BizException e) { 82 | result = JSONResult.Builder.builder().isSuccess(false).message(e.getMessage()).build(); 83 | } catch (LockedException e) { 84 | result = JSONResult.Builder.builder().isSuccess(false).message(e.getMessage()).build(); 85 | } 86 | return result.toString(); 87 | } 88 | 89 | @RequestMapping("/api/faas/service/publish/online") 90 | public String onlinePublish(@RequestParam("id") Integer id) { 91 | JSONResult result = null; 92 | try { 93 | boolean success = faaSServiceCommandService.online(id); 94 | result = JSONResult.Builder.builder().isSuccess(true).data(success).build(); 95 | } catch (ParamAccessException e) { 96 | result = JSONResult.Builder.builder().isSuccess(false).message(e.getMessage()).build(); 97 | } catch (BizException e) { 98 | result = JSONResult.Builder.builder().isSuccess(false).message(e.getMessage()).build(); 99 | } catch (LockedException e) { 100 | result = JSONResult.Builder.builder().isSuccess(false).message(e.getMessage()).build(); 101 | } 102 | return result.toString(); 103 | } 104 | 105 | @RequestMapping("/api/faas/service/publish/rollback") 106 | public JSONResult rollback(@RequestParam("id") Integer id, @RequestParam("toId") Integer toId) { 107 | JSONResult result = null; 108 | try { 109 | boolean success = faaSServiceCommandService.rollback(id, toId); 110 | result = JSONResult.Builder.builder().isSuccess(true).data(success).build(); 111 | } catch (ParamAccessException e) { 112 | result = JSONResult.Builder.builder().isSuccess(false).message(e.getMessage()).build(); 113 | } catch (BizException e) { 114 | result = JSONResult.Builder.builder().isSuccess(false).message(e.getMessage()).build(); 115 | } catch (LockedException e) { 116 | result = JSONResult.Builder.builder().isSuccess(false).message(e.getMessage()).build(); 117 | } 118 | return result; 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /runtime/src/main/java/com/tianxiao/faas/runtime/groovy/SimpleCompilerConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.runtime.groovy; 2 | 3 | import com.tianxiao.faas.common.asm.LoopCheckClassVisitor; 4 | 5 | import org.codehaus.groovy.control.BytecodeProcessor; 6 | import org.codehaus.groovy.control.CompilerConfiguration; 7 | import org.codehaus.groovy.control.ParserPluginFactory; 8 | import org.codehaus.groovy.control.customizers.CompilationCustomizer; 9 | import org.objectweb.asm.ClassReader; 10 | import org.objectweb.asm.ClassVisitor; 11 | import org.objectweb.asm.ClassWriter; 12 | 13 | import java.io.File; 14 | import java.io.PrintWriter; 15 | import java.util.Collections; 16 | import java.util.List; 17 | import java.util.Map; 18 | import java.util.Set; 19 | 20 | /** 21 | * 自定义扩展groovy编译配置 22 | */ 23 | public class SimpleCompilerConfiguration extends CompilerConfiguration { 24 | 25 | 26 | /** 27 | * 扩展一个字节码的后置处理器,对动态编译后的groovy代码进行字节码增强 28 | */ 29 | public SimpleCompilerConfiguration() { 30 | //super(); 31 | this.setBytecodePostprocessor(new BytecodeProcessor() { 32 | @Override 33 | public byte[] processBytecode(String name, byte[] original) { 34 | return hackByteCode(name, original); 35 | } 36 | }); 37 | } 38 | 39 | @Override 40 | public List getClasspath() { 41 | return Collections.unmodifiableList(super.getClasspath()); 42 | } 43 | 44 | @Override 45 | public List getCompilationCustomizers() { 46 | return Collections.unmodifiableList(super.getCompilationCustomizers()); 47 | } 48 | 49 | @Override 50 | public Set getDisabledGlobalASTTransformations() { 51 | return Collections.emptySet(); 52 | } 53 | 54 | @Override 55 | public Map getJointCompilationOptions() { 56 | return null; 57 | } 58 | 59 | @Override 60 | public Map getOptimizationOptions() { 61 | return Collections.unmodifiableMap(super.getOptimizationOptions()); 62 | } 63 | 64 | @Override 65 | public Set getScriptExtensions() { 66 | return Collections.unmodifiableSet(super.getScriptExtensions()); 67 | } 68 | 69 | @Override 70 | public void setBytecodePostprocessor(BytecodeProcessor bytecodePostprocessor) { 71 | super.setBytecodePostprocessor(bytecodePostprocessor); 72 | } 73 | 74 | @Override 75 | public void setClasspath(String classpath) { 76 | throw new UnsupportedOperationException(); 77 | } 78 | 79 | @Override 80 | public void setClasspathList(List parts) { 81 | throw new UnsupportedOperationException(); 82 | } 83 | 84 | @Override 85 | public CompilerConfiguration addCompilationCustomizers(CompilationCustomizer... customizers) { 86 | throw new UnsupportedOperationException(); 87 | } 88 | 89 | @Override 90 | public void setDebug(boolean debug) { 91 | throw new UnsupportedOperationException(); 92 | } 93 | 94 | @Override 95 | public void setDefaultScriptExtension(String defaultScriptExtension) { 96 | throw new UnsupportedOperationException(); 97 | } 98 | 99 | @Override 100 | public void setDisabledGlobalASTTransformations(Set disabledGlobalASTTransformations) { 101 | throw new UnsupportedOperationException(); 102 | } 103 | 104 | @Override 105 | public void setJointCompilationOptions(Map options) { 106 | throw new UnsupportedOperationException(); 107 | } 108 | 109 | @Override 110 | public void setMinimumRecompilationInterval(int time) { 111 | throw new UnsupportedOperationException(); 112 | } 113 | 114 | @Override 115 | public void setOptimizationOptions(Map options) { 116 | throw new UnsupportedOperationException(); 117 | } 118 | 119 | @Override 120 | public void setOutput(PrintWriter output) { 121 | throw new UnsupportedOperationException(); 122 | } 123 | 124 | @Override 125 | public void setParameters(boolean parameters) { 126 | throw new UnsupportedOperationException(); 127 | } 128 | 129 | @Override 130 | public void setPluginFactory(ParserPluginFactory pluginFactory) { 131 | throw new UnsupportedOperationException(); 132 | } 133 | 134 | @Override 135 | public void setRecompileGroovySource(boolean recompile) { 136 | throw new UnsupportedOperationException(); 137 | } 138 | 139 | @Override 140 | public void setScriptBaseClass(String scriptBaseClass) { 141 | throw new UnsupportedOperationException(); 142 | } 143 | 144 | @Override 145 | public void setScriptExtensions(Set scriptExtensions) { 146 | throw new UnsupportedOperationException(); 147 | } 148 | 149 | @Override 150 | public void setSourceEncoding(String encoding) { 151 | throw new UnsupportedOperationException(); 152 | } 153 | 154 | @Override 155 | public void setTargetBytecode(String version) { 156 | throw new UnsupportedOperationException(); 157 | } 158 | 159 | @Override 160 | public void setTargetDirectory(File directory) { 161 | throw new UnsupportedOperationException(); 162 | } 163 | 164 | @Override 165 | public void setTargetDirectory(String directory) { 166 | throw new UnsupportedOperationException(); 167 | } 168 | 169 | @Override 170 | public void setTolerance(int tolerance) { 171 | throw new UnsupportedOperationException(); 172 | } 173 | 174 | @Override 175 | public void setVerbose(boolean verbose) { 176 | throw new UnsupportedOperationException(); 177 | } 178 | 179 | @Override 180 | public void setPreviewFeatures(boolean previewFeatures) { 181 | throw new UnsupportedOperationException(); 182 | } 183 | 184 | @Override 185 | public void setWarningLevel(int level) { 186 | throw new UnsupportedOperationException(); 187 | } 188 | 189 | /** 190 | * 采用字节码增加的方法,将待测试类的字节码文件织入循环检测计数器,实现死循环检测的功能 191 | */ 192 | private byte[] hackByteCode(String name, byte[] originCode) { 193 | String me = name; 194 | // 读取原class文件二进制文件 195 | ClassReader classReader = new ClassReader(originCode); 196 | ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS); 197 | //织入循环检测计数器 198 | ClassVisitor classVisitor = new LoopCheckClassVisitor(classWriter); 199 | classReader.accept(classVisitor, ClassReader.SKIP_DEBUG); 200 | // 重新编译 201 | byte[] data = classWriter.toByteArray(); 202 | return data; 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /biz/src/main/java/com/tianxiao/faas/biz/domain/aggregate/FaaSAggregate.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.biz.domain.aggregate; 2 | 3 | import com.tianxiao.faas.biz.aspect.FaaSAspect; 4 | import com.tianxiao.faas.biz.aspect.context.FaaSAspectDefaultContext; 5 | import com.tianxiao.faas.biz.domain.FaaSServiceDomain; 6 | import com.tianxiao.faas.common.enums.biz.FaaSServiceLanguageEnum; 7 | import com.tianxiao.faas.common.enums.biz.FaaSServiceStatusEnum; 8 | import com.tianxiao.faas.common.exception.biz.BizException; 9 | import com.tianxiao.faas.common.exception.runtime.CompileException; 10 | import com.tianxiao.faas.common.exception.runtime.ExecuteException; 11 | import com.tianxiao.faas.runtime.Executor; 12 | import com.tianxiao.faas.runtime.ExecutorContext; 13 | import com.tianxiao.faas.runtime.ExecutorFactory; 14 | import org.springframework.util.CollectionUtils; 15 | import org.springframework.util.StringUtils; 16 | 17 | import java.util.List; 18 | 19 | /** 20 | * 聚合根 21 | */ 22 | public class FaaSAggregate { 23 | private final static String DEFAULT_METHOD_NAME = "execute"; 24 | /** 25 | * service 领域模型 26 | */ 27 | private FaaSServiceDomain faaSServiceDomain; 28 | 29 | /** 30 | * faaS切面集合 31 | */ 32 | private List faaSAspectList; 33 | 34 | private ExecutorFactory executorFactory; 35 | 36 | public Object execute(List params) { 37 | if (faaSServiceDomain == null || StringUtils.isEmpty(faaSServiceDomain.getScript())) { 38 | throw new BizException("FaaS script is empty"); 39 | } 40 | if (executorFactory == null) { 41 | throw new BizException("FaaS executor factory is null"); 42 | } 43 | FaaSServiceLanguageEnum languageEnum = FaaSServiceLanguageEnum.get(faaSServiceDomain.getLanguage()); 44 | if (languageEnum == null) { 45 | throw new BizException("not support the language"); 46 | } 47 | Executor executor = executorFactory.getExecutor(languageEnum.getExecutorType()); 48 | if (executor == null) { 49 | throw new BizException("not support the language"); 50 | } 51 | if (CollectionUtils.isEmpty(faaSAspectList)) { 52 | return execute(params, executor); 53 | } 54 | FaaSAspectDefaultContext context = new FaaSAspectDefaultContext(params, faaSServiceDomain); 55 | for (FaaSAspect faaSAspect : faaSAspectList) { 56 | FaaSAspect.AspectObject before = faaSAspect.before(context); 57 | if (before == null) { 58 | continue; 59 | } 60 | if (before.isReturn()) { 61 | return before.getObject(); 62 | } 63 | if (before.getThrowable() != null) { 64 | throw new BizException(before.getThrowable()); 65 | } 66 | } 67 | Object result = execute(params, executor); 68 | for (int i = faaSAspectList.size() - 1; i >= 0; i--) { 69 | FaaSAspect faaSAspect = faaSAspectList.get(i); 70 | FaaSAspect.AspectObject after = faaSAspect.after(context, result); 71 | if (after == null) { 72 | continue; 73 | } 74 | if (after.isReturn()) { 75 | return after.getObject(); 76 | } 77 | if (after.getThrowable() != null) { 78 | throw new BizException(after.getThrowable()); 79 | } 80 | if (after.getObject() != null) { 81 | result = after.getObject(); 82 | } 83 | } 84 | return result; 85 | } 86 | 87 | public void refresh() { 88 | FaaSServiceLanguageEnum languageEnum = FaaSServiceLanguageEnum.get(faaSServiceDomain.getLanguage()); 89 | if (languageEnum == null) { 90 | throw new BizException("not support the language"); 91 | } 92 | Executor executor = executorFactory.getExecutor(languageEnum.getExecutorType()); 93 | ExecutorContext executeContext = new ExecutorContext(); 94 | executeContext.setCode(faaSServiceDomain.getScript()); 95 | executeContext.setDebug(true); 96 | executeContext.setServiceName(faaSServiceDomain.getServiceName()); 97 | try { 98 | executor.compile(executeContext); 99 | } catch (CompileException e) { 100 | throw new BizException(e); 101 | } 102 | } 103 | 104 | private Object execute(List params, Executor executor) { 105 | try { 106 | ExecutorContext executeContext = new ExecutorContext(); 107 | executeContext.setCode(faaSServiceDomain.getScript()); 108 | executeContext.setMethodName(DEFAULT_METHOD_NAME); 109 | executeContext.setParams(params); 110 | int status = faaSServiceDomain.getStatus(); 111 | executeContext.setServiceName(this.faaSServiceDomain.getServiceName()); 112 | if (status != FaaSServiceStatusEnum.ONLINE.getStatus()) { 113 | executeContext.setDebug(true); 114 | } 115 | executeContext.setTimeout(faaSServiceDomain.getOverTime()); 116 | return executor.execute(executeContext); 117 | } catch (ExecuteException e) { 118 | throw new BizException(e); 119 | } 120 | } 121 | 122 | 123 | 124 | public FaaSServiceDomain getFaaSServiceDomain() { 125 | return faaSServiceDomain; 126 | } 127 | 128 | public List getFaaSAspectList() { 129 | return faaSAspectList; 130 | } 131 | 132 | public ExecutorFactory getExecutorFactory() { 133 | return executorFactory; 134 | } 135 | 136 | public static final class Builder { 137 | private FaaSServiceDomain faaSServiceDomain; 138 | private List faaSAspectList; 139 | private ExecutorFactory executorFactory; 140 | 141 | private Builder() { 142 | } 143 | 144 | public static Builder builder() { 145 | return new Builder(); 146 | } 147 | 148 | public Builder faaSServiceDomain(FaaSServiceDomain faaSServiceDomain) { 149 | this.faaSServiceDomain = faaSServiceDomain; 150 | return this; 151 | } 152 | 153 | public Builder faaSAspectList(List faaSAspectList) { 154 | this.faaSAspectList = faaSAspectList; 155 | return this; 156 | } 157 | 158 | public Builder executorFactory(ExecutorFactory executorFactory) { 159 | this.executorFactory = executorFactory; 160 | return this; 161 | } 162 | 163 | public FaaSAggregate build() { 164 | FaaSAggregate faaSAggregate = new FaaSAggregate(); 165 | faaSAggregate.executorFactory = this.executorFactory; 166 | faaSAggregate.faaSServiceDomain = this.faaSServiceDomain; 167 | faaSAggregate.faaSAspectList = this.faaSAspectList; 168 | return faaSAggregate; 169 | } 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /container/src/main/java/com/tianxiao/faas/container/processor/DubboReferenceBeanDefinitionsAfterProcessor.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.container.processor; 2 | 3 | import com.google.common.cache.Cache; 4 | import com.google.common.cache.CacheBuilder; 5 | import com.google.common.util.concurrent.Striped; 6 | import com.tianxiao.faas.common.constants.ContainerConstants; 7 | import com.tianxiao.faas.common.exception.runtime.BeanDefinitionsAfterProcessorException; 8 | import com.tianxiao.faas.common.util.StringUtils; 9 | import com.tianxiao.faas.container.annotation.DubboReference; 10 | import com.tianxiao.faas.container.bean.DubboApplicationConfig; 11 | import com.tianxiao.faas.container.invoker.DubboServiceInvoker; 12 | import com.tianxiao.faas.runtime.processor.BeanDefinitionsAfterProcessor; 13 | import org.apache.dubbo.config.ApplicationConfig; 14 | import org.apache.dubbo.config.ReferenceConfig; 15 | import org.apache.dubbo.config.RegistryConfig; 16 | import org.apache.dubbo.rpc.service.GenericService; 17 | import org.slf4j.Logger; 18 | import org.slf4j.LoggerFactory; 19 | import org.springframework.beans.factory.InitializingBean; 20 | import org.springframework.beans.factory.annotation.Autowired; 21 | import org.springframework.stereotype.Component; 22 | 23 | import java.lang.reflect.Field; 24 | import java.util.concurrent.TimeUnit; 25 | import java.util.concurrent.locks.Lock; 26 | 27 | @Component 28 | public class DubboReferenceBeanDefinitionsAfterProcessor implements BeanDefinitionsAfterProcessor, InitializingBean { 29 | private Logger logger = LoggerFactory.getLogger(DubboReferenceBeanDefinitionsAfterProcessor.class); 30 | private static final Striped striped = Striped.lazyWeakLock(127); 31 | private Cache> cache; 32 | @Autowired 33 | private DubboApplicationConfig dubboApplicationConfig; 34 | @Override 35 | public void process(Object object) throws BeanDefinitionsAfterProcessorException { 36 | if (object == null) { 37 | return; 38 | } 39 | Field[] declaredFields = object.getClass().getDeclaredFields(); 40 | if (declaredFields == null || declaredFields.length <= 0) { 41 | return; 42 | } 43 | for (Field field : declaredFields) { 44 | field.setAccessible(true); 45 | DubboReference annotation = field.getAnnotation(DubboReference.class); 46 | if (annotation != null) { 47 | String interfaceName = annotation.interfaceName(); 48 | String group = annotation.group(); 49 | if (StringUtils.isEmpty(interfaceName)) { 50 | throw new BeanDefinitionsAfterProcessorException("the dubbo reference interface name is required"); 51 | } 52 | if (StringUtils.isEmpty(group)) { 53 | throw new BeanDefinitionsAfterProcessorException("the dubbo reference group is required"); 54 | } 55 | String protocol = annotation.protocol(); 56 | String version = annotation.version(); 57 | Class type = field.getType(); 58 | if (!DubboServiceInvoker.class.equals(type)) { 59 | throw new BeanDefinitionsAfterProcessorException(String.format("the field %s, cannot use DubboReference annotation", field.getName())); 60 | } 61 | final String cacheKey = getCacheKey(interfaceName, group, version, protocol); 62 | ReferenceConfig service = cache.getIfPresent(cacheKey); 63 | 64 | GenericService genericService = null; 65 | try { 66 | // 如果service == null 则需要创建,创建需要加锁,避免多次创建影响内存资源 67 | if (service == null) { 68 | final Lock lock = striped.get(cacheKey); 69 | try { 70 | lock.lock(); 71 | service = cache.getIfPresent(cacheKey); 72 | if (service == null) { 73 | service = buildReference(annotation); 74 | cache.put(cacheKey, service); 75 | genericService = service.get(); 76 | } 77 | } finally { 78 | lock.unlock(); 79 | } 80 | } else { 81 | genericService = service.get(); 82 | } 83 | field.set(object, new DubboServiceInvoker(genericService)); 84 | } catch (Exception e) { 85 | throw new BeanDefinitionsAfterProcessorException(e); 86 | } 87 | } 88 | } 89 | } 90 | 91 | private ReferenceConfig buildReference(DubboReference annotation) { 92 | String protocol = annotation.protocol(); 93 | String version = annotation.version(); 94 | String interfaceName = annotation.interfaceName(); 95 | String group = annotation.group(); 96 | final int timeout = annotation.timeout(); 97 | ReferenceConfig reference = new ReferenceConfig<>(); 98 | if (dubboApplicationConfig != null) { 99 | final ApplicationConfig applicationConfig = dubboApplicationConfig.getApplicationConfig(); 100 | final RegistryConfig registryConfig = dubboApplicationConfig.getRegistryConfig(); 101 | reference.setApplication(applicationConfig); 102 | reference.setRegistry(registryConfig); 103 | } 104 | reference.setProtocol(protocol); 105 | reference.setInterface(interfaceName); 106 | reference.setGroup(group); 107 | reference.setTimeout(timeout); 108 | if (StringUtils.isNotEmpty(version)) { 109 | reference.setVersion(version); 110 | } 111 | // 声明为泛化接口 112 | reference.setGeneric("true"); 113 | return reference; 114 | } 115 | 116 | @Override 117 | public int order() { 118 | return 0; 119 | } 120 | 121 | private String getCacheKey(String interfaceName, String group, String version, String protocol) { 122 | StringBuilder builder = new StringBuilder(); 123 | builder.append(interfaceName) 124 | .append(ContainerConstants.UNDER_LINE) 125 | .append(group) 126 | .append(ContainerConstants.UNDER_LINE); 127 | if (StringUtils.isNotEmpty(version)) { 128 | builder.append(version); 129 | builder.append(ContainerConstants.UNDER_LINE); 130 | } 131 | builder.append(protocol); 132 | return builder.toString(); 133 | } 134 | 135 | /** 136 | * 加载缓存 137 | */ 138 | private void loadCache() { 139 | cache = CacheBuilder.newBuilder() 140 | .expireAfterAccess(5L, TimeUnit.MINUTES) 141 | // 初始化缓存数量 142 | .initialCapacity(50) 143 | // 最大缓存数量,如果接近300,则会移除最近不经常使用的bean 144 | .maximumSize(300) 145 | .build(); 146 | } 147 | 148 | @Override 149 | public void afterPropertiesSet() throws Exception { 150 | loadCache(); 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.tianxiao 8 | FaaS 9 | 1.0-SNAPSHOT 10 | 11 | runtime 12 | common 13 | container 14 | application 15 | mapper 16 | biz 17 | api 18 | console 19 | 20 | pom 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-parent 25 | 2.3.0.RELEASE 26 | 27 | 28 | 29 | 30 | UTF-8 31 | UTF-8 32 | 5.2.5.RELEASE 33 | 2.5.14 34 | 3.2.0 35 | 2.7.21 36 | 1.1.17 37 | 30.0-jre 38 | 39 | 40 | 41 | 42 | 43 | com.tianxiao 44 | api 45 | ${project.version} 46 | 47 | 48 | com.tianxiao 49 | common 50 | ${project.version} 51 | 52 | 53 | com.tianxiao 54 | runtime 55 | ${project.version} 56 | 57 | 58 | com.tianxiao 59 | container 60 | ${project.version} 61 | 62 | 63 | com.tianxiao 64 | mapper 65 | ${project.version} 66 | 67 | 68 | com.tianxiao 69 | biz 70 | ${project.version} 71 | 72 | 73 | org.codehaus.groovy 74 | groovy 75 | ${groovy.version} 76 | 77 | 78 | guava 79 | com.google.guava 80 | ${guava.version} 81 | 82 | 83 | 84 | org.apache.dubbo 85 | dubbo 86 | ${dubbo.version} 87 | 88 | 89 | org.apache.dubbo 90 | dubbo-dependencies-zookeeper 91 | ${dubbo.version} 92 | pom 93 | 94 | 95 | com.alibaba 96 | QLExpress 97 | ${qlExpress.version} 98 | 99 | 100 | org.springframework 101 | spring-context 102 | ${spring.version} 103 | 104 | 105 | org.springframework 106 | spring-jdbc 107 | ${spring.version} 108 | compile 109 | 110 | 111 | mysql 112 | mysql-connector-java 113 | 8.0.28 114 | 115 | 116 | com.alibaba 117 | druid-spring-boot-starter 118 | ${druid.version} 119 | 120 | 121 | org.springframework.boot 122 | spring-boot-starter-jdbc 123 | 124 | 125 | org.ow2.asm 126 | asm 127 | 7.1 128 | 129 | 130 | org.mybatis.spring.boot 131 | mybatis-spring-boot-starter 132 | 2.0.1 133 | 134 | 135 | org.springframework.boot 136 | spring-boot-starter-jdbc 137 | 2.4.0 138 | 139 | 140 | org.springframework.boot 141 | spring-boot-starter-webflux 142 | 2.5.12 143 | 144 | 145 | com.alibaba 146 | fastjson 147 | 1.2.83 148 | 149 | 150 | org.apache.commons 151 | commons-lang3 152 | 3.11 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | org.apache.maven.plugins 162 | maven-compiler-plugin 163 | 3.8.1 164 | 165 | 1.8 166 | 1.8 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | public 175 | aliyun nexus 176 | http://maven.aliyun.com/nexus/content/groups/public/ 177 | 178 | true 179 | 180 | 181 | 182 | 183 | 184 | 185 | public 186 | aliyun nexus 187 | http://maven.aliyun.com/nexus/content/groups/public/ 188 | 189 | true 190 | 191 | 192 | false 193 | 194 | 195 | 196 | 197 | 198 | 199 | -------------------------------------------------------------------------------- /biz/src/main/java/com/tianxiao/faas/biz/domain/FaaSServiceDomain.java: -------------------------------------------------------------------------------- 1 | package com.tianxiao.faas.biz.domain; 2 | 3 | import com.tianxiao.faas.biz.domain.event.PublishEvent; 4 | import com.tianxiao.faas.biz.infrastructure.publisher.EventPublisher; 5 | import com.tianxiao.faas.common.enums.biz.FaaSServiceLanguageEnum; 6 | import com.tianxiao.faas.common.enums.biz.FaaSServiceStatusEnum; 7 | import com.tianxiao.faas.common.exception.ParamAccessException; 8 | import com.tianxiao.faas.common.exception.biz.BizException; 9 | import com.tianxiao.faas.common.exception.biz.LockedException; 10 | import com.tianxiao.faas.common.exception.runtime.CompileException; 11 | import com.tianxiao.faas.common.util.StringUtils; 12 | import com.tianxiao.faas.runtime.Executor; 13 | import com.tianxiao.faas.runtime.ExecutorContext; 14 | import com.tianxiao.faas.runtime.ExecutorFactory; 15 | 16 | import java.io.Serializable; 17 | 18 | public class FaaSServiceDomain implements Serializable { 19 | 20 | private static final long serialVersionUID = -5740458254822011802L; 21 | 22 | private Integer id; 23 | 24 | private String serviceName; 25 | 26 | private String serviceDesc; 27 | 28 | private int overTime; 29 | 30 | private int maxQps; 31 | 32 | private String script; 33 | 34 | private int language; 35 | 36 | private String modifier; 37 | 38 | private String group; 39 | 40 | private int status; 41 | 42 | private int cacheTime; 43 | 44 | private int version; 45 | 46 | private ExecutorFactory executorFactory; 47 | 48 | private EventPublisher eventPublisher; 49 | 50 | public void edited(String modifier) { 51 | check(); 52 | if (status == FaaSServiceStatusEnum.WRITING.getStatus() && !this.modifier.equalsIgnoreCase(modifier)) { 53 | throw new LockedException("该脚本正在被编辑", this.getModifier()); 54 | } 55 | if (status == FaaSServiceStatusEnum.PRE.getStatus() || status == FaaSServiceStatusEnum.OFFLINE.getStatus() 56 | || status == FaaSServiceStatusEnum.OFFLINE.getStatus()) { 57 | this.id = null; 58 | } 59 | this.status = FaaSServiceStatusEnum.WRITING.getStatus(); 60 | this.modifier = modifier; 61 | } 62 | 63 | public boolean save() { 64 | check(); 65 | // 如果当前服务已经发布线上,则复制一份创建一份新的 66 | if (status == FaaSServiceStatusEnum.ONLINE.getStatus()) { 67 | this.id = null; 68 | } 69 | status = FaaSServiceStatusEnum.SAVE.getStatus(); 70 | return true; 71 | } 72 | 73 | /** 74 | * 线下发布 75 | * @return 76 | */ 77 | public boolean offlinePublish() { 78 | check(); 79 | publishCheck(); 80 | this.status = FaaSServiceStatusEnum.OFFLINE.getStatus(); 81 | return true; 82 | } 83 | 84 | /** 85 | * 预发发布 86 | * @return 87 | */ 88 | public boolean prePublish() { 89 | check(); 90 | publishCheck(); 91 | this.status = FaaSServiceStatusEnum.PRE.getStatus(); 92 | return true; 93 | } 94 | 95 | /** 96 | * 线上发布 97 | * @return 98 | */ 99 | public boolean publish() { 100 | check(); 101 | publishCheck(); 102 | this.status = FaaSServiceStatusEnum.ONLINE.getStatus(); 103 | eventPublisher.publishEvent(new PublishEvent(this)); 104 | return true; 105 | } 106 | 107 | /** 108 | * 归档 109 | * @return 110 | */ 111 | public boolean archive() { 112 | check(); 113 | if (status != FaaSServiceStatusEnum.ONLINE.getStatus()) { 114 | throw new BizException("该状态下不能归档"); 115 | } 116 | this.status = FaaSServiceStatusEnum.HISTORY_VERSION.getStatus(); 117 | return true; 118 | } 119 | 120 | public Integer getId() { 121 | return id; 122 | } 123 | 124 | public String getServiceName() { 125 | return serviceName; 126 | } 127 | 128 | public String getServiceDesc() { 129 | return serviceDesc; 130 | } 131 | 132 | public int getOverTime() { 133 | return overTime; 134 | } 135 | 136 | public int getMaxQps() { 137 | return maxQps; 138 | } 139 | 140 | public String getScript() { 141 | return script; 142 | } 143 | 144 | public int getLanguage() { 145 | return language; 146 | } 147 | 148 | public String getModifier() { 149 | return modifier; 150 | } 151 | 152 | public String getGroup() { 153 | return group; 154 | } 155 | 156 | public int getStatus() { 157 | return status; 158 | } 159 | 160 | public int getCacheTime() { 161 | return cacheTime; 162 | } 163 | 164 | public void setId(Integer id) { 165 | this.id = id; 166 | } 167 | 168 | public void setServiceName(String serviceName) { 169 | this.serviceName = serviceName; 170 | } 171 | 172 | public void setServiceDesc(String serviceDesc) { 173 | this.serviceDesc = serviceDesc; 174 | } 175 | 176 | public void setOverTime(int overTime) { 177 | this.overTime = overTime; 178 | } 179 | 180 | public void setMaxQps(int maxQps) { 181 | this.maxQps = maxQps; 182 | } 183 | 184 | public void setScript(String script) { 185 | this.script = script; 186 | } 187 | 188 | public void setLanguage(int language) { 189 | this.language = language; 190 | } 191 | 192 | public void setModifier(String modifier) { 193 | this.modifier = modifier; 194 | } 195 | 196 | public void setGroup(String group) { 197 | this.group = group; 198 | } 199 | 200 | public void setStatus(int status) { 201 | this.status = status; 202 | } 203 | 204 | public void setCacheTime(int cacheTime) { 205 | this.cacheTime = cacheTime; 206 | } 207 | 208 | public int getVersion() { 209 | return version; 210 | } 211 | 212 | public void setVersion(int version) { 213 | this.version = version; 214 | } 215 | 216 | public void copy(FaaSServiceDomain domain) { 217 | this.cacheTime = domain.getCacheTime(); 218 | this.group = domain.getGroup(); 219 | this.language = domain.getLanguage(); 220 | this.maxQps = domain.getMaxQps(); 221 | this.modifier = domain.getModifier(); 222 | this.overTime = domain.getOverTime(); 223 | this.script = domain.getScript(); 224 | this.serviceDesc = domain.getServiceDesc(); 225 | this.serviceName = domain.getServiceName(); 226 | this.status = domain.getStatus(); 227 | this.id = domain.getId(); 228 | this.version = 0; 229 | } 230 | 231 | /** 232 | * 发布检查 233 | */ 234 | private void publishCheck() { 235 | if (!FaaSServiceStatusEnum.canModified(status)) { 236 | throw new BizException("该状态下不能修改/发布"); 237 | } 238 | if (executorFactory == null) { 239 | throw new ParamAccessException("执行器工厂为空,请检查FaaS领域模型构造是否异常"); 240 | } 241 | FaaSServiceLanguageEnum languageEnum = FaaSServiceLanguageEnum.get(language); 242 | Executor executor = executorFactory.getExecutor(languageEnum.getExecutorType()); 243 | try { 244 | ExecutorContext executorContext = new ExecutorContext(); 245 | executorContext.setDebug(true); 246 | executorContext.setCode(script); 247 | executor.compile(executorContext); 248 | } catch (CompileException e) { 249 | throw new BizException(e); 250 | } 251 | } 252 | 253 | /** 254 | * 参数检查 255 | */ 256 | private void check() { 257 | if (StringUtils.isEmpty(serviceDesc)) { 258 | throw new BizException("服务描述不能为空"); 259 | } 260 | if (StringUtils.isEmpty(serviceName)) { 261 | throw new BizException("服务名称不能为空"); 262 | } 263 | if (StringUtils.isEmpty(script)) { 264 | throw new BizException("脚本内容不能为空"); 265 | } 266 | if (StringUtils.isEmpty(modifier)) { 267 | throw new BizException("服务修改者不能为空"); 268 | } 269 | FaaSServiceLanguageEnum languageEnum = FaaSServiceLanguageEnum.get(language); 270 | if (languageEnum == null) { 271 | throw new BizException("暂不支持该语言"); 272 | } 273 | } 274 | 275 | public static final class Builder { 276 | private Integer id; 277 | private String serviceName; 278 | private String serviceDesc; 279 | private int overTime; 280 | private int maxQps; 281 | private String script; 282 | private int language; 283 | private String modifier; 284 | private String group; 285 | private int status; 286 | private int cacheTime; 287 | private int version; 288 | private ExecutorFactory executorFactory; 289 | private EventPublisher eventPublisher; 290 | 291 | private Builder() { 292 | } 293 | 294 | public static Builder builder() { 295 | return new Builder(); 296 | } 297 | 298 | public Builder id(Integer id) { 299 | this.id = id; 300 | return this; 301 | } 302 | 303 | public Builder serviceName(String serviceName) { 304 | this.serviceName = serviceName; 305 | return this; 306 | } 307 | 308 | public Builder serviceDesc(String serviceDesc) { 309 | this.serviceDesc = serviceDesc; 310 | return this; 311 | } 312 | 313 | public Builder overTime(int overTime) { 314 | this.overTime = overTime; 315 | return this; 316 | } 317 | 318 | public Builder maxQps(int maxQps) { 319 | this.maxQps = maxQps; 320 | return this; 321 | } 322 | 323 | public Builder script(String script) { 324 | this.script = script; 325 | return this; 326 | } 327 | 328 | public Builder language(int language) { 329 | this.language = language; 330 | return this; 331 | } 332 | 333 | public Builder modifier(String modifier) { 334 | this.modifier = modifier; 335 | return this; 336 | } 337 | 338 | public Builder group(String group) { 339 | this.group = group; 340 | return this; 341 | } 342 | 343 | public Builder status(int status) { 344 | this.status = status; 345 | return this; 346 | } 347 | 348 | public Builder cacheTime(int cacheTime) { 349 | this.cacheTime = cacheTime; 350 | return this; 351 | } 352 | 353 | public Builder version(int version) { 354 | this.version = version; 355 | return this; 356 | } 357 | 358 | public Builder executorFactory(ExecutorFactory executorFactory) { 359 | this.executorFactory = executorFactory; 360 | return this; 361 | } 362 | 363 | public Builder eventPublisher(EventPublisher eventPublisher) { 364 | this.eventPublisher = eventPublisher; 365 | return this; 366 | } 367 | 368 | public FaaSServiceDomain build() { 369 | FaaSServiceDomain faaSServiceDomain = new FaaSServiceDomain(); 370 | faaSServiceDomain.setId(id); 371 | faaSServiceDomain.setServiceName(serviceName); 372 | faaSServiceDomain.setServiceDesc(serviceDesc); 373 | faaSServiceDomain.setOverTime(overTime); 374 | faaSServiceDomain.setMaxQps(maxQps); 375 | faaSServiceDomain.setScript(script); 376 | faaSServiceDomain.setLanguage(language); 377 | faaSServiceDomain.setModifier(modifier); 378 | faaSServiceDomain.setGroup(group); 379 | faaSServiceDomain.setStatus(status); 380 | faaSServiceDomain.setCacheTime(cacheTime); 381 | faaSServiceDomain.setVersion(version); 382 | faaSServiceDomain.eventPublisher = this.eventPublisher; 383 | faaSServiceDomain.executorFactory = this.executorFactory; 384 | return faaSServiceDomain; 385 | } 386 | } 387 | } 388 | --------------------------------------------------------------------------------