j-easy / easy-rules

The simple, stupid rules engine for Java
https://github.com/j-easy/easy-rules/wiki
MIT License
4.83k stars 1.04k forks source link

通过注解(即生成代理类)形式接入,多线程共享Rules时存在线程安全问题 #411

Open 1ufy opened 1 year ago

1ufy commented 1 year ago

java.util.ConcurrentModificationException: null at java.util.TreeMap$PrivateEntryIterator.nextEntry(TreeMap.java:1207) at java.util.TreeMap$KeyIterator.next(TreeMap.java:1261) at org.jeasy.rules.core.RuleProxy.appendActionMethodsNames(RuleProxy.java:353) at org.jeasy.rules.core.RuleProxy.getRuleDescription(RuleProxy.java:334) at org.jeasy.rules.core.RuleProxy.invoke(RuleProxy.java:101) at com.sun.proxy.$Proxy160.getDescription(Unknown Source) at org.jeasy.rules.core.DefaultRulesEngine.log(DefaultRulesEngine.java:146) at org.jeasy.rules.core.DefaultRulesEngine.doFire(DefaultRulesEngine.java:80) at org.jeasy.rules.core.DefaultRulesEngine.fire(DefaultRulesEngine.java:70)

private Set getActionMethodBeans() { if (this.actionMethods == null) { this.actionMethods = new TreeSet<>(); Method[] methods = getMethods(); for (Method method : methods) { if (method.isAnnotationPresent(Action.class)) { Action actionAnnotation = method.getAnnotation(Action.class); int order = actionAnnotation.order(); this.actionMethods.add(new ActionMethodOrderBean(method, order)); } } } return this.actionMethods; }

内部actionMethods对象是TreeSet非线程安全,多线程并发时,遍历时会抛出ConcurrentModificationException

解决思路:

  1. 不共享Rules对象,缺点会生成重复代理对象
  2. 采用继承非注解的形式接入
zpshowhan commented 1 month ago

RuleProxy创建的时候优先把rule的元数据获取到并赋值就行了 RuleProxy#RuleProxy() ` private RuleProxy(final Object target) { this.target = target; // load meta data this.init(); } /**