Spring Boot中Proxy与Aspect代码正确性咨询(首次使用AOP)
Spring AOP 代码问题解答
问题描述
我是首次使用Spring Boot的AOP技术,正在学习Proxy与Aspect的用法,目前编写了相关代码,但不确定代码是否正确,尤其疑惑切面是否应该指向代理方法,希望得到解答。
现有代码
代理类代码(ProxyOggetto)
package local.luddel; import org.springframework.stereotype.Component; @Component public class ProxyOggetto { private InterfacciaOggetto interfacciaOggetto; public ProxyOggetto(InterfacciaOggetto interfacciaOggetto) { super(); this.interfacciaOggetto = interfacciaOggetto; } public void getEccociOggetto() { System.out.println("Sono nel proxy"); interfacciaOggetto.eccoci(); } public void getCiaoOggetto() { System.out.println("Sono nel proxy"); interfacciaOggetto.ciao(); } }
切面类代码(MyAspect)
package local.luddel; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; @Aspect @Component public class MyAspect { @Before(value = "execution(* local.luddel.ProxyOggetto.getEccociOggetto())") public void beforeEccoci() { System.out.println("Sono in aspect"); } }
配置类代码(ConfigBean)
package local.luddel; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; @Configuration @ComponentScan @EnableAspectJAutoProxy public class ConfigBean { @Bean(value = "oggetto") public Oggetto getOggetto() { return new Oggetto(); } @Bean(value = "myAspect") public MyAspect getMyAspect() { return new MyAspect(); } @Bean(value = "service") public Servizio getServizio(){ return new Servizio(); } @Bean(value = "proxy") public ProxyOggetto getProxyOggetto() { return new ProxyOggetto(getOggetto()); } }
主类代码(Main)
package local.luddel; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class Main { public static void main(String[] args) { myBeanOggetto(); } static public void myBeanOggetto() { ApplicationContext applicationContext = new AnnotationConfigApplicationContext(ConfigBean.class); ProxyOggetto proxyOggetto = applicationContext.getBean("proxy", ProxyOggetto.class); proxyOggetto.getEccociOggetto(); } }
代码分析与解答
核心误区澄清
你现在手动编写的ProxyOggetto是静态代理类,而Spring AOP的核心是动态代理——Spring会自动为被切面切入的Bean生成代理对象,完全不需要你手动编写代理类。你的写法虽然能运行,但违背了Spring AOP的设计初衷,也增加了不必要的代码复杂度。
关于切面指向代理方法的疑问
切面可以指向代理方法(比如你现在切ProxyOggetto.getEccociOggetto()),运行时会按以下顺序执行:
- 执行Aspect的
beforeEccoci()方法 - 执行
ProxyOggetto.getEccociOggetto()方法 - 调用目标对象
Oggetto.eccoci()方法
但这种写法完全没必要,Spring AOP可以直接把切面切入到目标对象的方法上,自动帮你完成代理逻辑。
现有代码的问题
- Bean重复定义:
ProxyOggetto类加了@Component,同时ConfigBean里又用@Bean注册了名为proxy的实例,这会导致Spring容器中存在两个ProxyOggetto实例(一个是ComponentScan扫描生成的proxyOggetto,另一个是@Bean定义的proxy),可能引发依赖注入冲突。 - 冗余代码:手动编写的静态代理类完全多余,Spring AOP的动态代理可以替代这个逻辑。
优化方案
- 删除手动代理类:直接移除
ProxyOggetto类,不需要手动实现代理逻辑。 - 修改切面切入点:把切面直接切入到目标对象
Oggetto的方法上,修改MyAspect的@Before注解:@Before(value = "execution(* local.luddel.Oggetto.eccoci())") public void beforeEccoci() { System.out.println("Sono in aspect"); } - 清理配置类:删除
ConfigBean中getProxyOggetto()的@Bean定义,避免Bean重复。 - 简化主类调用:直接从容器获取
Oggetto实例并调用方法,Spring会自动生成代理:static public void myBeanOggetto() { ApplicationContext applicationContext = new AnnotationConfigApplicationContext(ConfigBean.class); Oggetto oggetto = applicationContext.getBean("oggetto", Oggetto.class); oggetto.eccoci(); }
优化后运行效果
执行Main类后,控制台会输出:
Sono in aspect // Oggetto.eccoci()方法的输出内容
内容的提问来源于stack exchange,提问作者Ludovico Deledda
相关产品推荐
相关产品推荐

