spring case中的单例作用域bean的问题

xpcnnkqh  于 2023-03-22  发布在  Spring
关注(0)|答案(1)|浏览(84)

我有一个Sping Boot 项目,在其中我实现了责任链模式。我创建了多个服务类的链。每个服务的范围都是Singleton。现在我有2个线程正在访问单例bean,然后在这种情况下,一个线程所做的修改会影响其他线程在同一个bean上工作。我尝试将bean范围作为请求,但它不起作用。

TransactionChainContext -定义链

@Service 
public class TransactionChainContext {

@Autowired
TransactionChain validationChainOne;

@Autowired
TransactionChain validationChainTwo;

@Autowired
TransactionChain validationChainThree;

@Autowired
TransactionChain validationChainFour;

@Autowired
TransactionChain validationChainFive;

/* Execute by Thread 1 */
 public void saveTransactionInChain() {                   
    validationChainOne.nextChain(validationChainTwo);
    validationChainTwo.nextChain(validationChainThree);
    validationChainThree.nextChain(validationChainFour);
    validationChainFour.nextChain(null);

    validationChainOne.processChain();
}

/* Execute by Thread 2 but it changes the chaing for thread 1 as well */

 public void saveChainTwo() {                     
    validationChainOne.nextChain(validationChainFour);
    validationChainFour.nextChain(validationChainFive);
    validationChainFive.nextChain(null);

    validationChainOne.processChain();
}

}

TransactionChain接口

public interface TransactionChain {

void nextChain(TransactionChain transactionChain);

void processChain();

}

验证类

@Service
public class ValidationChainOne implements TransactionChain {

TransactionChain nextTransactionChain;


@Override
public void nextChain(TransactionChain transactionChain) {
    this.nextTransactionChain = transactionChain;
}

@Override
public void processChain()  {
    // some business logic
}

}
"我所尝试的"
为了确保两个线程不会相互影响,我将bean范围作为request

@Scope(value = "request",  proxyMode = ScopedProxyMode.TARGET_CLASS)

但出现以下错误

'scopedTarget.ValidationChainOne': Scope 'request' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:368)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
    at org.springframework.aop.target.SimpleBeanTargetSource.getTarget(SimpleBeanTargetSource.java:35)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:673)
xxb16uws

xxb16uws1#

就我个人而言,我会从TransactionChain中删除nextChain(...)方法,这样它是不可变的,因此是线程安全的。

public class ChainProcessor {
   private TransactionChain[] steps;
   public ChainProcessor(TransactionChain... steps) { 
      this.steps = steps;
   }
   public void process(ChainContext context) { 
      Arrays.stream(steps).forEach(step -> step.processChain(context));
   }
}
/**
 * This context class only required if you need to pass state from one step to another
 */
public class ChainContext {
   public void setValue(String name, Object value) { ... }
   public <T> T getValue(String name, Class<T> type) { ... }
}
public interface TransactionChain {
   void processChain(ChainContext context);
}
@Service 
public class TransactionChainContext {

   @Autowired
   TransactionChain validationChainOne;

   @Autowired
   TransactionChain validationChainTwo;

   @Autowired
   TransactionChain validationChainThree;
   
   private ChainProcessor cp1;
   private ChainProcessor cp2;

   @AfterPropertiesSet
   public void afterPropertiesSet() {
      cp1 = new ChainProcessor(validationChainOne, validationChainTwo, validationChainThree);
      cp2 = new ChainProcessor(validationChainThree, validationChainTwo, validationChainOne);
   }

   public void saveChainOne() { 
      cp1.process(new ChainContext());
   }

   public void saveChainTwo() {                     
      cp2.process(new ChainContext());
   }
}

我个人讨厌@Autowired@AfterPropertiesSet,而且从来没有使用过它们。我更喜欢最终成员变量和构造函数注入。

相关问题