SpringAop的使用

本篇文章查看博客Spring入门第七讲——Spring AOP的注解开发写的非常好,只所以在写,是为了加深自己的理解。,这里只是aop的使用,aop的原理等看大佬博客Spring入门第六讲——Spring AOP的XML开发

环境搭建

Spring核心容器包(spring的所有模块都构建在核心容器之上,所以导入核心容器包构建的就是最基础的运行环境)
在这里插入图片描述
此外还需要一个日志接口包:
在这里插入图片描述
ps:上面所引入的依赖包仅能实现基本功能,但比如spring的事务管理、aop这些还需要引入其他的包。

本文的aop功能所需的jar包有如下的5个:

还需要如下的几个包:
在这里插入图片描述

Spring aop的使用(基于xml)

编写目标类
首先,在src目录下创建一个com.yongbin.spring.aop的包,并在该包下创建一个为ProductDao的接口。

/**
 * @author 刘瘦瘦
 * @create 2021-07-03-16:45
 */
public interface ProductDao {

    public void save();
    public void update();
    public void find();
    public void delete();
}

接着,在com.yongbin.spring.aop包下创建以上接口的一个实现类----ProductDaoImpl.java。

/**
 * @author 刘瘦瘦
 * @create 2021-07-03-16:46
 */
public class ProductDaoImpl implements ProductDao{
    @Override
    public void save() {
        System.out.println("保存商品");
    }

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

    @Override
    public void find() {
        System.out.println("查找商品");
    }

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

创建增强的类以及增强的方法
先在来了这样一个需要:我们想在ProductDaoImpl实现了的save方法执行之前,进行一个权限校验,那该咋弄?这时我们编写一个切面类,并在切面类中编写一个进行权限校验的方法。待会,我们就在Spring配置文件中对其进行配置,让切面类中的权限校验方法在save方法执行之前执行。

/*
切面类
 */
public class MyAspectXml {
    /*
        前置通知

        权限校验方法
     */
    public void checkPri(){
        System.out.println("权限校验~~~~");
    }
}

在Spring配置文件中进行配置
xml中的配置(如果你有其他功能(开启组件扫描所需的context名称空间等),注意进行保留,在原来的基础上增加aop的xsd)
在这里插入图片描述
然后在Spring配置文件配置好目标对象(即被增强的对象)和切面类。

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

        <!--配置目标对象,即被增强的对象-->
    <bean id="productDao" class="com.yongbin.spring.aop.ProductDaoImpl"></bean>

        <!--将编写好的切面类交给spring去管理-->
    <bean id="myAspect" class="com.yongbin.spring.aop.MyAspectXml"></bean>
</beans>

接着,通过AOP的配置来完成对目标对象去产生代理。
在这里插入图片描述
在com.yongbin.spring.aop的包中创建SpringDemo测试类

 public class SpringDemo {
    @Test
    public void test1(){
        ApplicationContext context=new ClassPathXmlApplicationContext("bean.xml");
        //错误的ProductDaoImpl productDao = (ProductDaoImpl) context.getBean("productDao");
        ProductDao productDao = (ProductDao) context.getBean("productDao");
        productDao.save();
        productDao.update();
        productDao.find();
        productDao.delete();
    }
}

在这里插入图片描述
Spring整合Junit单元测试
其实,Spring也可以整合JUnit单元测试,Spring对JUnit4进行了支持,可以通过注解方便的测试Spring程序,所以就不必写那么麻烦的单元测试类了。如果Spring真要整合JUnit单元测试,那么首先得导入如下jar包(可以在你下载的spring框架中找到):
在这里插入图片描述
然后,将SpringDemo的单元测试类改成下面的样子。

/**
 * @author 刘瘦瘦
 * @create 2021-07-03-17:06
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:bean.xml")//加载类路径下的配置文件
public class SpringDemo {
    
    //想用谁,就注入谁(但是注意这个类得交给Spring管,我们已经在bean.xml中的bean标签进行了创建)
    @Resource(name="productDao")
    private ProductDao productDao;

    @Test
    public void demo01() {
        productDao.save();//作断点调试,可以看到使用到的是JDK的动态代理:JdkDynamicAopProxy
        productDao.update();
        productDao.find();
        productDao.delete();
    }

}

运行结果:
在这里插入图片描述

SpringAop xml配置方式的步骤总结:
配置之前要有:
1、创建要被增强的类(当然有连接点(即方法))
2、创建增强的类
配置xml
1、在idea中生成的springxml文件中添加aop名称空间
在这里插入图片描述

2、配置目标对象,即被增强的对象
在这里插入图片描述

3、将编写好的切面类交给spring管理(使用bea标签创建切面类的对象)
在这里插入图片描述

4、通过配置来完成对目标类去产生代理(比较复杂
切面:包括切入点和增强(通知))。
在这里插入图片描述

总体配置图:
在这里插入图片描述

切点
在xml中,用<aop:pointcut expression="..." id="..."/>来声明一个切点,使得增强可以针对一个切点来进行。其中id是用于标识一个切点的;expression是用来表示切点的位置的,表示增强用于哪个类的哪个方法上。

切面
在xml中,用<aop:aspect ref="..."></aop:aspect>来声明一个切面,声明切面怎么对切点增强。

  • aop:aspect 的属性:
    • ref用来引用spring管理的切面类的bean。
    • order:用与多个切面处理同一个切点的时候,决定它们之间的顺序。没有的时候,多个切面处理一个切点的时候,顺序是乱的,如果想有顺序的,需要使用order。
  • 通知类型【aop:aspect 下使用各种通知类型来定义什么时候对切点进行增强】
    • 前置通知:<aop:before method=“调用的方法” pointcut-ref=“切点id”/>
    • 后置通知:<aop:after method=“调用的方法” pointcut-ref=“切点id” />
    • 环绕通知:<aop:around method=“调用的方法” pointcut-ref=“切点id” />
    • 返回通知:<aop:after-returning method=“调用的方法” pointcut-ref=“切点id” />
    • 异常抛出通知:<aop:after-throwing method=“调用的方法” pointcut-ref=“切点id” />

前置通知
前置通知是指在目标方法执行之前进行操作。上面我演示的就是前置通知,只不过,还有一点我还没有说到,那就是前置通知还可以获得切入点的信息。为了验证这一点,我们可以将以上MyAspectXML切面类修改成下面这个样子。

/*
切面类
 */
public class MyAspectXml {
    /*
        前置通知

        权限校验方法
     */
    public void checkPri(JoinPoint jp){
        System.out.println("权限校验~~~~");
        System.out.println(jp);
    }
}

此时,Spring的配置文件不用做修改,试着运行一下SpringDemo单元测试类中的demo01方法,你就会看到Eclipse控制台打印出了如下内容。
在这里插入图片描述
后置通知
后置通知是指在目标方法执行之后进行操作。它除了可以获得切入点的信息外,还可以获得方法的返回值。为了验证这一点,首先,将ProductDao接口修改成下面这个样子(主要是修改 了一下delete方法的声明,让其返回一个字符串)。

public interface ProductDao {

    public void save();
    public void update();
    public void find();
//    public void delete();
    public String delete();

}

然后,将以上接口的实现类(ProductDaoImpl.java)修改成下面这个样子。

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

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

    @Override
    public void find() {
        System.out.println("查找商品");
    }

    @Override
    public String delete() {
        System.out.println("删除商品");
        return "删除商品成功";
    }
}

接着,在MyAspectXML切面类中添加一个日志记录的方法,一定要注意方法中参数的写法。
在这里插入图片描述

紧接着,还需要配置切入点和切面
在这里插入图片描述
最后,运行一下SpringDemo单元测试类中的demo01方法,你就会看到IDEA控制台打印出了如下内容。
在这里插入图片描述
环绕通知
环绕通知是功能最强的一个通知,它是指在目标方法执行之前和执行之后进行操作。环绕通知可以用来拦截方法,所以它需要“放行”才能正常环绕,在方法中需要定义一个形参ProceedingJoinPoint pj(会自动传入值),然后pj.proceed()就可以放行了。
。为了验证这一点,我们可以在以上MyAspectXml切面类中添加一个性能监控的方法。

/*
切面类
 */
public class MyAspectXml {
    //前置通知 权限校验方法
    public void checkPri(JoinPoint jp){
        System.out.println("权限校验~~~~");
        System.out.println(jp);
    }
    // 日志记录方法
    public void writeLog(Object result){
        System.out.println("日志记录--------"+result);
    }

    //性能监控
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("环绕前增强~~~~");
        Object obj = joinPoint.proceed();//相当于执行目标程序,有可能会有返回值(可以获得被增强方法的返回值)
        System.out.println("环绕后增强~~~~");
        return obj;
    }

}

接着配置切入点和切面。这里,咱主要是在ProductDaoImpl实现类中的update方法(目标方法)执行之前和之后做一些事。
在这里插入图片描述
最后,运行一下SpringDemo单元测试类中的demo01方法,你就会看到IDEA控制台打印出了如下内容。
在这里插入图片描述
异常抛出通知
异常抛出通知是指在程序出现异常的时候而进行的操作,而且它还可以获得异常的信息。异常抛出通知能想到的一个应用场景就是在事务管理的时候会用到。为了验证这一点,首先,修改一下ProductDaoImpl实现类中的find方法,使其抛出一个除零异常。

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

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

    @Override
    public void find() {
        System.out.println("查找商品");
        int i=10/0;
    }

    @Override
    public String delete() {
        System.out.println("删除商品");
        return "删除商品成功";
    }
}

然后,在MyAspectXML切面类中添加一个异常抛出的方法,一定要注意方法中参数的写法哟!
在这里插入图片描述
紧接着要配置切入点和切面
在这里插入图片描述
最后,运行SpringDemo单元测试类中的demo01方法,你就会看到idea控制台打印出了如下内容。
在这里插入图片描述
最终通知
无论目标方法是否出现异常,最终通知都会执行。此时,我们已经知道了ProductDaoImpl实现类中的find方法(也即目标方法)抛出了一个除零异常。现在,咱就是要看看find方法(也即目标方法)出现了异常,最终通知会不会执行。为了验证这一点,我们在以上MyAspectXML切面类中添加如下的一个after方法。

/*
切面类
 */
public class MyAspectXml {
    //前置通知 权限校验方法
    public void checkPri(JoinPoint jp){
        System.out.println("权限校验~~~~");
        System.out.println(jp);
    }
    // 日志记录方法
    public void writeLog(Object result){
        System.out.println("日志记录--------"+result);
    }

    //性能监控
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("环绕前增强~~~~");
        Object obj = joinPoint.proceed();//相当于执行目标程序,有可能会有返回值
        System.out.println("环绕后增强~~~~");
        return obj;
    }

    //异常抛出
    public void afterThrowing(Throwable ex){
        System.out.println("异常抛出通知~~~~~~"+ex.getMessage());
    }

    //最终通知:相当于finally代码块中的内容
    public void after(){
        System.out.println("最终通知~~~~");
    }

}

接着配置切入点和切面。
在这里插入图片描述
最后,运行SpringDemo单元测试类中的demo01方法,你就会看到idea控制台打印出了如下内容。
在这里插入图片描述
从上面输出的结果中,我们就证明了即使目标方法出现了异常,最终通知也会执行。

Spring中切入点表达式的写法

表达式的原型:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

了解完上面的知识点以后,你可以试着解决一下这个需求:在ProductDaoImpl实现类中的所有方法执行之前,应用前置增强。此时,你的Spring配置文件可能要改成下面这个样子。
在这里插入图片描述

Spring aop的使用(基于注解)

创建web项目,引入jar包
首先创建一个动态web项目,例如spring_demo03_aop,然后导入Spring框架相关依赖jar包,要导入哪些jar包呢?这里不废话,直接给出要导入的jar包。
在这里插入图片描述

引入相关配置文件
首先,引入Spring的配置文件,在该文件中应引入aop约束,这样一开始applicationContext.xml文件的内容就应该是下面的样子。

<?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">

</beans>

编写目标类并配置
首先,在src目录下创建一个com.yongbin.spring.demo3包,并在该包下创建一个名为OrderDao的类。

public class OrderDao {
    public void save(){
        System.out.println("保存订单");
    }
    
    public void update(){
        System.out.println("修改订单");
    }
    
    public void delete(){
        System.out.println("删除订单");
    }
    
    public void find(){
        System.out.println("查询订单");
    }
}

然后,在spring配置文件中对以上目标类进行配置
在这里插入图片描述
编写切面类并配置
现在有这样一个需求:我们想在OrderDao类的save方法执行之前,就简简单单地执行一个操作,那该咋怎呢?这时我们可以编写一个切面类,并在切面类中随便编写一个方法,例如下面的before方法。待会,我们就使用注解对该切面类进行增强,让切面类中的before方法在目标类的save方法执行之前执行。

public class MyAspectAnno {
    public void before() {
        System.out.println("前置增强--------------------");
    }
}

接着,在spring配置文件中对以上切面类进行配置。
在这里插入图片描述
使用注解对目标类进行增强
首先,我们需要在Spring的配置文件中开启注解的AOP开发。
在这里插入图片描述
然后,我们就可以在切面类(增强类)上使用注解了。

@Aspect //表明这是一个切面类
public class MyAspectAnno {
    //@Before注解代表前置增强,还要告诉Spring在哪个类上的哪个方法上应用前置增强
    @Before(value = "execution(* com.yongbin.spring.demo3.OrderDao.save(..))")
    public void before() {
        System.out.println("前置增强--------------------");
    }
}

温馨提示:@Aspect生成代理类对象,@Before注解代表的是前置通知。
编写测试类并进行测试
在com.yonginb.spring.demo3下新建SpringDemo01类

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(value = "classpath:application.xml")
public class SpringDemo01 {

    @Resource(name = "orderDao")
    private OrderDao orderDao;

    @Test
    public void demo1(){
        orderDao.save();//作断点调试,可以看到使用到的是Cglib的动态代理:CglibAopProxy
        orderDao.update();
        orderDao.delete();
        orderDao.find();
    }

}

idea控制填的显示:
在这里插入图片描述

Spring Aop注解开发中的通知类型

Spring AOP注解开发入门之后,咱就来看一下AOP注解开发中的通知类型。

前置通知

前置通知是指在目标方法执行之前进行操作。上面我演示的就是前置通知,这里不再赘述。

后置通知

后置通知是指在目标方法执行之后进行操作。它除了可以获得切入点的信息以外,还可以获得方法的返回值。为了验证这一点,首先,将OrderDao类修改成下面这个样子(主要是修改了一下delete方法,让其返回一个字符串)。

public class OrderDao {
    public void save(){
        System.out.println("保存订单");
    }

    public void update(){
        System.out.println("修改订单");
    }

    public String delete(){
        System.out.println("删除订单");
        return "删除订单成功";
    }

    public void find(){
        System.out.println("查询订单");
    }
}

然后,在MyAspectAnno切面类中添加一个afterReturning方法,并在该方法上使用@AfterReturning注解,告诉Spring要在OrderDao类中的delete方法上应用后置通知。

@Aspect //表明这是一个切片类
public class MyAspectAnno {
    //@Before注解代表前置增强,还要告诉Spring在哪个类上的哪个方法上应用前置增强
    @Before(value = "execution(* com.yongbin.spring.demo3.OrderDao.save(..))")
    public void before() {
        System.out.println("前置增强--------------------");
    }

    //后置通知
    @AfterReturning(value = "execution(* com.yongbin.spring.demo3.OrderDao.delete(..))",returning = "result")
    public void afterRunning(Object result){
        System.out.println("后置增强:"+result);//这儿的result一定得跟returning="result"中的result对应上
    }
}

在上面的前置通知演示时,我们的目标类对象和切面类对象都是通过bean标签生成的,下面我们该为使用注解的方式。
使用注解生成对象并第一步需要:
引入context名称空间,并开启组件扫描
在这里插入图片描述
然后在切面类上使用了@Component注解生成切面类对象

@Component
@Aspect //表明这是一个切面类
public class MyAspectAnno {
    //@Before注解代表前置增强,还要告诉Spring在哪个类上的哪个方法上应用前置增强
    @Before(value = "execution(* com.yongbin.spring.demo3.OrderDao.save(..))")
    public void before() {
        System.out.println("前置增强--------------------");
    }

    //后置通知
    @AfterReturning(value = "execution(* com.yongbin.spring.demo3.OrderDao.delete(..))",returning = "result")
    public void afterRunning(Object result){
        System.out.println("后置增强:"+result);//这儿的result一定得跟returning="result"中的result对应上
    }
}

在目标类使用@Repository(value=“orderDao”)生成目标类对象。

@Repository(value = "orderDao")
public class OrderDao {
    public void save(){
        System.out.println("保存订单");
    }

    public void update(){
        System.out.println("修改订单");
    }

    public String delete(){
        System.out.println("删除订单");
        return "删除订单成功";
    }

    public void find(){
        System.out.println("查询订单");
    }
}

编写测试类并进行测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(value = "classpath:application.xml")
public class SpringDemo01 {

    @Resource(name = "orderDao")
    private OrderDao orderDao;

    @Test
    public void demo1(){
        orderDao.save();//作断点调试,可以看到使用到的是Cglib的动态代理:CglibAopProxy
        orderDao.update();
        orderDao.delete();
        orderDao.find();
    }

}

控制台输出信息:
在这里插入图片描述

环绕通知

环绕通知是功能最强的一个通知,它是指在目标方法执行之前和之后进行操作。很重要的一点就是它可以阻止目标方法的执行。为了验证这一点,我们可以在MyAspectAnno切面类中添加一个如下的around方法,并在该方法上使用@Around注解,告诉Spring要在OrderDao类中的update方法上应用环绕通知。

@Component
@Aspect //表明这是一个切面类
public class MyAspectAnno {
    //@Before注解代表前置增强,还要告诉Spring在哪个类上的哪个方法上应用前置增强
    @Before(value = "execution(* com.yongbin.spring.demo3.OrderDao.save(..))")
    public void before() {
        System.out.println("前置增强--------------------");
    }

    //后置通知
    @AfterReturning(value = "execution(* com.yongbin.spring.demo3.OrderDao.delete(..))",returning = "result")
    public void afterRunning(Object result){
        System.out.println("后置增强:"+result);//这儿的result一定得跟returning="result"中的result对应上
    }

    //环绕通知
    @Around(value = "execution(* com.yongbin.spring.demo3.OrderDao.update(..))")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("环绕前增强--------------------");
        Object obj = joinPoint.proceed();//执行我们的目标方法,它会返回一个Object
        System.out.println("环绕后增强--------------------");
        return obj;
    }
}

接着运行上面的测试方法,控制台打印:
在这里插入图片描述

异常通知

异常抛出通知是指在程序出现异常的时候而进行的操作,而且它还可以获得异常的信息。异常抛出通知能想到的一个应用场景就是在事务管理的时候会用到。为了验证这一点,首先,修改一下OrderDao类中的find方法,使其抛出一个除零异常。

@Repository(value = "orderDao")
public class OrderDao {
    public void save(){
        System.out.println("保存订单");
    }

    public void update(){
        System.out.println("修改订单");
    }

    public String delete(){
        System.out.println("删除订单");
        return "删除订单成功";
    }

    public void find(){
        System.out.println("查询订单");
        int i=1/0;
    }
}

然后,在MyAspectAnno切面类中添加如下一个afterThrowing方法,并在该方法上使用@AfterThrowing注解,告诉Spring要在OrderDao类中的find方法上应用异常抛出通知。

@Component
@Aspect //表明这是一个切面类
public class MyAspectAnno {
    //@Before注解代表前置增强,还要告诉Spring在哪个类上的哪个方法上应用前置增强
    @Before(value = "execution(* com.yongbin.spring.demo3.OrderDao.save(..))")
    public void before() {
        System.out.println("前置增强--------------------");
    }

    //后置通知
    @AfterReturning(value = "execution(* com.yongbin.spring.demo3.OrderDao.delete(..))",returning = "result")
    public void afterRunning(Object result){
        System.out.println("后置增强:"+result);//这儿的result一定得跟returning="result"中的result对应上
    }

    //环绕通知
    @Around(value = "execution(* com.yongbin.spring.demo3.OrderDao.update(..))")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("环绕前增强--------------------");
        Object obj = joinPoint.proceed();//执行我们的目标方法,它会返回一个Object
        System.out.println("环绕后增强--------------------");
        return obj;
    }

    //异常抛出通知
    @AfterThrowing(value ="execution(* com.yongbin.spring.demo3.OrderDao.find(..))",throwing = "e")
    public void afterThrowing(Throwable e){这儿的e一定得跟throwing="e"中的e对应上
        System.out.println("异常抛出增强~~~"+e.getMessage());
    }
}

控制台打印结果:
在这里插入图片描述

在这里插入图片描述

最终通知

无论目标方法是否出现异常,最终通知都会执行。此时,我们已经知道了OrderDao类中的find方法(也即目标方法)抛出了一个除零异常。现在,咱就是要看看find方法(也即目标方法)出现了异常,最终通知会不会执行。为了验证这一点,我们在MyAspectAnno切面类中添加如下的一个after方法,并在该方法上使用@After注解,告诉Spring要在OrderDao类中的find方法上应用最终通知。

@Component
@Aspect //表明这是一个切面类
public class MyAspectAnno {
    //@Before注解代表前置增强,还要告诉Spring在哪个类上的哪个方法上应用前置增强
    @Before(value = "execution(* com.yongbin.spring.demo3.OrderDao.save(..))")
    public void before() {
        System.out.println("前置增强--------------------");
    }

    //后置通知
    @AfterReturning(value = "execution(* com.yongbin.spring.demo3.OrderDao.delete(..))",returning = "result")
    public void afterRunning(Object result){
        System.out.println("后置增强:"+result);//这儿的result一定得跟returning="result"中的result对应上
    }

    //环绕通知
    @Around(value = "execution(* com.yongbin.spring.demo3.OrderDao.update(..))")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("环绕前增强--------------------");
        Object obj = joinPoint.proceed();//执行我们的目标方法,它会返回一个Object
        System.out.println("环绕后增强--------------------");
        return obj;
    }

    //异常抛出通知
    @AfterThrowing(value ="execution(* com.yongbin.spring.demo3.OrderDao.find(..))",throwing = "e")
    public void afterThrowing(Throwable e){这儿的e一定得跟throwing="e"中的e对应上
        System.out.println("异常抛出增强~~~"+e.getMessage());
    }
    
    //最终通知
    @After(value ="execution(* com.yongbin.spring.demo3.OrderDao.find(..))" ) 
    public void after(){
        System.out.println("最终增强~~~~");
    }
}

查看控制台
在这里插入图片描述

Spring Aop注解开发中的切入点配置

假设切面类里面有很多种通知,但它们都需要作用于目标类的同一个方法上,比如说find方法,假如说我有一天不想作用在find方法上了,而想作用在save方法或者update方法上,那该咋办呢?这时,我们得到切面类里面一个一个改,如果切面类这里面的通知很多,那么我们是不是得改好几个啊!这势必会很麻烦!为了解决这种问题,咱可以使用@Pointcut注解来定义切入点。例如,咱可以在MyAspectAnno切面类里面定义如下一些切入点。
在这里插入图片描述
那么,我们怎么把之前写好的各种类型的通知应用在这些切入点上呢?也就是说MyAspectAnno切面类定义了以上一系列切入点之后,可以修改成下面这个样子。

@Component
@Aspect //表明这是一个切面类
public class MyAspectAnno {

    /*
        这里面有一个问题:假设我这里面有很多种通知,但都需要作用于同一个方法上,
        比如说find()方法,假如我有一天不想作用再find()方法上了,我想作用再save()方法或者update()
        方法上,咋办呢?你是不是得到这边一个一个改啊!那如果我这里面的通知很多,
        但都作用于一个方法上,你是不是得改好几个啊?很麻烦!

     */
    //切入点的注解
    @Pointcut(value = "execution(* com.yongbin.spring.demo3.OrderDao.find(..))")
    private void pointcut1(){}//该方法没有特殊的意义,私有就行
    @Pointcut(value = "execution(* com.yongbin.spring.demo3.OrderDao.save(..) )")
    private void pointcut2(){}
    @Pointcut(value = "execution(* com.yongbin.spring.demo3.OrderDao.update(..) )")
    private void pointcut3(){}
    @Pointcut(value = "execution(* com.yongbin.spring.demo3.OrderDao.delete(..) )")
    private void pointcut4(){}

    //@Before注解代表前置增强,还要告诉Spring在哪个类上的哪个方法上应用前置增强
    @Before(value = "MyAspectAnno.pointcut2()")
    public void before() {
        System.out.println("前置增强--------------------");
    }

    //后置通知
    @AfterReturning(value = "MyAspectAnno.pointcut4()",returning = "result")
    public void afterRunning(Object result){
        System.out.println("后置增强:"+result);//这儿的result一定得跟returning="result"中的result对应上
    }

    //环绕通知
    @Around(value = "MyAspectAnno.pointcut2())")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("环绕前增强--------------------");
        Object obj = joinPoint.proceed();//执行我们的目标方法,它会返回一个Object
        System.out.println("环绕后增强--------------------");
        return obj;
    }

    //异常抛出通知
    @AfterThrowing(value ="MyAspectAnno.pointcut1()",throwing = "e")
    public void afterThrowing(Throwable e){这儿的e一定得跟throwing="e"中的e对应上
        System.out.println("异常抛出增强~~~"+e.getMessage());
    }

    //最终通知
    @After(value ="MyAspectAnno.pointcut1()" )
    public void after(){
        System.out.println("最终增强~~~~");
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值