Spring框架(6)---AspectJ实现AOP

来源:互联网 发布:阿里云飞天八部 编辑:程序博客网 时间:2024/04/28 17:36

什么是Spring的AspectJ的AOP

      AspectJ是一个面向切面的框架,它扩展了Java语言。AspectJ定义了AOP语法所以它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件。
  Spring2.0以后新增了对AspectJ切点表达式支持,@AspectJ 是AspectJ1.5新增功能,通过JDK5注解技术,允许直接在Bean类中定义切面
  新版本Spring框架,建议使用AspectJ方式来开发AOP

那我们先来一个小案例,还是以前面狗的案例举例:

1.导入相关架包

在原来的基础上导入下面四个架包:

  • spring-aop-4.2.0.RELEASE.jar
  • com.springsource.org.aopalliance-1.0.0.jar
  • spring-aspects-4.2.0.RELEASE.jar
  • com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar

 2.编写配置文件applicationContext.xml    导入aop的命名空间

复制代码
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xmlns:p="http://www.springframework.org/schema/p"    xmlns:aop="http://www.springframework.org/schema/aop"    xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- bean definitions here -->                  <!-- 配置注解bean所在的包 -->          <context:annotation-config/>          <context:component-scan base-package="com.study.spring.d_advisor"></context:component-scan>        <!-- 打开自动代理 -->        <aop:aspectj-autoproxy/></beans>
复制代码

 3.编写代理对象

复制代码
 1 public class Dog { 2  3     public void run() { 4         System.out.println("狗会跑"); 5     } 6  7     public void jump() { 8  9         System.out.println("狗会跳");10 11     }12 13     public void eat() {14 15         System.out.println("狗能吃");16     }17 }
复制代码

4)编写切面类

复制代码
import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;//@Aspect声明当前类是一个切面@Aspect     public class MyAspectJ {    //@Before代表在执行方法之前执行增强代码    @Before("execution(* com.study.dog.Dog.*(..))")    public void before1() {        System.out.println("饲养员叫你你猜能动");    }}
复制代码

5编写配置文件 

复制代码
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xmlns:p="http://www.springframework.org/schema/p"    xmlns:aop="http://www.springframework.org/schema/aop"    xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- bean definitions here -->                  <!-- 配置注解bean所在的包 -->          <context:annotation-config/>          <context:component-scan base-package="com.study.spring.d_advisor"></context:component-scan>        <!-- 打开自动代理 -->        <aop:aspectj-autoproxy/>                          <!-- 被代理对象 -->           <bean id="Dog" class="com.study.dog.Dog"></bean>         <!-- 切面 -->          <bean id="MyAspectJ" class="com.study.dog.MyAspectJ"></bean>               </beans>
复制代码

6.编写测试类

复制代码
 1 import org.junit.Test; 2 import org.junit.runner.RunWith; 3 import org.springframework.beans.factory.annotation.Autowired; 4 import org.springframework.beans.factory.annotation.Qualifier; 5 import org.springframework.test.context.ContextConfiguration; 6 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 7  8 //完成配置文件的加载 9 @RunWith(SpringJUnit4ClassRunner.class)10 @ContextConfiguration(locations="classpath:applicationContext.xml")11 public class AspectJTest {12     // 得到dog对象13     @Autowired14     @Qualifier("Dog")15     private Dog dog;16 17     @Test18     public void Demo1() {19         dog.eat();20         dog.run();21         dog.jump();22     }23     /*24      * 输出结果:25      *    饲养员叫你你猜能动26      *    狗能吃27      *    饲养员叫你你猜能动28      *    狗会跑29      *    饲养员叫你你猜能动30      *    狗会跳31      */32 }
复制代码

 总结:上面是一个最简单的AspectJ的AOP,我们这样就可以通过输入一个”饲养员叫你你猜能动",就可以在多个方法中存在,在以后开发非常需要

那么下来来说一些非常重要的干货!

 AspectJ表达式:
    语法:execution(表达式) 通过execution函数,可以定义切点的方法切入

      execution(<访问修饰符>?<返回类型><方法名>(<参数>)<异常>)      

         例如

               execution(public * *(..))                             匹配所有类public方法

               execution(* cn.study.dao..*(..))                  匹配指定包下所有类方法,不包含子包

     execution(* cn.study.dao..*(..))                  ..*表示包、子孙包下所有类

     execution(* cn.study.service.UserService.*(..))  匹配指定类所有方法

     execution(* cn.study.dao.GenericDAO+.*(..))   匹配实现特定接口所有类方法

     execution(* save*(..))                                     匹配所有save开头的方法

    AspectJ增强
    
@Before 前置通知,相当于BeforeAdvice
    @AfterReturning 后置通知,相当于AfterReturningAdvice
    @Around 环绕通知,相当于MethodInterceptor
    @AfterThrowing抛出通知,相当于ThrowAdvice
    @After 最终final通知,不管是否异常,该通知都会执行
    @DeclareParents 引介通知,相当于IntroductionInterceptor (不要求掌握)

那现在我们通过上面的列子,来全面贯彻上面的干货!

对上面MyAspectJ的进行全面增强:

复制代码
import org.aspectj.lang.JoinPoint;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.After;import org.aspectj.lang.annotation.AfterReturning;import org.aspectj.lang.annotation.AfterThrowing;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.aspectj.lang.annotation.Pointcut;//@Aspect声明当前类是一个切面@Aspect     public class MyAspectJ {        //@Before代表在执行方法之前执行增强代码     @Before("execution(* com.study.dog.Dog.run(..))")        public void before(JoinPoint joinPoint){            System.out.println("前置增强...."+joinPoint);        }       //后置通知      @AfterReturning (value="execution(* com.study.dog.Dog.jump(..))",returning="returnVal")        public void afterReturin(Object returnVal){            System.out.println("后置增强....方法的返回值:"+returnVal);        }        //环绕通知        @Around(value="MyAspectJ.myPointcut()")        public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{            System.out.println("环绕前增强....");            Object obj = proceedingJoinPoint.proceed();            System.out.println("环绕后增强....");            return obj;        }         //抛出通知        @AfterThrowing(value="MyAspectJ.myPointcut()",throwing="e")        public void afterThrowing(Throwable e){            System.out.println("不好了 出异常了!!!"+e.getMessage());        }                 //最终final通知,不管是否异常,该通知都会执行        @After("MyAspectJ.myPointcut()")        public void after(){            System.out.println("最终通知...");        }       //切点的定义        @Pointcut("execution(* com.study.dog.Dog.eat(..))")        private void myPointcut(){}}
复制代码

编写测试类AspectJTest   和上面一点不变 

复制代码
import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;//完成配置文件的加载@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(locations="classpath:applicationContext.xml")public class AspectJTest {    // 得到dog对象    @Autowired    @Qualifier("Dog")    private Dog dog;    @Test    public void Demo1() {        dog.eat();        dog.run();        dog.jump();    }}
0 0