如何让Spring为我的bean创建AOP Proxies

时间:2013-05-10 19:17:57

标签: java spring aop

在我的Spring应用程序中,我有一大堆bean(在这种情况下是DAO),在我的XML配置中创建为简单的<bean>。在这些方法中有各种注释,具体包括@Transactional。我自然也有<tx:annotation-driven />

但是对于其中一些对象 - 虽然只有其中一些 - 没有创建代理(我通过启用调试日志记录确认了这一点)并且@Transactional注释无效。相反,包含(通常是自动装配的)对这些DAO的引用的对象将连接到直接类的引用,而不是代理。

所有类都有相应的接口,自动引用的引用总是通过这些接口。

我无法弄清楚哪些类获取代理,哪些不获取代理。我想要他们所有人。所以我的问题是:

a)在什么情况下Spring不为类创建代理,即使它实现了一些接口?

b)如何强制Spring创建我需要的代理?

请注意,我没有做任何事情来明确启用代理,但我过去并不需要。它通常是有效的。

尝试使用Spring 3.1.3和3.2.2。

我没有这方面的SSCCE。基本上我的XML是

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"       
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:sec="http://www.springframework.org/schema/security"    
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:ehcache="http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring"                       
       xmlns:cache="http://www.springframework.org/schema/cache"       
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
       http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
       http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring
       http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring/ehcache-spring-1.2.xsd
       http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd
">

       <bean id="userDao" class="com.soschat.dao.spring.SpringUserDAO"/>

           <tx:annotation-driven transaction-manager="transactionManager" />

    <bean id="transactionManager" class=" org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
        <property name="globalRollbackOnParticipationFailure" value="false" />
    </bean>

... etc ...
</beans>

我的代码或多或少

public class UserDaoImpl implements UserDao {

   @Override
   @Transactional
   @Cacheable
   public User getUserById(long userId) {
         // do stuff
   }
}

不确定在没有过多细节的情况下我需要添加多少。

一个有趣的补充 - 我可以强制它使用BeanNameAutoProxyCreator创建代理。但是我放在那里的注释都没有实际生效。

3 个答案:

答案 0 :(得分:3)

@Component注释将告诉Spring创建和处理该类的bean。您需要让您的应用程序(或其他)上下文扫描具有<component-scan>元素的类包。

@Service@Repository@Controller就像@Component一样工作。

至于代理,Spring不会代理所有内容,只需要添加行为所需的类的实例。例如,对于@Transactional,它需要添加begin / commit / rollback事务行为。为此,它使用自己的代码包装类的方法,因此需要代理。对于@Controller类,它不需要添加任何行为,因此它只是实例化您的类。

答案 1 :(得分:2)

最终我发现它失败了,因为某种依赖链从一个以某种方式“太早”加载的bean开始 - 在我的例子中是一个Spring Security PermissionEvaluator。我仍然没有SSCCE,但我在这里添加这个答案以防其他人遇到类似的问题。

解决方案是使用非常晚的绑定。我将PermssionEvaluator转换为ApplicationContextAware,然后编写了一个私有方法来加载来自ApplicationContext的本地引用,并且只在首次需要时调用此方法,而不是在初始化。

换句话说,我有一个类似

的豆子
private AuthorizationServices authServices;

然后在我的主要方法中像

if (authServices == null)
   initBeans();

然后

private void initBeans() {
    authServices = ac.getBean(AuthorizationServices.class);
}

答案 2 :(得分:0)

我们遇到了同样的问题,并意识到在应用程序启动时org.springframework.cache.ehcache.EhCacheCacheManager之前初始化了bean,因此@Cacheable无效。

我们最终将缓存配置从java配置类移动到xml,强制(不确定如何),EHCacheManager在任何应用程序bean之前初始化。我们的应用程序中有xml和java配置。

<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager" p:cache-manager-ref="ehcache"/>
    <bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:config-location="classpath:ehcache.xml" p:shared="true"/>