2012-09-26 41 views
4

我創建了一個負責通過dao與數據庫聯繫的服務。我使用@Transactional註釋來處理事務。當添加全局方法安全性名稱空間時,Spring看不到@Transactional

@Service("aclService") 
public class HibernateAclServiceImpl implements HibernateAclService{ 

private final Log logger = LogFactory.getLog(HibernateAclServiceImpl.class); 
@Autowired 
private AclObjectIdentityDao objectIdentityDao ; 
private PermissionFactory permissionFactory = new DefaultPermissionFactory(); 
@Autowired 
private AclCache aclCache; 
@Autowired 
private PermissionGrantingStrategy grantingStrategy; 
@Autowired 
private AclAuthorizationStrategy aclAuthorizationStrategy; 

private final Field fieldAces = FieldUtils.getField(AclImpl.class, "aces"); 

@Override 
@Transactional 
public List<ObjectIdentity> findChildren(ObjectIdentity parentIdentity) { 
    AclObjectIdentity aclObjectIdentity = objectIdentityDao 
      .get((Long) parentIdentity.getIdentifier()); 
    List<ObjectIdentity> list = new ArrayList<ObjectIdentity>(
      aclObjectIdentity.getChildren().size()); 
    for (AclObjectIdentity aoid : aclObjectIdentity.getChildren()) { 
     final ObjectIdentity oid = new ObjectIdentityImpl(aoid.getObjectClass().getClazz()); 
     list.add(oid); 
    } 
    return list; 
} 

@Override 
@Transactional 
public Acl readAclById(ObjectIdentity object) throws NotFoundException { 
    final Map<ObjectIdentity, Acl> objects = readAclsById(Arrays.asList(object), null); 
    return objects.get(object); 
} 

@Override 
@Transactional 
public Acl readAclById(ObjectIdentity object, List<Sid> sids) 
     throws NotFoundException { 
    Map<ObjectIdentity, Acl> objects = readAclsById(Arrays.asList(object), sids); 
    return objects.get(object); 
} 


@Override 
@Transactional 
public Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects) 
     throws NotFoundException { 
    return readAclsById(objects, null); 
} 

@Override 
public Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, 
     List<Sid> sids) throws NotFoundException { 
    Map<ObjectIdentity, Acl> result = new HashMap<ObjectIdentity, Acl>(); 
    Set<Long> objectsToLoad = new HashSet<Long>(); 

    for (int i = 0; i < objects.size(); i++) { 
     final ObjectIdentity oid = objects.get(i); 
     boolean aclFound = false; 

     if (result.containsKey(oid)) { 
      aclFound = true; 
     } 

     if (!aclFound) { 
      Acl acl = aclCache.getFromCache(oid); 

      if (acl != null) { 
       if (acl.isSidLoaded(sids)) { 
        result.put(acl.getObjectIdentity(), acl); 
        aclFound = true; 
       } else { 
        throw new IllegalStateException(
          "Error: SID-filtered element detected when implementation does not perform SID filtering " 
            + "- have you added something to the cache manually?"); 
       } 
      } 
     } 
     if (!aclFound) { 
      objectsToLoad.add((Long) oid.getIdentifier()); 
     } 
    } 

    if (objectsToLoad.size() > 0) { 
     lookupAcl(result, objectsToLoad); 
    } 
    return result; 
} 
public void lookupAcl(Map<ObjectIdentity, Acl> map, Set<Long> objects){ 
    final List<AclObjectIdentity> aoids = objectIdentityDao.getList(objects); 
    final Map<Long, Long> parents = new HashMap<Long, Long>(); 
    for(AclObjectIdentity aoid : aoids){ 
     if(aoid.isEntriesInheriting()){ 
      parents.put(aoid.getId(), aoid.getParent().getId()); 
     } 
    } 
    if(parents.size() > 0){ 
     lookupAcl(map, (Set<Long>)parents.values()); 
    } 
    for(AclObjectIdentity aoid : aoids){ 
     if(map.containsKey(aoid.getId())) 
      continue; 
     final Acl parentAcl = map.get(parents.get(aoid.getId())); 
     final Acl acl = new AclImpl(new ObjectIdentityImpl(aoid.getObjectClass().getClazz(), aoid.getId()), aoid.getId(), aclAuthorizationStrategy, grantingStrategy, parentAcl, null, aoid.isEntriesInheriting(), new PrincipalSid(aoid.getOwnerSid().getSid())); 



     List<AccessControlEntryImpl> aces = new ArrayList<AccessControlEntryImpl>(aoid.getAclEntries().size()); 
     for(AclEntry aclEntry : aoid.getAclEntries()){ 
      final Permission permission = permissionFactory.buildFromMask(aclEntry.getMask()); 
      aces.add(new AccessControlEntryImpl(aclEntry.getId(), acl, new PrincipalSid(aclEntry.getSid().getSid()), permission, aclEntry.isGranting(), aclEntry.isAuditSuccess(), aclEntry.isAuditFailure())); 
     } 
     setAces((AclImpl) acl, aces); 
     aclCache.putInCache((AclImpl) acl); 
    } 
} 

private void setAces(AclImpl acl, List<AccessControlEntryImpl> aces) { 
    try { 
     fieldAces.set(acl, aces); 
    } catch (IllegalAccessException e) { 
     throw new IllegalStateException("Could not set AclImpl entries", e); 
    } 
} 

}

這裏是我的 'APP-context.xml中' 的一部分文件

<security:global-method-security pre-post-annotations="enabled"> 
    <security:expression-handler ref="expressionHandler" /> 
</security:global-method-security> 
<bean id="expressionHandler" 
    class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler"> 
    <property name="permissionEvaluator" ref="permissionEvaluator" /> 
    <property name="roleHierarchy" ref="roleHierarchy" /> 
</bean> 

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

現在,當我撥打服務的功能如。從控制器它會拋出一個錯誤org.hibernate.HibernateException: No Session found for current thread。但是,一切都(與交易沒有問題)的偉大工程時,我的評論

<security:global-method-security pre-post-annotations="enabled"> <security:expression-handler ref="expressionHandler" /> </security:global-method-security>

我檢查了一切,我縮小問題的代碼上述作品。有誰知道爲什麼會發生這種情況?

+0

您是否已經正確配置了'?查看[文檔](http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/transaction.html#transaction-clawial- annotations)瞭解詳細的事務管理器配置。 –

+0

這取決於你的意思是否正確。我已經將其與默認值配置\t ' \t <豆ID = 「transactionManager的」 \t \t類= 「org.springframework.orm.hibernate4.HibernateTransactionManager」><屬性名=」 sessionFactory「ref =」sessionFactory「/>' – user1137146

回答

7

我不知道如何global-method-security在幕後執行,但有一種BeanPostProcessors一個鮮爲人知的副作用 - 由BeanPostProcessor直接引用,或通過一些引用的任何Bean,它是BPP引用,沒有資格AOP的自動代理

BeanPostProcessor的和AOP自動代理

類實現了BeanPostProcessor接口是特殊的,由容器特別對待。作爲ApplicationContext特殊啓動階段的一部分,它們直接引用的所有BeanPostProcessors和Bean都將在啓動時實例化。接下來,所有BeanPostProcessors都以已排序的方式註冊並應用於容器中的所有其他bean。因爲AOP自動代理被實現爲BeanPostProcessor本身,所以BeanPostProcessors和它們直接引用的bean都不適用於自動代理,因此不具有編入它們的方面。

對於任何這樣的bean,您應該看到一條信息性日誌消息:「Bean foo不適合被所有BeanPostProcessor接口處理(例如:不適合自動代理)」。

(source)

這意味着,如果你是在參考了BeanPostProcessor裝載一個bean有@Transactional,該註釋有效地忽略。

解決方案通常是,如果您需要在必須加載引用BeanPostProcessor的bean中的事務行爲,則需要使用非AOP事務定義 - 即使用TransactionTemplate。

您可以將org.springframework記錄器的記錄設置爲DEBUG,並驗證是否正在爲您的aclService bean輸出此消息。

相關問題