mirror of
https://gitee.com/dromara/liteFlow.git
synced 2026-05-14 12:12:08 +08:00
bug #ICO23A 修复设置AbstractBeanFactory的cacheMetadata为false时LF无法正确获取rawClass的问题
This commit is contained in:
@@ -2,11 +2,13 @@ package com.yomahub.liteflow.spring;
|
|||||||
|
|
||||||
import cn.hutool.core.annotation.AnnotationUtil;
|
import cn.hutool.core.annotation.AnnotationUtil;
|
||||||
import cn.hutool.core.util.ReflectUtil;
|
import cn.hutool.core.util.ReflectUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||||
import com.yomahub.liteflow.core.proxy.DeclWarpBean;
|
import com.yomahub.liteflow.core.proxy.DeclWarpBean;
|
||||||
import com.yomahub.liteflow.log.LFLog;
|
import com.yomahub.liteflow.log.LFLog;
|
||||||
import com.yomahub.liteflow.log.LFLoggerManager;
|
import com.yomahub.liteflow.log.LFLoggerManager;
|
||||||
import com.yomahub.liteflow.spi.holder.DeclComponentParserHolder;
|
import com.yomahub.liteflow.spi.holder.DeclComponentParserHolder;
|
||||||
|
import org.apache.commons.lang3.tuple.Triple;
|
||||||
import org.springframework.beans.BeansException;
|
import org.springframework.beans.BeansException;
|
||||||
import org.springframework.beans.MutablePropertyValues;
|
import org.springframework.beans.MutablePropertyValues;
|
||||||
import org.springframework.beans.factory.config.BeanDefinition;
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
@@ -17,7 +19,7 @@ import org.springframework.beans.factory.support.*;
|
|||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.function.Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 声明式类的元信息注册器
|
* 声明式类的元信息注册器
|
||||||
@@ -34,35 +36,10 @@ public class DeclBeanDefinition implements BeanDefinitionRegistryPostProcessor {
|
|||||||
|
|
||||||
String[] beanDefinitionNames = defaultListableBeanFactory.getBeanDefinitionNames();
|
String[] beanDefinitionNames = defaultListableBeanFactory.getBeanDefinitionNames();
|
||||||
|
|
||||||
Arrays.stream(beanDefinitionNames).filter(beanName -> {
|
Arrays.stream(beanDefinitionNames)
|
||||||
BeanDefinition beanDefinition = defaultListableBeanFactory.getMergedBeanDefinition(beanName);
|
.map(beanName -> combineAsTriple(beanName, defaultListableBeanFactory))
|
||||||
Class<?> rawClass = getRawClassFromBeanDefinition(beanDefinition);
|
.filter(this::hasLiteflowMethodAnnotation)
|
||||||
if (rawClass == null){
|
.forEach(triple -> splitAndRegisterNewBeanDefinition(triple, defaultListableBeanFactory));
|
||||||
return false;
|
|
||||||
}else{
|
|
||||||
return Arrays.stream(rawClass.getMethods()).anyMatch(method -> AnnotationUtil.getAnnotation(method, LiteflowMethod.class) != null);
|
|
||||||
}
|
|
||||||
}).forEach(beanName -> {
|
|
||||||
BeanDefinition beanDefinition = defaultListableBeanFactory.getMergedBeanDefinition(beanName);
|
|
||||||
Class<?> rawClass = getRawClassFromBeanDefinition(beanDefinition);
|
|
||||||
List<DeclWarpBean> declWarpBeanList = DeclComponentParserHolder.loadDeclComponentParser().parseDeclBean(rawClass);
|
|
||||||
|
|
||||||
declWarpBeanList.forEach(declWarpBean -> {
|
|
||||||
GenericBeanDefinition newBeanDefinition = new GenericBeanDefinition();
|
|
||||||
newBeanDefinition.setBeanClass(DeclWarpBean.class);
|
|
||||||
newBeanDefinition.setScope(ConfigurableBeanFactory.SCOPE_SINGLETON);
|
|
||||||
MutablePropertyValues mutablePropertyValues = new MutablePropertyValues();
|
|
||||||
mutablePropertyValues.add("nodeId", declWarpBean.getNodeId());
|
|
||||||
mutablePropertyValues.add("nodeName", declWarpBean.getNodeName());
|
|
||||||
mutablePropertyValues.add("nodeType", declWarpBean.getNodeType());
|
|
||||||
mutablePropertyValues.add("rawClazz", declWarpBean.getRawClazz());
|
|
||||||
mutablePropertyValues.add("methodWrapBeanList", declWarpBean.getMethodWrapBeanList());
|
|
||||||
mutablePropertyValues.add("rawBean", beanDefinition);
|
|
||||||
newBeanDefinition.setPropertyValues(mutablePropertyValues);
|
|
||||||
defaultListableBeanFactory.setAllowBeanDefinitionOverriding(true);
|
|
||||||
defaultListableBeanFactory.registerBeanDefinition(declWarpBean.getNodeId(), newBeanDefinition);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -70,17 +47,91 @@ public class DeclBeanDefinition implements BeanDefinitionRegistryPostProcessor {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Class<?> getRawClassFromBeanDefinition(BeanDefinition beanDefinition){
|
/**
|
||||||
try{
|
* 根据 BeanName 封装一个 triple
|
||||||
|
*
|
||||||
|
* @param beanName bean 名称
|
||||||
|
* @param defaultListableBeanFactory bean 工厂
|
||||||
|
* @return Triple, left 是 beanName, middle 是 beanName 在工厂中对应的 beanDefinition, right 是 rawClass
|
||||||
|
*/
|
||||||
|
private Triple<String, BeanDefinition, Class<?>> combineAsTriple(String beanName, DefaultListableBeanFactory defaultListableBeanFactory) {
|
||||||
|
BeanDefinition beanDefinition = defaultListableBeanFactory.getMergedBeanDefinition(beanName);
|
||||||
|
Class<?> rawClass = getRawClassFromBeanDefinition(beanDefinition);
|
||||||
|
return Triple.of(beanName, beanDefinition, rawClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断 triple 中的 rawClass 是否有 LiteflowMethod 注解修饰的方法
|
||||||
|
*
|
||||||
|
* @param triple beanName、beanDefinition、rawClass 的封装对象
|
||||||
|
* @return true 表明 triple 中的 rawClass 有 LiteflowMethod 注解修饰的方法; false 没有
|
||||||
|
*/
|
||||||
|
private boolean hasLiteflowMethodAnnotation(Triple<String, BeanDefinition, Class<?>> triple) {
|
||||||
|
Class<?> rawClass = triple.getRight();
|
||||||
|
return rawClass != null &&
|
||||||
|
Arrays.stream(rawClass.getMethods())
|
||||||
|
.anyMatch(method -> AnnotationUtil.hasAnnotation(method, LiteflowMethod.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据 triple 中的信息, 对声明式组件的 beanDefinition 进行拆分
|
||||||
|
* 拆分成新的 beanDefinition 并注册进 Spring 工厂
|
||||||
|
*
|
||||||
|
* @param triple 声明式组件原始 bean 的封装
|
||||||
|
* @param defaultListableBeanFactory bean 工厂
|
||||||
|
*/
|
||||||
|
private void splitAndRegisterNewBeanDefinition(Triple<String, BeanDefinition, Class<?>> triple, DefaultListableBeanFactory defaultListableBeanFactory) {
|
||||||
|
BeanDefinition beanDefinition = triple.getMiddle();
|
||||||
|
Class<?> rawClass = triple.getRight();
|
||||||
|
DeclComponentParserHolder.loadDeclComponentParser()
|
||||||
|
.parseDeclBean(rawClass)
|
||||||
|
.forEach(declWarpBean -> registerNewBeanDefinition(declWarpBean, beanDefinition, defaultListableBeanFactory));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerNewBeanDefinition(DeclWarpBean declWarpBean, BeanDefinition beanDefinition, DefaultListableBeanFactory defaultListableBeanFactory) {
|
||||||
|
GenericBeanDefinition newBeanDefinition = new GenericBeanDefinition();
|
||||||
|
newBeanDefinition.setBeanClass(DeclWarpBean.class);
|
||||||
|
newBeanDefinition.setScope(ConfigurableBeanFactory.SCOPE_SINGLETON);
|
||||||
|
MutablePropertyValues mutablePropertyValues = new MutablePropertyValues();
|
||||||
|
mutablePropertyValues.add("nodeId", declWarpBean.getNodeId());
|
||||||
|
mutablePropertyValues.add("nodeName", declWarpBean.getNodeName());
|
||||||
|
mutablePropertyValues.add("nodeType", declWarpBean.getNodeType());
|
||||||
|
mutablePropertyValues.add("rawClazz", declWarpBean.getRawClazz());
|
||||||
|
mutablePropertyValues.add("methodWrapBeanList", declWarpBean.getMethodWrapBeanList());
|
||||||
|
mutablePropertyValues.add("rawBean", beanDefinition);
|
||||||
|
newBeanDefinition.setPropertyValues(mutablePropertyValues);
|
||||||
|
defaultListableBeanFactory.setAllowBeanDefinitionOverriding(true);
|
||||||
|
defaultListableBeanFactory.registerBeanDefinition(declWarpBean.getNodeId(), newBeanDefinition);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Class<?> getRawClassFromBeanDefinition(BeanDefinition beanDefinition) {
|
||||||
|
try {
|
||||||
|
Class<?> res = null;
|
||||||
Method method = ReflectUtil.getMethodByName(DeclBeanDefinition.class, "getResolvableType");
|
Method method = ReflectUtil.getMethodByName(DeclBeanDefinition.class, "getResolvableType");
|
||||||
if (method != null){
|
if (method != null) {
|
||||||
Object resolvableType = ReflectUtil.invoke(beanDefinition, method);
|
Object resolvableType = ReflectUtil.invoke(beanDefinition, method);
|
||||||
return ReflectUtil.invoke(resolvableType, "getRawClass");
|
res = ReflectUtil.invoke(resolvableType, "getRawClass");
|
||||||
}else{
|
|
||||||
return ReflectUtil.invoke(beanDefinition, "getTargetType");
|
|
||||||
}
|
}
|
||||||
}catch (Exception e){
|
|
||||||
LOG.error("An error occurred while obtaining the rowClass.",e);
|
if (res != null)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
res = ReflectUtil.invoke(beanDefinition, "getTargetType");
|
||||||
|
if (res != null)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
String beanClassName = beanDefinition.getBeanClassName();
|
||||||
|
if (StrUtil.isNotBlank(beanClassName)) {
|
||||||
|
try {
|
||||||
|
res = Class.forName(beanClassName);
|
||||||
|
}
|
||||||
|
catch (ClassNotFoundException ignored) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
LOG.error("An error occurred while obtaining the rawClass.", e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package com.yomahub.liteflow.test.cacheBeanMetadata;
|
||||||
|
|
||||||
|
import org.springframework.context.ApplicationContextInitializer;
|
||||||
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
|
|
||||||
|
public class CustomSpringApplicationInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
|
||||||
|
@Override
|
||||||
|
public void initialize(ConfigurableApplicationContext applicationContext) {
|
||||||
|
applicationContext.getBeanFactory().setCacheBeanMetadata(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package com.yomahub.liteflow.test.cacheBeanMetadata;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ReflectUtil;
|
||||||
|
import com.yomahub.liteflow.core.FlowExecutor;
|
||||||
|
import com.yomahub.liteflow.spring.DeclBeanDefinition;
|
||||||
|
import com.yomahub.liteflow.test.cacheBeanMetadata.demoComponents.DemoComponent;
|
||||||
|
import com.yomahub.liteflow.test.component.FlowExecutorELSpringbootTest;
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
|
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||||
|
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.context.annotation.*;
|
||||||
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
|
import org.springframework.test.context.TestPropertySource;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
@TestPropertySource(value = "classpath:/cacheBeanMetadata/application.properties")
|
||||||
|
@SpringBootTest(classes = FlowExecutorELSpringbootTest.class)
|
||||||
|
@EnableAutoConfiguration
|
||||||
|
@ComponentScan({"com.yomahub.liteflow.test.cacheBeanMetadata.demoComponents"})
|
||||||
|
@ContextConfiguration(initializers = CustomSpringApplicationInitializer.class)
|
||||||
|
public class SpringbootCacheBeanMetadataConfigTest {
|
||||||
|
@Resource
|
||||||
|
private FlowExecutor flowExecutor;
|
||||||
|
@Resource
|
||||||
|
private ApplicationContext applicationContext;
|
||||||
|
@Resource
|
||||||
|
private DeclBeanDefinition declBeanDefinition;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() throws InvocationTargetException, IllegalAccessException {
|
||||||
|
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();
|
||||||
|
BeanDefinition demoComponent = beanFactory.getMergedBeanDefinition("demoComponent");
|
||||||
|
Method method = ReflectUtil.getMethodByName(DeclBeanDefinition.class, "getRawClassFromBeanDefinition");
|
||||||
|
method.setAccessible(true);
|
||||||
|
Object clz = method.invoke(declBeanDefinition, demoComponent);
|
||||||
|
Assertions.assertNotNull(clz);
|
||||||
|
Assertions.assertEquals(DemoComponent.class, clz);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test2() {
|
||||||
|
flowExecutor.execute2Resp("chain1");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package com.yomahub.liteflow.test.cacheBeanMetadata.demoComponents;
|
||||||
|
|
||||||
|
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||||
|
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||||
|
import com.yomahub.liteflow.core.NodeComponent;
|
||||||
|
import com.yomahub.liteflow.enums.LiteFlowMethodEnum;
|
||||||
|
import com.yomahub.liteflow.enums.NodeTypeEnum;
|
||||||
|
|
||||||
|
@LiteflowComponent
|
||||||
|
public class DemoComponent {
|
||||||
|
@LiteflowMethod(value = LiteFlowMethodEnum.PROCESS, nodeId = "demo", nodeName = "demo组件", nodeType = NodeTypeEnum.COMMON)
|
||||||
|
public void process(NodeComponent demoNode) throws Exception {
|
||||||
|
System.out.println("当前执行 processA 方法, demoNode.getClass is " + demoNode.getClass() + ", demoNode.getSuperClass is " + demoNode.getClass().getSuperclass());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
liteflow.rule-source=cacheBeanMetadata/flow.xml
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE flow PUBLIC "liteflow" "https://liteflow.cc/liteflow.dtd">
|
||||||
|
<flow>
|
||||||
|
<chain name="chain1">
|
||||||
|
THEN(demo);
|
||||||
|
</chain>
|
||||||
|
</flow>
|
||||||
Reference in New Issue
Block a user