Spring AOP实战例子与springmvc整合不起效果的解决办法
在使用AOP之前,首先我们先了解一下什么是AOP吧。在网上很多人将AOP翻译为“面向切面编程”,什么是面向切面?与面向对象有什么区别呢?
在回答这两个问题之前,我们先要明白切面的概念。
切面由切点与增强组成,它既包括了横切逻辑的定义,也包括了连接点的定义,springAOP就是负责实施切面的框架,它将切面定义的横切逻辑
织入到切面所指定的连接点中。
这时候就要问了:什么是切点?什么是增强?
先看个例子,在例子中再为大家一一解释。
例子:在服务行业,热情问好,带人礼貌是每一个成熟的服务员应有的规范。
建立一个接口 Water.java 方法:问好与服务,greetTo(),serviceTo()
1 2 3 4 5 6 7 8 9 10 11 12 | package test.aop; /** * * @author 作者: wcy * @version 创建时间:Mar 3, 2015 4:27:12 PM * @Description: TODO(一个服务生向顾客问候接待) */ public interface Waiter { public void greetTo(String name); public void serviceTo(String name); } |
那么接下来一个生涩的,训练不足的服务员,他只会生硬的打招呼,这对客人的服务可不好。
建立一个类NativeWater.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | package test.aop.impl; import test.aop.Waiter; /** * * @author 作者: wcy * @version 创建时间:Mar 3, 2015 4:29:53 PM * @Description: TODO(一个训练不足的服务生) */ public class NativeWater implements Waiter{ public void greetTo(String name) { System.out.println( "greet to :" +name+ "...." ); } public void serviceTo(String name) { System.out.println( "service to :" +name+ "...." ); } } |
这样子不好,我们必须对训练不足的服务员进行规范,在打招呼之前先热情问好
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | package test.aop.impl; import java.lang.reflect.Method; import org.springframework.aop.MethodBeforeAdvice; /** * * @author 作者: wcy * @version 创建时间:Mar 3, 2015 4:32:39 PM * @Description: TODO(服务生打招呼前,友好问候别人) */ public class GreetingBeforeAdvice implements MethodBeforeAdvice{ public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable { String clientName = (String) arg1[ 0 ]; System.out.println( "How are you ? Mr." +clientName+ "~~~~~" ); } } |
好,已经对其进行规范了,我们就要测试一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | package test.aop.impl; import org.junit.Before; import org.junit.Test; import org.springframework.aop.BeforeAdvice; import org.springframework.aop.framework.ProxyFactory; import test.aop.Waiter; /** * * @author 作者: wcy * @version 创建时间:Mar 3, 2015 4:40:14 PM * @Description: TODO(强制服务生要热情问候顾客) */ public class BeforeAdviceTest { private Waiter waiter; private BeforeAdvice advice; private ProxyFactory pf; @Before public void init(){ waiter = new NativeWater(); advice = new GreetingBeforeAdvice(); pf = new ProxyFactory(); //Spring工厂提供的代理类 pf.setTarget(waiter); //设置代理目标 pf.addAdvice(advice); //为代理目标添加增强 } @Test public void test01(){ Waiter proxy = (Waiter) pf.getProxy(); proxy.greetTo( "xiaoyu" ); proxy.serviceTo( "xiaolian" ); } } |
运行的结果如下:
How are you ? Mr.xiaoyu~~~~~
greet to :xiaoyu....
How are you ? Mr.xiaolian~~~~~
service to :xiaolian....
好了,这就是一个面向切面的简单例子,那我们就要总结一下了,面向切面需要什么东西。
1、目标类。也就是上文所说的NativeWater.java 该类是一个训练不足的服务生,需要我们对其进行规范,所以要有规范类。
2、增强类。需要实现AOP的前置增强(同样也有后置、环绕等增强),就是规范类,对服务生进行规范。
3、测试类。要为其进行代理,所以要有AOP的代理工厂。
详细的AOP资料,百度很多我就不一一介绍了。
先说一下AOP的执行流程吧。
当我们调用某个定义了AOP的目标类中某个方法时,spring容器会为目标类生成代理类,这生成的方法有2种,一是:jdk的动态代理,使用它必须要有接口;二是CGLib代理,
代理类融合了原类和增强类,它可能与原类具有同样的接口,也可能是原类的子类,所以当我们访问原类的方法的时候,会先访问增强类,再到原类。
好了,以上就说到这。
spring与springmvc整合出现AOP不起作用的原因:
1、spring与springmvc加载配置文件是不同步的,springmvc加载文件对注解进行扫描后,所有的注解都被扫到容器里面,当spring同样加载配置文件扫描注解时,因为容器中已经
存在Service类,那么CGLib代理或jdk动态代理就不对它进行代理了,直接导致了applicationContext.xml中的事务不起作用,出现异常,事务不会滚。
2、解决方法:Spring MVC 和 Spring 整合的时候,SpringMVC的springmvc.xml文件中 配置扫描包,不要包含 service的注解,Spring的applicationContext.xml文件中 配置扫描包时,不要包含controller的注解,如下所示:
SpringMVC的xml配置:
1 2 3 4 | <!-- 1 、 注解探测器,对注解进行扫描 --> <context:component-scan base- package = "com" > <context:exclude-filter type= "annotation" expression= "org.springframework.stereotype.Service" /> </context:component-scan> |
同样的,spring的applicationContext.xml配置文件也一样,不要扫描@Controller注解
1 2 3 4 | <!-- 注解扫描器 --> <context:component-scan base- package = "com" > <context:exclude-filter type= "annotation" expression= "org.springframework.stereotype.Controller" /> </context:component-scan> |
工作完成。
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步