如何将对象作为参数传递给 spring 方面?
How to pass object as parameter to a spring aspect?
假设我需要用 @MusicAround
建议增强 shower()
方法,以便在执行 shower()
方法前后给我一些音乐。
public class Me {
@MusicAround
public void shower() {
// shower code omitted
}
}
首先我创建了新注释 @MusicAround
。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MusicAround {
然后绑定一个aspect 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
class 和 IPhone
class 耦合了。我想通过注入 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 功能来分离 IPhone
和 MusicAspect
吗?
!注:感谢@kriegaex 校对
这是初步的回答,因为内容不适合评论
在查看您更新后的问题中的代码时,有些事情让我觉得很奇怪:
- 我想知道为什么每个人都如此热衷于始终将方面与注释结合使用。为什么不使用直接针对包、classes 或感兴趣的方法的切入点?如果不是绝对必要的话,所有这些注释污染都是可怕的。理想情况下,应用程序代码应该完全不知道方面的存在。
- 您错误地使用了
@annotation
切入点指示符。而不是 @annotation(@MusicAround)
,它应该是 @annotation(MusicAround)
。但这也仅在注释恰好与方面位于完全相同的包中时才有效,否则您需要 @annotation(fully.qualified.package.name.MusicAround)
.
- 您使用
MusicAspect
,但随后声明了一个 MinstrelAroundAdvice
bean。这似乎不匹配。此外,切面就是切面,它里面实际做某事的方法就是建议。因此,某个方面的 class 名称 *Advice
完全是错误的。最好改用 *Aspect
或其他可以正确描述方面功能的东西。在这种情况下,MusicAspect
对我来说似乎很好。
现在关于你的实际问题,我还不清楚。它是关于如何将另一个 bean 注入(自动连接)到方面实例中吗?
Of course I was not allowed to do so.
为什么是“当然”?什么是不允许的?你是怎么注意到的?是不是有什么问题?您收到错误消息了吗?堆栈跟踪?请清楚说明您尝试了什么,预期结果是什么以及发生了什么。使您的问题可重现。不幸的是,您的代码片段不会这样做。试想一下,如果您没有看到完整的代码,也没有了解问题所需的其他上下文信息,其他人会问您同样的问题。你能回答吗?如果你的助手不明白这个问题,他们怎么能回答你的问题呢?请注意了解什么是 MCVE。
在 @k-wasilewski 和 @kriegaex 的帮助下解决了问题。谢谢兄弟
答案是@Autowired
注解
将 IPhone
定义为 MusicAspect
class 的字段。添加 @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
中注册 IPhone
bean。其余部分保持不变。
@Configuration
@EnableAspectJAutoProxy
public class ApplicationConfig {
// ... other beans omitted
@Bean
public IPhone iphone() {
return new IPhone();
}
}
代码在我的笔记本电脑上通过了单元测试。
假设我需要用 @MusicAround
建议增强 shower()
方法,以便在执行 shower()
方法前后给我一些音乐。
public class Me {
@MusicAround
public void shower() {
// shower code omitted
}
}
首先我创建了新注释 @MusicAround
。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MusicAround {
然后绑定一个aspect 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
class 和 IPhone
class 耦合了。我想通过注入 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 功能来分离 IPhone
和 MusicAspect
吗?
!注:感谢@kriegaex 校对
这是初步的回答,因为内容不适合评论
在查看您更新后的问题中的代码时,有些事情让我觉得很奇怪:
- 我想知道为什么每个人都如此热衷于始终将方面与注释结合使用。为什么不使用直接针对包、classes 或感兴趣的方法的切入点?如果不是绝对必要的话,所有这些注释污染都是可怕的。理想情况下,应用程序代码应该完全不知道方面的存在。
- 您错误地使用了
@annotation
切入点指示符。而不是@annotation(@MusicAround)
,它应该是@annotation(MusicAround)
。但这也仅在注释恰好与方面位于完全相同的包中时才有效,否则您需要@annotation(fully.qualified.package.name.MusicAround)
. - 您使用
MusicAspect
,但随后声明了一个MinstrelAroundAdvice
bean。这似乎不匹配。此外,切面就是切面,它里面实际做某事的方法就是建议。因此,某个方面的 class 名称*Advice
完全是错误的。最好改用*Aspect
或其他可以正确描述方面功能的东西。在这种情况下,MusicAspect
对我来说似乎很好。
现在关于你的实际问题,我还不清楚。它是关于如何将另一个 bean 注入(自动连接)到方面实例中吗?
Of course I was not allowed to do so.
为什么是“当然”?什么是不允许的?你是怎么注意到的?是不是有什么问题?您收到错误消息了吗?堆栈跟踪?请清楚说明您尝试了什么,预期结果是什么以及发生了什么。使您的问题可重现。不幸的是,您的代码片段不会这样做。试想一下,如果您没有看到完整的代码,也没有了解问题所需的其他上下文信息,其他人会问您同样的问题。你能回答吗?如果你的助手不明白这个问题,他们怎么能回答你的问题呢?请注意了解什么是 MCVE。
在 @k-wasilewski 和 @kriegaex 的帮助下解决了问题。谢谢兄弟
答案是@Autowired
注解
将 IPhone
定义为 MusicAspect
class 的字段。添加 @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
中注册 IPhone
bean。其余部分保持不变。
@Configuration
@EnableAspectJAutoProxy
public class ApplicationConfig {
// ... other beans omitted
@Bean
public IPhone iphone() {
return new IPhone();
}
}
代码在我的笔记本电脑上通过了单元测试。