【问题标题】:How to pass object as parameter to a spring aspect?如何将对象作为参数传递给弹簧方面?
【发布时间】:2021-07-24 19:39:34
【问题描述】:

假设我需要使用@MusicAround 建议来增强shower() 方法,以便在执行shower() 方法之前和之后给我一些音乐。

public class Me {
    @MusicAround
    public void shower() {
        // shower code omitted
    }
}

首先我创建了新的注解@MusicAround

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MusicAround {

然后用切面MusicAspect绑定它。

@Aspect
public class MusicAspect {
    @Around("@annotation(MusicAround)")
    public Object musicAround(ProceedingJoinPoint joinPoint) throws Throwable {
        IPhone iphone = new IPhone();
        Iphone.music();
        joinPoint.proceed();
        iphone.music();
    }
}

MusicAspect 配置为Bean@EnableAspectJAutoProxy 注释离开 spring 来为我封装方面代理。

@Configuration
@EnableAspectJAutoProxy
public class ApplicationConfig {
    // ... other beans omitted

    @Bean 
    public MusicAspect musicAspect() {
        return new MusicAspect();
    }
}

在main方法中,从上下文中获取Me实例,并执行shower()方法。

public static void main(String[] args) {
    try {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfig.class);
        Me me = context.getBean(Me.class);
        me.shower();
        context.close();
    } catch (ApplicationContextException ace) {
        // handle exception
    }
}

现在我可以在淋浴时播放音乐了。

<hey jude>
I'm showering
<don't be so serious>

问题是这样MusicAspect 类与IPhone 类耦合。我想通过注入IPhone 对象作为参数来解耦它们,如下所示,

@Aspect
public class MusicAspect {
    @Around("@annotation(MusicAround)")
    public Object musicAround(ProceedingJoinPoint joinPoint, IPhone iphone) throws Throwable {
        iphone.music();
        joinPoint.proceed();
        iphone.music();
    }
}

当然,这里不允许musicAround() 方法中的第二个参数“iphone”。在这种情况下,我是否可以使用任何弹簧功能来解耦 IPhoneMusicAspect

!注意:感谢@kriegaex 的校对。

【问题讨论】:

  • 这个问题来自XY problem:它解释了如何你在技术上梦想实现你的目标,而不是解释你真正想要的什么达到。示例代码不适合解释您的目标,您的解释也是如此。注释只是一个注释,它什么都不做。方面做了一些事情。通过将某些内容“注入”到注释中,您将获得什么,无论这可能意味着什么?请编辑并改进您的问题。谢谢。
  • @kriegaex 现在看起来更好了?
  • 感谢@k-wasilewski @Autowired 标签解决了我的问题。

标签: java spring annotations aop aspect


【解决方案1】:

这是一个初步的回答,因为内容不适合评论。

查看更新后问题中的代码时,有些事情让我觉得很奇怪:

  • 我想知道为什么每个人都如此渴望总是将方面与注释结合使用。为什么不使用直接针对感兴趣的包、类或方法的切入点呢?如果不是绝对必要的话,所有这些注释污染都是可怕的。理想情况下,应用程序代码应该完全不知道切面的存在。
  • 您错误地使用了@annotation 切入点指示符。而不是@annotation(@MusicAround),它应该是@annotation(MusicAround)。但也只有当注释恰好与切面位于完全相同的包中时才有效,否则您需要@annotation(fully.qualified.package.name.MusicAround)
  • 您使用了MusicAspect,但随后声明了MinstrelAroundAdvice bean。这似乎不匹配。此外,切面就是切面,它里面实际做某事的方法就是advice。所以一个方面的类名*Advice 是完全错误的。最好使用*Aspect 或其他正确描述方面功能的东西。在这种情况下,MusicAspect 对我来说似乎很好。

现在关于你的实际问题,我还不清楚。是关于如何将另一个 bean 注入(自动连接)到方面实例中吗?

我当然不被允许这样做。

为什么是“当然”?什么是不允许的?你是怎么注意到的?有什么不工作吗?你收到错误信息了吗?堆栈跟踪?请清楚地解释您尝试了什么,预期结果是什么以及发生了什么。使您的问题可重现。不幸的是,您的代码 sn-ps 没有这样做。想象一下,别人会问你同样的问题,而你却没有看到完整的代码,也没有理解问题所需的其他上下文信息。你能回答吗?如果您的助手不理解问题,他们如何回答您的问题?请注意了解MCVE 是什么。

【讨论】:

  • 切入点表达式不灵活且难以使用。在我们想要的任何地方添加注释看起来更直观。污染?你觉得像@Pointcut("execution(public String com.baeldung.pointcutadvice.dao.FooDao.findById(Long))") 这样的长切入点表达式很漂亮吗?
  • 它使用起来并不难,而且很灵活,因为你可以改变它。更重要的是,您可以在一个地方使用和维护它,而无需在数百个地方更改您的应用程序代码。用户可能会忘记添加注释,但方面维护者可以确保方面针对正确的位置。无论如何,我只是提到了这一点,因为它在您的初学者示例中过度工程化。实际的问题是切入点中的语法错误以及您不知道如何自动连接组件的事实——后者是 Spring 基础知识,根本与 AOP 无关。
【解决方案2】:

@k-wasilewski@kriegaex 的帮助下解决了问题。谢谢兄弟。

答案是@Autowired注解。

IPhone 定义为MusicAspect 类的字段。添加@Autowired标签,告诉spring context为我们初始化IPhone实例。

@Aspect
public class MusicAspect {

    @Autowired
    private IPhone iphone;

    @Around("@annotation(MusicAround)")
    public Object musicAround(ProceedingJoinPoint joinPoint) throws Throwable {
        Iphone.music();
        joinPoint.proceed();
        iphone.music();
    }

}

不要忘记在ApplicationConfig 中注册IPhone bean。其余部分保持不变。

@Configuration
@EnableAspectJAutoProxy
public class ApplicationConfig {
    // ... other beans omitted

    @Bean 
    public IPhone iphone() {
        return new IPhone();
    }
}

代码在我的笔记本电脑上通过了单元测试。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-03-30
    • 2022-11-02
    • 2022-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-22
    相关资源
    最近更新 更多