mirror of
https://gitee.com/dromara/liteFlow.git
synced 2026-05-15 04:22:09 +08:00
feature #I4UPWG 模块架构调整,支持非Spring的项目使用
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
package com.yomahub.liteflow.annotation;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* LiteFlow的组件标识注解
|
||||
*
|
||||
* @author Bryan.Zhang
|
||||
* @since 2.6.0
|
||||
*/
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Inherited
|
||||
@Component
|
||||
public @interface LiteflowComponent {
|
||||
|
||||
@AliasFor(annotation = Component.class, attribute = "value")
|
||||
String value() default "";
|
||||
|
||||
@AliasFor(annotation = Component.class, attribute = "value")
|
||||
String id() default "";
|
||||
|
||||
String name() default "";
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package com.yomahub.liteflow.spi.spring;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import com.yomahub.liteflow.spi.ContextAware;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.GenericBeanDefinition;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
|
||||
/**
|
||||
* 基于代码形式的spring上下文工具类
|
||||
* @author Bryan.Zhang
|
||||
*/
|
||||
public class SpringAware implements ApplicationContextAware, ContextAware {
|
||||
|
||||
private static ApplicationContext applicationContext = null;
|
||||
|
||||
public SpringAware() {
|
||||
}
|
||||
|
||||
public void setApplicationContext(ApplicationContext ac) throws BeansException {
|
||||
applicationContext = ac;
|
||||
}
|
||||
|
||||
public static ApplicationContext getApplicationContext() {
|
||||
return applicationContext;
|
||||
}
|
||||
|
||||
public <T> T getBean(String name) {
|
||||
try{
|
||||
T t = (T) applicationContext.getBean(name);
|
||||
return t;
|
||||
}catch (Exception e){
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public <T> T getBean(Class<T> clazz) {
|
||||
try{
|
||||
T t = applicationContext.getBean(clazz);
|
||||
return t;
|
||||
}catch (Exception e){
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public <T> T registerBean(String beanName, Class<T> c) {
|
||||
try{
|
||||
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory)applicationContext.getAutowireCapableBeanFactory();
|
||||
BeanDefinition beanDefinition = new GenericBeanDefinition();
|
||||
beanDefinition.setBeanClassName(c.getName());
|
||||
beanFactory.registerBeanDefinition(beanName, beanDefinition);
|
||||
return getBean(beanName);
|
||||
}catch (Exception e){
|
||||
return ReflectUtil.newInstance(c);
|
||||
}
|
||||
}
|
||||
|
||||
public <T> T registerBean(Class<T> c) {
|
||||
return registerBean(c.getName(), c);
|
||||
}
|
||||
|
||||
public <T> T registerOrGet(String beanName, Class<T> clazz) {
|
||||
if (ObjectUtil.isNull(applicationContext)){
|
||||
return null;
|
||||
}
|
||||
T t = getBean(clazz);
|
||||
if (ObjectUtil.isNull(t)) {
|
||||
t = registerBean(beanName, clazz);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int priority() {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.yomahub.liteflow.spi.spring;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.yomahub.liteflow.entity.data.Slot;
|
||||
import com.yomahub.liteflow.spi.CmpAroundAspect;
|
||||
import com.yomahub.liteflow.spring.ComponentScanner;
|
||||
|
||||
/**
|
||||
* Spring环境全局组件切面实现
|
||||
* @author Bryan.Zhang
|
||||
* @since 2.6.11
|
||||
*/
|
||||
public class SpringCmpAroundAspect implements CmpAroundAspect {
|
||||
@Override
|
||||
public void beforeProcess(String nodeId, Slot slot) {
|
||||
if (ObjectUtil.isNotNull(ComponentScanner.cmpAroundAspect)) {
|
||||
ComponentScanner.cmpAroundAspect.beforeProcess(nodeId, slot);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterProcess(String nodeId, Slot slot) {
|
||||
if (ObjectUtil.isNotNull(ComponentScanner.cmpAroundAspect)) {
|
||||
ComponentScanner.cmpAroundAspect.afterProcess(nodeId, slot);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int priority() {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.yomahub.liteflow.spi.spring;
|
||||
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.flow.FlowBus;
|
||||
import com.yomahub.liteflow.spi.ContextCmpInit;
|
||||
import com.yomahub.liteflow.spring.ComponentScanner;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Spring环境容器上下文组件初始化实现
|
||||
* @author Bryan.Zhang
|
||||
* @since 2.6.11
|
||||
*/
|
||||
public class SpringContextCmpInit implements ContextCmpInit {
|
||||
@Override
|
||||
public void initCmp() {
|
||||
for (Map.Entry<String, NodeComponent> componentEntry : ComponentScanner.nodeComponentMap.entrySet()) {
|
||||
if (!FlowBus.containNode(componentEntry.getKey())) {
|
||||
FlowBus.addSpringScanNode(componentEntry.getKey(), componentEntry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int priority() {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.yomahub.liteflow.spi.spring;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.spi.LiteflowComponentSupport;
|
||||
|
||||
/**
|
||||
* spring环境LiteflowComponent注解的处理器
|
||||
* @author Bryan.Zhang
|
||||
* @since 2.6.11
|
||||
*/
|
||||
public class SpringLiteflowComponentSupport implements LiteflowComponentSupport {
|
||||
@Override
|
||||
public String getCmpName(NodeComponent nodeComponent) {
|
||||
//判断NodeComponent是否是标识了@LiteflowComponent的标注
|
||||
//如果标注了,那么要从中取到name字段
|
||||
LiteflowComponent liteflowComponent = nodeComponent.getClass().getAnnotation(LiteflowComponent.class);
|
||||
if (ObjectUtil.isNotNull(liteflowComponent)) {
|
||||
return liteflowComponent.name();
|
||||
}else{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int priority() {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package com.yomahub.liteflow.spi.spring;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.yomahub.liteflow.exception.ConfigErrorException;
|
||||
import com.yomahub.liteflow.spi.PathContentParser;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class SpringPathContentParser implements PathContentParser {
|
||||
@Override
|
||||
public List<String> parseContent(List<String> pathList) throws Exception {
|
||||
if(CollectionUtil.isEmpty(pathList)){
|
||||
throw new ConfigErrorException("rule source must not be null");
|
||||
}
|
||||
|
||||
List<Resource> allResource = new ArrayList<>();
|
||||
for (String path : pathList) {
|
||||
String locationPattern;
|
||||
|
||||
//如果path是绝对路径且这个文件存在时,我们认为这是一个本地文件路径,而并非classpath路径
|
||||
if (FileUtil.isAbsolutePath(path) && FileUtil.isFile(path)){
|
||||
locationPattern = ResourceUtils.FILE_URL_PREFIX + path;
|
||||
} else {
|
||||
if (!path.startsWith(ResourceUtils.CLASSPATH_URL_PREFIX)) {
|
||||
locationPattern = ResourceUtils.CLASSPATH_URL_PREFIX + path;
|
||||
}else{
|
||||
locationPattern = path;
|
||||
}
|
||||
}
|
||||
|
||||
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
|
||||
Resource[] resources = resolver.getResources(locationPattern);
|
||||
if (ArrayUtil.isEmpty(resources)) {
|
||||
throw new ConfigErrorException("config error,please check rule source property");
|
||||
}
|
||||
allResource.addAll(ListUtil.toList(resources));
|
||||
}
|
||||
|
||||
//如果有多个资源,检查资源都是同一个类型,如果出现不同类型的配置,则抛出错误提示
|
||||
Set<String> fileTypeSet = new HashSet<>();
|
||||
allResource.forEach(resource -> fileTypeSet.add(FileUtil.extName(resource.getFilename())));
|
||||
if (fileTypeSet.size() != 1) {
|
||||
throw new ConfigErrorException("config error,please use the same type of configuration");
|
||||
}
|
||||
|
||||
//转换成内容List
|
||||
List<String> contentList = new ArrayList<>();
|
||||
for (Resource resource : allResource) {
|
||||
String content = IoUtil.read(resource.getInputStream(), CharsetUtil.CHARSET_UTF_8);
|
||||
if (StrUtil.isNotBlank(content)){
|
||||
contentList.add(content);
|
||||
}
|
||||
}
|
||||
|
||||
return contentList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int priority() {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* <p>Title: liteflow</p>
|
||||
* <p>Description: 轻量级的组件式流程框架</p>
|
||||
*
|
||||
* @author Bryan.Zhang
|
||||
* @email weenyc31@163.com
|
||||
* @Date 2020/4/1
|
||||
*/
|
||||
package com.yomahub.liteflow.spring;
|
||||
|
||||
import com.yomahub.liteflow.aop.ICmpAroundAspect;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.property.LiteflowConfig;
|
||||
import com.yomahub.liteflow.util.LOGOPrinter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 组件扫描类,只要是NodeComponent的实现类,都可以被这个扫描器扫到
|
||||
* @author Bryan.Zhang
|
||||
*/
|
||||
public class ComponentScanner implements BeanPostProcessor {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ComponentScanner.class);
|
||||
|
||||
public static Map<String, NodeComponent> nodeComponentMap = new HashMap<>();
|
||||
|
||||
private LiteflowConfig liteflowConfig;
|
||||
|
||||
public static ICmpAroundAspect cmpAroundAspect;
|
||||
|
||||
public ComponentScanner() {
|
||||
LOGOPrinter.print();
|
||||
}
|
||||
|
||||
public ComponentScanner(LiteflowConfig liteflowConfig) {
|
||||
this.liteflowConfig = liteflowConfig;
|
||||
if(liteflowConfig.getPrintBanner()){
|
||||
// 打印liteflow的LOGO
|
||||
LOGOPrinter.print();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
Class clazz = bean.getClass();
|
||||
// 组件的扫描发现,扫到之后缓存到类属性map中
|
||||
if (NodeComponent.class.isAssignableFrom(clazz)) {
|
||||
LOG.info("component[{}] has been found", beanName);
|
||||
NodeComponent nodeComponent = (NodeComponent) bean;
|
||||
nodeComponentMap.put(beanName, nodeComponent);
|
||||
}
|
||||
|
||||
// 组件Aop的实现类加载
|
||||
if (ICmpAroundAspect.class.isAssignableFrom(clazz)) {
|
||||
LOG.info("component aspect implement[{}] has been found", beanName);
|
||||
cmpAroundAspect = (ICmpAroundAspect) bean;
|
||||
}
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
//用于清楚spring上下文扫描到的组件实体
|
||||
public static void cleanCache() {
|
||||
nodeComponentMap.clear();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user