我正在尝试使春季ACL工作。您可以在下面看到我如何尝试将新条目插入MutableAcl。只要我加一个就可以
一次。但是,如果我尝试添加多个权限(例如READ,WRITE),则会收到ConcurrentModificationException,请参见下面的堆栈跟踪。因此,似乎存在一个并发问题,到目前为止,我还无法确定如何防止它。为了进行测试,我添加了Thread.sleep(1000);在mutableAclService.updateAcl(acl)下面;电话和瞧,突然
我可以添加多个权限,因此对于MutableAclService或我的使用显然是一个问题。有任何想法吗?
问候,Nanoquack。
插入ACL的代码:
@Autowired
私有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>
最佳答案
显然您正在使用基于Ehcache的AclCache(由MutableAclService使用),并且Ehcaches磁盘存储似乎存在并发问题。
您的Ehcache配置如何?您是否尝试过使用内存存储(而不是磁盘存储)?