接下里的博客会一篇一篇的讲解每一个通知。其实AOP_AspectJ的编程与传统的AOP的编程的最大的区别就是写一个Aspect 支持多个Advice和多个PointCut 。而且我们写AOP_Aspctj不需要继承任何的接口,不像传统的AOP还要继承接口。
前置通知是在运行我们被代理的方法之前先执行的。
前置通知具有如下的特点:
1.在目标方法执行前 进行增强代码。
2.AspectJ 提供Advice无需实现任何借口, 可以将很多通知代码 写入一个类 (切面类)
3.前置通知定义方法: 无返回值,可以传入参数 JoinPoint 连接点
先拿出案例,再具体讲解:
案例结构图如下:
CustomerService.java是目标类(被代理的类)。
MyAspect.java是切面类(里面可以写很多个通知)
TestAop2.java是junit的测试类。
applicationContext.xml是Spring的配置文件
第一步:我们先写目标类(要被代理的类)
package cn.itcast.spring.d_aspectj; //目标业务类 public class CustomerService { public void update() { System.out.println("this is update"); } public void delete() { System.out.println("this is delete"); } public void search() { System.out.println("this is search"); } }
第二步:我们写切面类
package cn.itcast.spring.d_aspectj; import org.aspectj.lang.JoinPoint; //切面类(内部可以写很多的Advice的方法) public class MyAspect { //前置通知1,2 public void before1() { System.out.print("前置通知1"); } //这个方法传入了参数JoinPoint,通过这个参数我们其实可以得到很多的信息, //比如现在执行的是那个切点 public void before2( JoinPoint joinPoint) { System.out.print("前置通知2"); } }
第三步:写配置文件
<!-- AspectJ AOP --> <!-- 配置目标 --> <bean id="CustomerService" class="cn.itcast.spring.d_aspectj.CustomerService"></bean> <!-- 配置切面类 --> <bean id="MyAspect" class="cn.itcast.spring.d_aspectj.MyAspect"></bean> <aop:config> <!-- ref引用切面类 --> <aop:aspect ref="MyAspect"> <aop:pointcut expression="execution(* cn.itcast.spring.d_aspectj.CustomerService.*(..))" id="mypointcut2"/> <aop:before method="before1" pointcut-ref="mypointcut2" /> <aop:before method="before2" pointcut-ref="mypointcut2" /> </aop:aspect> <!-- 解释一下上面的执行流程 <bean id="CustomerService" class="cn.itcast.spring.d_aspectj.CustomerService"></bean> <bean id="MyAspect" class="cn.itcast.spring.d_aspectj.MyAspect"></bean>都是是创建目标的对象。没什么好说的 <aop:pointcut expression="execution(* cn.itcast.spring.d_aspectj.CustomerService.*(..))" id="mypointcut2"/> <aop:before method="before1" pointcut-ref="mypointcut2" /> <aop:before method="before2" pointcut-ref="mypointcut2" /> 是说我们先找到pointcut-ref="mypointcut2"然后根据mypointcut2找到cn.itcast.spring.d_aspectj.CustomerService.*(..),然后 当每次执行cn.itcast.spring.d_aspectj.CustomerService.*(..)这里的方法时 都是执行"MyAspect"(cn.itcast.spring.d_aspectj.MyAspect)里面的before1这个方法。 同理我们找到pointcut-ref="mypointcut2"然后根据mypointcut2找到cn.itcast.spring.d_aspectj.CustomerService.*(..),然后 当每次执行cn.itcast.spring.d_aspectj.CustomerService.*(..)这里的方法时 都是执行"MyAspect"(cn.itcast.spring.d_aspectj.MyAspect)里面的before2这个方法。 --> </aop:config>
第四步:写JUnit测试代码:
//整合spring和junit //指定spring配置文件位置 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations="classpath:applicationContext.xml") public class TestAop2 { @Autowired private CustomerService customerService; @Test public void testbefore() {System.out.print(customerService.getClass().getName()); customerService.delete(); } }
最后的输出的结果是:
前置通知1
前置通知2
this is delete
由上面可知MyAspect"这个切面类里面的before1(Advice)和before2(Advice)都可以去执行不同的pointCut(切点)。这就是所谓的一个Aspect 支持多个Advice和多个PointCut。
前置通知细节:
1、 默认不能阻止目标方法执行,如果抛出异常,目标方法无法执行
2、 可以传入JoinPoint 连接点参数 , 通过该参数可以获得当前拦截对象和方法信息
最后再提醒一点:所有的所有都是基于动态代理模式,这里没有用到接口,所以这里的代理是Cglib代理。
验证一下:
在TestAop2 的代码上中写
System.out.println(customerSetvice.getClass().getName());
输出是$$EnhancerByCGLIB$$