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.util.ReflectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.yomahub.liteflow.annotation.LiteflowMethod;
|
||||
import com.yomahub.liteflow.core.proxy.DeclWarpBean;
|
||||
import com.yomahub.liteflow.log.LFLog;
|
||||
import com.yomahub.liteflow.log.LFLoggerManager;
|
||||
import com.yomahub.liteflow.spi.holder.DeclComponentParserHolder;
|
||||
import org.apache.commons.lang3.tuple.Triple;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
@@ -17,7 +19,7 @@ import org.springframework.beans.factory.support.*;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
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();
|
||||
|
||||
Arrays.stream(beanDefinitionNames).filter(beanName -> {
|
||||
BeanDefinition beanDefinition = defaultListableBeanFactory.getMergedBeanDefinition(beanName);
|
||||
Class<?> rawClass = getRawClassFromBeanDefinition(beanDefinition);
|
||||
if (rawClass == null){
|
||||
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);
|
||||
});
|
||||
});
|
||||
Arrays.stream(beanDefinitionNames)
|
||||
.map(beanName -> combineAsTriple(beanName, defaultListableBeanFactory))
|
||||
.filter(this::hasLiteflowMethodAnnotation)
|
||||
.forEach(triple -> splitAndRegisterNewBeanDefinition(triple, defaultListableBeanFactory));
|
||||
}
|
||||
|
||||
@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");
|
||||
if (method != null){
|
||||
if (method != null) {
|
||||
Object resolvableType = ReflectUtil.invoke(beanDefinition, method);
|
||||
return ReflectUtil.invoke(resolvableType, "getRawClass");
|
||||
}else{
|
||||
return ReflectUtil.invoke(beanDefinition, "getTargetType");
|
||||
res = ReflectUtil.invoke(resolvableType, "getRawClass");
|
||||
}
|
||||
}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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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