spring中AspectJ的使用


AspectJ:

什么是AOP:

AOP为Aspect Oriented Programming,意为:面向切面编程;它是一种思想一种设计典范(同Ioc);它是OOP(面向对象编程)的一种衍生。通过AOP对业务逻辑进行隔离,可以降低各个业务逻辑之间的耦合度。AOP主要解决的是”系统及服务“和”主业务逻辑“之间的耦合;

AOP和AspctJ:

AspecJ是一个基于java的AOP框架;spring自身也实现了AOP,在spring中一般使用AspectJ;

关系:AspectJ是AOP思想的实现,AOP实现方式有很多,著名的有spring AOP ,AspectJ;

AOP术语

  1. 目标类(target):需要被增强的类;

  2. 连接点(joinpoint):是指可以被增强到的方法;

  3. 切入点(Pointcut):已经被增强的方法(属于连接点中的方法)

  4. 通知(advice):指被增强的内容;

  5. 切面(Aspect):切面=切入点+通知;

  6. 织入(weaving):把“通知”应用到“目标类”中的过程;

通知的类型

  • before:前置通知(应用:各种校验)
    • 在方法执行前执行,如果通知抛出异常,阻止方法运行
  • afterReturning:后置通知(应用:常规数据处理)
    • 方法正常返回后执行,如果方法中抛出异常,通知无法执行
    • 必须在方法执行后才执行,所以可以获得方法的返回值。
  • around:环绕通知(应用:十分强大,可以做任何事情)
    • 方法执行前后分别执行,可以阻止方法的执行
    • 必须手动执行目标方法
  • afterThrowing:抛出异常通知(应用:包装异常信息)
    • 方法抛出异常后执行,如果方法没有抛出异常,无法执行
  • after:最终通知(应用:清理现场)
    • 方法执行完毕后执行,无论方法中是否出现异常

切入点表达式

基本格式:

execution( 修饰符 返回值 包.类.方法名(参数) throws异常 )

括号中的内容其实就是声明一个方法。通常”修饰符“和”throw 异常“省略不写;

返回值:

基本类型,对象
*//(匹配任意返回值)

包:用限定名。可以使用通配符如:

com.abc.service//表示固定包
com.abc.crm.*.service//表示crm包下任意子包的service包
com.abc.crm..//表示crm包下面的所有子包(包括自己)
“..”可以表示自己本身和自己下面的多级包

类:可以使用固定名称,和统配符号

*Impl //以Impl结尾
User* //以User开头的
* //任意

方法名

addUser//固定方法
add*//以add开头
*Do//以Do结尾

参数

()//无参
(int)//一个整型
(int,int)//两个
(..)//参数任意

例子

execution(* *.someServiceImpl.*(..))
//所有的包下面(限定一级包)someServiceImpl类的所有任意参数的方法
execution(* *..someServiceImpl.*(..))
//所有的包下面(可以是多级包)someServiceImpl类的所有任意参数的方法
execution(* com.abc.crm.*.service..*.*(..))
//service下自己以及自己的子包的任意类的任意方法

基于xml的AspectJ编程

导入jar包

导入四个jar包

  • AspectJ的jar包
  • spring用于整合aspectJ的jar包
  • spring的AOP实现jar包
  • AOP联盟的AOP规范jar包
<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjweaver</artifactId>
  <version>1.9.4</version>
</dependency>

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-aspects</artifactId>
  <version>5.2.0.RELEASE</version>
</dependency>

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-aop</artifactId>
  <version>5.2.0.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/aopalliance/aopalliance -->
<dependency>
    <groupId>aopalliance</groupId>
    <artifactId>aopalliance</artifactId>
    <version>1.0</version>
</dependency>

定义切面类

定义切面类用于写对应通知的方法

public class MyAspect {
    public void before(){
        System.out.println("执行前置通知before()!");
    }
    //可以输出当前的连接点
    public void before2(JoinPoint jp){
        System.out.println("执行前置通知before2() jp = "+ jp);
    }
    public void afterReturning(){
        System.out.println("执行后置通知afterReturning()!");
    }
    //result接收目标方法的返回结果
    //后置通知不能修改目标返回的返回结果本身
    public void afterReturning2(Object res){
        System.out.println("执行后置通知afterReturning2()目标方法的返回结果为result = "+ res +"aaa");
    }
    //环绕通知中来调用目标方法确定目标方法的执行时间
    //环绕通知可以改变目标方法的返回结果本身
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("执行环绕通知-目标方法执行之前!");
        //目标方法执行
        Object proceed = pjp.proceed();
        System.out.println("执行环绕通知-目标方法执行之后");
        if (proceed != null){
            proceed = proceed.toString().toUpperCase();
        }
        return proceed;
    }
    public void afterThrowing(){
        System.out.println("执行异常通知afterThrowing()");
    }
    public void afterThrowing2(Exception ex){
        System.out.println("执行异常通知afterThrowing2() ex = "+ex);
    }
    public void after(){
        System.out.println("执行最终同时after()");
    }
}

引入约束

引入spring对aop的约束即可

AOP配置

<!--注册切面:交叉业务逻辑对象-->
<bean id="myAspect" class="com.abc.service.MyAspect"/>

<aop:config>
    <!--定义切入点表达式-->
    <aop:pointcut id=" " expression=""/>
    <aop:pointcut id=" " expression=""/>
    <!--配置切面-->
    <!--切面为切入点+通知-->
    <aop:aspect ref="myAspect">
    	<!--前置通知,引用切入点表达式-->
        <aop:before method=" " pointcut-ref=""/>
        <!--后置通知-->
        <aop:after-returning method=" " pointcut-ref=" " returning="res"/>
        <!--环绕通知-->
        <aop:around method=" " pointcut-ref=" "/>
        <!--异常通知-->
        <aop:after-throwing method=" " pointcut-ref=" "/>
        <!--最终通知-->
        <aop:after method=" " pointcut-ref=" "/>
</aop:config>

基于注解的AspectJ编程

  1. 导入jar包

  2. 定义切面类

  3. 引入约束

  4. 注册AspectJ自动代理生成器

    <!--注册aspectj的自动代理-->
    <aop:aspectj-autoproxy/>
    
  5. 在切面类中添加注解

//切面:交叉业务逻辑
@Aspect   //该类是切面类
public class MyAspect {
    @Before("doFirstPC()")
    public void before(){
        System.out.println("执行前置通知before()!");
    }
    @Before("doAllPC()")
    public void before2(JoinPoint jp){
        System.out.println("执行前置通知before2() jp = "+ jp);
    }

    @AfterReturning("doSecondPC()")
    public void afterReturning(){
        System.out.println("执行后置通知afterReturning()!");
    }
    //result接收目标方法的返回结果
    //后置通知不能修改目标返回的返回结果本身
    @AfterReturning(value = "doSecondPC()",returning = "res")
    public void afterReturning2(Object res){
        System.out.println("执行后置通知afterReturning2()目标方法的返回结果为result = "+ res +"aaa");
    }

    //环绕通知中来调用目标方法确定目标方法的执行时间
    //环绕通知可以改变目标方法的返回结果本身
    @Around("doThirdPC()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("执行环绕通知-目标方法执行之前!");
        //目标方法执行
        Object proceed = pjp.proceed();
        System.out.println("执行环绕通知-目标方法执行之后");
        if (proceed != null){
            proceed = proceed.toString().toUpperCase();
        }
        return proceed;
    }

    @AfterThrowing("doSecondPC()")
    public void afterThrowing(){
        System.out.println("执行异常通知afterThrowing()");
    }
    @AfterThrowing(value = "doSecondPC()",throwing = "ex")
    public void afterThrowing2(Exception ex){
        System.out.println("执行异常通知afterThrowing2() ex = "+ex);
    }

    @After("doSecondPC()")
    public void after(){
        System.out.println("执行最终同时after()");
    }

    @Pointcut("execution(* *..SomeServiceImpl.doFirst())")
    public void doFirstPC(){};
    @Pointcut("execution(* *..SomeServiceImpl.doSecond())")
    public void doSecondPC(){};
    @Pointcut("execution(* *..SomeServiceImpl.doThird())")
    public void doThirdPC(){};
    @Pointcut("execution(* *..SomeServiceImpl.*())")
    public void doAllPC(){};
}


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM