【问题标题】:How to implement a "Lock"-Layer in exisiting service structure如何在现有服务结构中实现“锁定”层
【发布时间】:2011-02-28 14:27:32
【问题描述】:

当前情况:我有一个服务有几个典型的服务方法,如 create()、remove()、findXy()、.. 等。现在我想防止两个不同的服务调用同时,这意味着我想在第一次输入后锁定我的服务调用,因此第二个客户端(或再次相同的客户端)只会在第一个客户端完成后立即进入该方法。

出于锁定目的,我们通常使用 ReentrantLocks。他们工作得很好。但是现在我怀疑如何实现这些 ReentrantLocks,因为我不想在每一个方法中都插入它们。此外,我们的服务层已经自行定义了它们的事务上下文,这意味着,当我将它们集成到方法本身时,事务在锁定发生之前就已经开始了。

public class WorkerServiceServerImpl implements WorkerServiceRemote
{
  private static final ReentrantLock workerLock = new ReentrantLock( true );

  @Autowired
  private WorkerDao                 workerDao;

  @Override
  @Transactional
  public int createWorker( int projectId ) throws RemoteException
  {
    workerLock.lock();//NO GOOD! Transaction already started!

    try
    {
      workerDao.create( projectId );

      //Do some more stuff...
    }
    finally
    {
      workerLock.unlock();//Unlock, next request can be handled!
    }
  }

  ...
}

当然我可以在这个 WorkerServiceImpl 类之上创建一个 ServiceLayer 并将调用转发到原始服务,但是由于我有 30 个服务,我想知道是否有任何全局解决方案来解决这个问题。或者是否可以创建一个在事务开始之前触发的自己的注释?

欢迎任何想法,在此先感谢! 梅内

编辑:为简单起见,我选择 CRUD 方法。当然,这些服务调用要高级得多,可以在一次调用中调用不同的 CRUD 方法。

【问题讨论】:

    标签: java spring transactions service locking


    【解决方案1】:

    关于这个设计有几点可以说明:

    • 对服务方法应用锁的需求看起来很奇怪。如果您在并发执行服务方法时遇到一些问题,也许在访问底层数据库时通过适当的事务配置来解决这些问题会更好。

    • unlock() 必须在 finally 块内调用。

    • 如果你的服务是单例的,你使用ReentrantLock就相当于标记你的方法synchronized

    • 您可以创建一个方面以将同步应用于您的方法。见7. Aspect Oriented Programming with Spring,尤其是7.2.4.7 Advice ordering

    【讨论】:

    • 我在吹毛求疵,但如果服务不是单例,那么它的实现并不等同于将方法标记为同步,因为锁是静态的。
    • 逐点回答: 1) 有时会发生一些服务调用不允许发生,在其他调用完成之前,这就是我们要锁定它们的原因。 2)当然在finally块中,只是为了simplycity而忽略了它,将在示例中更正它。 3) 可重入锁还有其他好处,例如我们可以在一个锁中锁定更多而不是单个方法。那里可能真的不需要静态,因为我们的服务是单例的。 4)我会检查这一章,谢谢!
    • @ymene: synchronized 也不会锁定单个方法 - 它相当于syncronized(this) { ... },因此该类的所有synchronized 方法都是互斥的。
    • @axtavt 但我不会让所有方法互斥,但我希望能够自己声明的特殊方法。使用 ReentrantLock 而不是同步有什么缺点吗?
    • @ymene:不,除了冗长。
    【解决方案2】:

    由于您似乎在使用 Spring,您可以定义一个单例 LockInterceptor,并将其放入您的拦截器堆栈中,然后再进行事务拦截器。这个拦截器非常简单:

    import org.aopalliance.intercept.*;
    public class LockInterceptor implements MethodInterceptor {
    
        @Override
        public synchronized Object invoke(MethodInvocation mi) throws Throwable {
            return mi.proceed();
        }
    }
    

    【讨论】:

    • 这种可能性看起来很有趣。我会努力让它发挥作用并给予回应。
    • 我喜欢你的想法并且效果很好,但是人们认为它“太神奇了”,所以他们更喜欢独立的服务层。不过感谢您的回复!
    猜你喜欢
    • 1970-01-01
    • 2020-10-25
    • 2020-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-27
    • 1970-01-01
    相关资源
    最近更新 更多