4

daoを介してデータベースとの連絡を担当するサービスを作成しました。@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>

すべてをチェックし、問題のあるコードを上記の部分に絞り込みました。なぜこれが起こっているのか誰かが知っていますか?

4

1 に答える 1

8

裏でどのように実装されているかはわかりませんglobal-method-securityが、の副作用はほとんど知られていません。BeanPostProcessors直接参照されているBean BeanPostProcessor、またはBPPが参照しているものによって参照されているBeanは、AOP自動プロキシの対象ではありません

BeanPostProcessorsとAOP自動プロキシ

BeanPostProcessorインターフェースを実装するクラスは特別であり、コンテナーによって異なる方法で処理されます。すべてのBeanPostProcessorsとそれらが直接参照するBeanは、ApplicationContextの特別な起動フェーズの一部として、起動時にインスタンス化されます。次に、すべてのBeanPostProcessorsがソートされた方法で登録され、コンテナー内の以降のすべてのBeanに適用されます。AOP自動プロキシはBeanPostProcessor自体として実装されているため、BeanPostProcessorsもそれらが直接参照するBeanも自動プロキシの対象にはならず、したがって、それらに織り込まれた側面はありません。

このようなBeanについては、「Bean fooはすべてのBeanPostProcessorインターフェースで処理される資格がありません(例:自動プロキシの資格がありません)」という情報ログメッセージが表示されます。

(ソース)

これは@Transactional、BeanPostProcessorを参照してロードされるBeanにある場合、そのアノテーションは事実上無視されることを意味します。

一般に、解決策は、BeanPostProcessorを参照してロードする必要があるBeanでトランザクション動作が必要な場合、非AOPトランザクション定義を使用する必要があることです。つまり、TransactionTemplateを使用します。

org.springframeworkロガーのロギングを上げて、DEBUGこのメッセージがaclServiceBeanに出力されているかどうかを確認できます。

于 2012-09-26T19:00:03.983 に答える