有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何将对象作为参数传递给spring方面?

假设我需要用@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”。在这种情况下,是否有任何spring特性可以用来解耦IPhoneMusicAspect

!注:感谢@kriegaex的校对


共 (2) 个答案

  1. # 1 楼答案

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

    答案是注释

    IPhone定义为MusicAspect类的字段。添加@Autowired标记,它告诉spring上下文为我们初始化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中注册IPhonebean。其余部分保持不变

    @Configuration
    @EnableAspectJAutoProxy
    public class ApplicationConfig {
        // ... other beans omitted
    
        @Bean 
        public IPhone iphone() {
            return new IPhone();
        }
    }
    

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

  2. # 2 楼答案

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

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

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

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

    Of course I was not allowed to do so.

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