Spring Security Inserting Acls:ConcurrentModificationException

时间:2013-09-21 13:38:25

标签: java spring spring-security

我正在尝试使用spring acl。您可以在下面看到我如何尝试在MutableAcl中插入新条目。它有效,只要我只添加一个 一次。但是如果我尝试添加多个权限(例如READ,WRITE),那么我会得到一个ConcurrentModificationException,请参阅下面的堆栈跟踪)。所以似乎存在并发问题,到目前为止我一直无法确定如何防止它。出于测试目的,我添加了一个Thread.sleep(1000);在mutableAclService.updateAcl(acl)下面;突然,打电话和瞧瞧 我可以添加多个权限,所以这显然是关于MutableAclService或我使用它的问题。有什么想法吗?

问候,Nanoquack。

插入ACL的代码:     @Autowired     private MutableAclService mutableAclService;

public void addPermission(Object entity, Serializable identifier, Sid recipient, Permission permission) {
    MutableAcl acl;
    ObjectIdentity oid = new ObjectIdentityImpl(entity.getClass(), identifier);
    try {
        acl = (MutableAcl) mutableAclService.readAclById(oid);
    } catch (NotFoundException e) {
        acl = (MutableAcl) mutableAclService.createAcl(oid);
    }
    acl.insertAce(acl.getEntries().size(), permission, recipient, true);
    mutableAclService.updateAcl(acl);
    log.debug("Added permission. Entity: " + entity + " Recipient: " + recipient + " Permission: " + permission);
}
尝试插入多个ACL时

堆栈跟踪:

25565 [acl%0043ache.data] ERROR net.sf.ehcache.store.disk.DiskStorageFactory - Disk Write of org.springframework.security.acls.domain.ObjectIdentityImpl[Type: com.coderunner.caliope.module.caliope.model.Page; Identifier: 0] failed:
net.sf.ehcache.CacheException: Failed to serialize element due to ConcurrentModificationException. This is frequently the result of inappropriately sharing thread unsafe object (eg. ArrayList, HashMap, etc) between threads
    at net.sf.ehcache.store.disk.DiskStorageFactory.serializeElement(DiskStorageFactory.java:401)
    at net.sf.ehcache.store.disk.DiskStorageFactory.write(DiskStorageFactory.java:381)
    at net.sf.ehcache.store.disk.DiskStorageFactory$DiskWriteTask.call(DiskStorageFactory.java:473)
    at net.sf.ehcache.store.disk.DiskStorageFactory$PersistentDiskWriteTask.call(DiskStorageFactory.java:1067)
    at net.sf.ehcache.store.disk.DiskStorageFactory$PersistentDiskWriteTask.call(DiskStorageFactory.java:1051)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
    at java.util.concurrent.FutureTask.run(FutureTask.java:166)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:178)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:292)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:724)
Caused by: java.util.ConcurrentModificationException
    at java.util.ArrayList.writeObject(ArrayList.java:713)
    at sun.reflect.GeneratedMethodAccessor40.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:988)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1493)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1429)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1175)
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1541)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1506)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1429)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1175)
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1541)
    at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:439)
Hibernate: delete from acl_entry where acl_object_identity=?
    at net.sf.ehcache.Element.writeObject(Element.java:851)
    at sun.reflect.GeneratedMethodAccessor39.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:988)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1493)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1429)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1175)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:347)
    at net.sf.ehcache.util.MemoryEfficientByteArrayOutputStream.serialize(MemoryEfficientByteArrayOutputStream.java:97)
    at net.sf.ehcache.store.disk.DiskStorageFactory.serializeElement(DiskStorageFactory.java:399)
    ... 11 more

Spring ACL配置:                                                                                                             ROLE_ADMINISTRATOR                                                                                                     

  <bean id="aclService"
    class="org.springframework.security.acls.jdbc.JdbcMutableAclService">
    <constructor-arg ref="dataSource" />
    <constructor-arg ref="lookupStrategy" />
    <constructor-arg ref="aclCache" />
    <property name="classIdentityQuery" value="SELECT @@IDENTITY" />
    <property name="sidIdentityQuery" value="SELECT @@IDENTITY" />
  </bean>
  <bean id="expressionHandler"
    class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
    <property name="permissionEvaluator" ref="permissionEvaluator" />
    <property name="permissionCacheOptimizer">
      <bean
        class="org.springframework.security.acls.AclPermissionCacheOptimizer">
        <constructor-arg ref="aclService" />
      </bean>
    </property>
  </bean>

  <bean id="permissionEvaluator"
    class="org.springframework.security.acls.AclPermissionEvaluator">
    <constructor-arg ref="aclService" />
  </bean>

  <bean id="webexpressionHandler"
    class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler" />

  <bean id="aclCache"
    class="org.springframework.security.acls.domain.EhCacheBasedAclCache">
    <constructor-arg>
      <bean class="org.springframework.cache.ehcache.EhCacheFactoryBean">
        <property name="cacheManager">
          <bean
            class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" />
        </property>
        <property name="cacheName" value="aclCache" />
      </bean>
    </constructor-arg>
  </bean>

1 个答案:

答案 0 :(得分:3)

显然你正在使用基于Ehcache的AclCache(MutableAclService使用它),而且Ehcaches磁盘存储似乎有并发问题。

您的Ehcache配置如何?您是否尝试过使用内存存储(而非磁盘存储)?