1

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

问候,纳米夸克。

插入 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>
4

1 回答 1

3

显然,您使用的是基于 Ehcache 的 AclCache(由 MutableAclService 使用),而 Ehcaches 磁盘存储似乎存在并发问题。

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

于 2013-09-21T20:37:22.307 回答