【SSM】AspectJ开发AOP流程

本文介绍了AspectJ在Spring AOP中的应用,包括@AspectJ的通知类型:@Before、@AfterReturning、@Around、@AfterThrowing和@After。详细讲解了切点的定义、切面类的创建及配置,以及@Pointcut的使用,帮助理解AOP的实战操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

一、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包

<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>5.1.7.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>aopalliance</groupId>
            <artifactId>aopalliance</artifactId>
            <version>1.0</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.9</version>
        </dependency>
        <dependency>
            <groupId>com.xyz.spring</groupId>
            <artifactId>spring_aspect</artifactId>
            <version>1.0-SNAPSHOT</version>
</dependency>

applicationContext.xml配置文件 

          使用<aop:aspectj-autoproxy/>就可以使用AspectJ的注解

<?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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--开启AspectJ的注解开发,自动代理=====================-->
    <aop:aspectj-autoproxy/>
</beans>

二、@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("前置通知");
    }
}

        在配置文件中将类配置

<?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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--开启AspectJ的注解开发,自动代理=====================-->
    <aop:aspectj-autoproxy/>
    <!--目标类-->
    <bean id="ProductDao" class="com.xyz.aspectj.demo1.ProductDao"/>
    <!--切面类-->
    <bean class="com.xyz.aspectj.demo1.MyAspectAnno"/>
</beans>

     2.使用AspectJ进行AOP开发

①:@Before前置通知

   

@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指定的前置通知 

 

②:@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();
    }
}

 

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

  修改切面类,在@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);
    }
}

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

③:@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;
    }
}

            将目标方法修改为下图          

 

            测试结果

         如果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(){}
}

      

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值