如何在 Aspect 内可靠地自动装配成员 - 即使在上下文刷新之后? [英] How to Autowire members reliably inside an Aspect - even after a context refresh?

查看:26
本文介绍了如何在 Aspect 内可靠地自动装配成员 - 即使在上下文刷新之后?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 AspectJ 方面,我想在其中包含 @Autowired 字段.鉴于默认情况下,方面是在 Spring 容器之外创建的单例,Spring 不管理方面的任何依赖注入.

I have an AspectJ aspect in which I want to have @Autowired fields. Given that by default, the aspects are singletons created outside the Spring container, Spring does not manage any of the dependency injection for the aspect.

在 SO 上搜索,Spring autowired bean for @Aspect aspect is null 遇到了同样的问题,并使用 <方面的代码>@Configurable 注释以某种方式神奇地允许 Spring 进行依赖注入(参见@codebrickie 响应).我仍然不完全清楚这种魔法是如何工作的,但它似乎工作得很好.

Searching around on SO, Spring autowired bean for @Aspect aspect is null encountered the same problem, and using the @Configurable annotation on the aspect somehow magically allows Spring to do the dependency injection (see @codebrickie response). I'm still not entirely clear how that magic works, but it seems to work fine.

我现在的问题是,如果我刷新 Spring 上下文,Spring 不会更新依赖项以指向新 bean.这是我的单元测试中的一个问题.我有一个定义了 @DirtiesContext(classMode=ClassMode.AFTER_EACH_TEST_METHOD) 的类,表明我希望 spring 在每个测试方法之后刷新上下文.但是,鉴于它不更新 Aspect 的依赖项,我第一次测试后的任何测试都失败了,因为引用的 bean(第一次运行时自动装配的剩余部分)不再有效.

My problem, now, is that if I refresh the Spring context, Spring does not update the dependencies to point to the new beans. This is a problem in my unit tests. I have a class with @DirtiesContext(classMode=ClassMode.AFTER_EACH_TEST_METHOD) defined, indicating that I want spring to refresh the context after each test method. However, given that it doesn't update the Aspect's dependencies, any tests after my first test fail given that the referenced beans (left over autowired from the first run) are no longer valid.

示例测试类:

@DirtiesContext(classMode=ClassMode.AFTER_EACH_TEST_METHOD)
@Transactional
public class UserServiceImplTest extends TestBase {
    @Test
    @RequiredUserDetails(permissions={Permission.USER_LIST})
    public void testFindUser() throws Exception {
        User u = dod.getRandomUser();
        long userId = u.getId();

        User u2 = userService.findUser(userId);

        assertThat(u2, equalTo(u));
    }

    @Test(expected=AccessDeniedException.class)
    public void testFindUserWithoutPermissions() throws Exception {
        User u = dod.getRandomUser();
        long userId = u.getId();

        User u2 = userService.findUser(userId);

        assertThat(u2, equalTo(u));
    }
}

方面片段:

@Configurable
@Aspect
public class RequiredUserDetailsAspect {

    @Autowired UserRepository userRepository;

    @Pointcut("execution(public * *(..)) && @annotation(org.junit.Test)")
    public void testMethod() {};

    /**
     * Inject the specific permissions before test executes
     */
    @Before("testMethod() && requiresPermission(requiredUserDetails)")
    public void beforeTest( RequiredUserDetails requiredUserDetails){
        authenticateUser( userRepository.findOne( requiredUserDetails.id ) );
    }

    ...
    ...
    ...


}

如果我在 beforeTest 方法中在我的方面放置一个断点,我可以看到 userRepository bean 引用在 2 个单元测试之间是相同的,即使从我可以看到 Spring 已经实例化了一个新的 userRepository bean 的日志.因此,在第二个测试期间,方面指向一个陈旧的 bean.

If I put a breakpoint in my aspect in the beforeTest method, I can see that the userRepository bean reference is the same between the 2 unit tests, even though from the logs I can see that Spring has instantiated a new userRepository bean. Consequently, during the second test, the aspect is pointing to a stale bean.

如何指示 Spring 刷新它通过 @Configurable 实例化注入方面的依赖项?

How can I instruct Spring to refresh the dependencies that it injected into the aspect via the @Configurable instantiation?

推荐答案

我经常想知道为什么他们不让 Spring 更轻松地管理方面.

I've have often wondered why they don't make it easier for spring to manage the aspect.

但是为了使方面 spring 得到管理,您将以下内容放入您的 xml ... 不知道您将如何使用 java 配置来做到这一点.

But to make the aspect spring managed you put the following into your xml... Don't know how you'd do it with java configuration.

虽然我认为配置应该也能正常工作……尽管您可能会遇到生命周期冲突的问题.

Though I think configuration should work as well... although you may have issues with life cycle conflicts.

<bean id="securityAspect" 
   class="com.afrozaar.ashes.core.security.AuthorizationAspect"> 
   factory-method="aspectOf" autowire="byType" />

当方面编译器创建一个方面时,它会将aspectOf"方法添加到类中.此方法可以访问作为方面的对象,并且在您的 xml 中具有此配置将通过 spring 将该对象暴露给注入等.

When the aspect compiler creates an aspect it adds that "aspectOf" method to the class. This method gives access to the object that is the aspect and having this config in your xml will expose that object to injection etc by spring.

这篇关于如何在 Aspect 内可靠地自动装配成员 - 即使在上下文刷新之后?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆