【SSM】AspectJ开发AOP流程

目录

一、AspectJ基本介绍

二、@AspectJ的通知类型

三、在通知中通过value属性定义切点

四、使用案例

    1.首先创建目标类以及切面类

     2.使用AspectJ进行AOP开发

①:@Before前置通知

②:@AfterReturing前置通知

③:@Around环绕通知

④:@AfterThrowing异常抛出通知

⑤:@After最终通知

五、使用@Pointcut 为切点命名

一、AspectJ基本介绍

Aspectj是一个基于Java语言的AOP框架,由于传统AOP开发过于麻烦,Spring2.0后将其添加到自己体系中。

使用AspectJ需要导入Spring AOP 和 AspectJ相关的jar包

需要在spring包的基础上再添加如下jar包


            org.springframework
            spring-aop
            5.1.7.RELEASE
        
        
            aopalliance
            aopalliance
            1.0
        
        
            org.aspectj
            aspectjweaver
            1.8.9
        
        
            com.xyz.spring
            spring_aspect
            1.0-SNAPSHOT

applicationContext.xml配置文件 

          使用就可以使用AspectJ的注解




    
    

二、@AspectJ的通知类型

@Before前置通知,在目标方法执行之前,相当于Beforeadvice
@Afterreturning后置通知,在目标方法执行之后,相当于Afterreturningadvice
@Around环绕通知,在目标方法执行前和执行后,相当于Methodinterceptor
@Afterthrowing异常抛出通知,相当于Throwadvice
@After最终final通知,不管是否异常,该通知都会执行

三、在通知中通过value属性定义切点

通过execution函数,可以定义切点的方法切入

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

           其中访问修饰符可以省略

举例:

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

                                         第一个public是访问修饰符,第一个*是返回类型任意,第二个*是任意方法名,(..)标识任意参数

2.匹配指定包下所有类方法:execution(* com.xyz.dao.*(..))

                                             第一个*代表任意的返回类型,com.xyz.dao.*(..)代表dao包下的所有类的任意方法,但不包含子包

                                             execution(* com.xyz.dao..*(..))         这种写法dao后面两"."是包含dao包及其子包

3.匹配实现了特定接口的所有类方法 :execution(* com.xyz.dao.UserDao+.*(..))

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

四、使用案例

    1.首先创建目标类以及切面类

           创建目标类

public class ProductDao {
    public void save(){
        System.out.println("保存商品");
    }

    public void update(){
        System.out.println("修改商品");
    }

    public void delete(){
        System.out.println("删除商品");
    }

    public void findOne(){
        System.out.println("查询某个商品");
    }

    public void findAll(){
        System.out.println("查询所有商品");
    }
}

        创建创建切面类(需使用@Aspect进行标识)
  

@Aspect
public class MyAspectAnno {
    public void before(){
        System.out.println("前置通知");
    }
}

        在配置文件中将类配置




    
    
    
    
    
    

     2.使用AspectJ进行AOP开发

①:@Before前置通知

   

【SSM】AspectJ开发AOP流程_第1张图片

@Aspect
public class MyAspectAnno {
    @Before(value="execution(* com.xyz.aspectj.demo1.ProductDao.*(..))")
    public void before(){
        System.out.println("前置通知");
    }
}

       测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class Test {

    @Resource(name = "ProductDao")
    private ProductDao productDao;
    @org.junit.Test
    public void demo1(){
        productDao.save();
        productDao.delete();
        productDao.findAll();
        productDao.findOne();
        productDao.update();
    }
}

可以看到在每个方法前都执行了@Before指定的前置通知 

【SSM】AspectJ开发AOP流程_第2张图片 

②:@AfterReturing前置通知

                  在切面类中加上一个@AfterReturining后置通知,并且仅对ProductDao类的update方法起作用

@Aspect
public class MyAspectAnno {
    @Before(value="execution(* com.xyz.aspectj.demo1.ProductDao.*(..))")
    public void before(){
        System.out.println("前置通知");
    }

    @AfterReturning(value = "execution(* com.xyz.aspectj.demo1.ProductDao.update(..))")
    public void after(){
        System.out.println("后置通知!!");
    }
}

            测试 

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class Test {

    @Resource(name = "ProductDao")
    private ProductDao productDao;
    @org.junit.Test
    public void demo1(){
        productDao.save();
        productDao.delete();
        productDao.findAll();
        productDao.findOne();
        productDao.update();
    }
}

【SSM】AspectJ开发AOP流程_第3张图片

 

           后置通知还可以得到方法的返回值,此时将ProductDao方法的update方法改成有返回值的

【SSM】AspectJ开发AOP流程_第4张图片

  修改切面类,在@AfterReturning中新增了一个参数为returning接收返回值,随意命名,但要保证与下面after方法中参数名一直

@Aspect
public class MyAspectAnno {
    @Before(value="execution(* com.xyz.aspectj.demo1.ProductDao.*(..))")
    public void before(){
        System.out.println("前置通知");
    }

    @AfterReturning(value = "execution(* com.xyz.aspectj.demo1.ProductDao.update(..))",returning = "result")
    public void after(Object result){
        System.out.println("后置通知!!"+result);
    }
}

 可以看到测试结果,表明收到了返回值

【SSM】AspectJ开发AOP流程_第5张图片

③:@Around环绕通知

           around()方法的返回值就是目标方法的返回值,使用Object保证任意返回值都OK

           around()方法中的ProceedingJoinPoint参数用来调用目标方法执行,当joinPoint.proceed()就相当于目标方法的执行

@Aspect
public class MyAspectAnno {
    @Around(value = "execution(* com.xyz.aspectj.demo1.ProductDao.delete(..))")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("环绕前通知");
        Object proceed = joinPoint.proceed();
        System.out.println("环绕后通知");
        return proceed;
    }
}

            将目标方法修改为下图          

  【SSM】AspectJ开发AOP流程_第6张图片

            测试结果

【SSM】AspectJ开发AOP流程_第7张图片

         如果joinPoint.proceed()方法不执行,则目标方法也不会执行,这时就可以在这里加一下业务上的判断

④:@AfterThrowing异常抛出通知

          使用该注解在目标方法发生异常时会触发,可以用于事务回滚。

:@After最终通知

          相当于try catch的finally,无论目标方法如何都会执行

五、使用@Pointcut 为切点命名

      在案例4可以看出,添加切点时优点麻烦,每次都要写长长的一串,这时就可以使用@Pointcut简化

举例:下面是案例4的代码,其中execution(* com.xyz.aspectj.demo1.ProductDao.delete(..))表示对包下的delete方法进行环绕通知,如果此时该delete方法有多个通知就可以采用@Pointcut进行别名

@Aspect
public class MyAspectAnno {
    @Around(value = "execution(* com.xyz.aspectj.demo1.ProductDao.delete(..))")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("环绕前通知");
        Object proceed = joinPoint.proceed();
        System.out.println("环绕后通知");
        return proceed;
    }
}

         下图是使用了@Pointcut将execution(* com.xyz.aspectj.demo1.ProductDao.delete(..))直接用myPointcut1()使用

@Aspect
public class MyAspectAnno {
    @Around(value = "myPointcut1()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("环绕前通知");
        Object proceed = joinPoint.proceed();
        System.out.println("环绕后通知");
        return proceed;
    }

    @Pointcut(value = "execution(* com.xyz.aspectj.demo1.ProductDao.delete(..))")
    private void myPointcut1(){}
}

      

 

你可能感兴趣的:(Java)