(三)Spring超全面快速入门-AspectJ开发

1、@AspectJ提供不同的通知类型

  • @Before 前置通知,相当于MethodBeforeAdvice

  • @AfterReturning 后置通知,相当于AfterReturningAdvice

  • @Around 环绕通知,相当于MethodInterceptor

  • @AfterThrowing异常抛出通知,相当于ThrowAdvice

  • @After 最终final通知,不管是否异常,该通知都会执行(相当于finally代码块)

  • @DeclareParents 引介通知,相当于IntroductionInterceptor(不必掌握)

2、需要依赖的Jar包

Spring四大基本包: spring-core, spring-context, spring-expression, spring-beans
测试包: junit切记一定要4.1版本或以上,不要使用3.X版本的,否则@Runwith注解用不了
spring测试包: spring-test
AOP联盟aopaliance和spring-aop两个包
AspectJ两个包 :aspectjweaver和spring-aspects

3、入门案例

还是老三样:目标类、通知类、配置信息
目标类:

package demo1;

public class UserDaoImpl implements UserDao {
    @Override
    public void insert() {
        System.out.println("新增用户...");
    }

    @Override
    public void update() {
        System.out.println("更新用户...");
    }

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

    @Override
    public void findin() {
        System.out.println("查找用户...");
    }
}

通知类:

package demo1;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class MyAspectJAnno {

    @Before(value="execution(* demo1.UserDaoImpl.*(..))")
    public void before() {
        System.out.println("==========前置通知========");
    }

}

需要注意的是应该在类前面加@Aspect注解,这样才能使其变成切面类,在要执行通知的前面加@Before注解,后面的value里面是"execution(要增强的目标类信息的包,正则表达式)"
看下配置文件:

<?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="userDao" class="demo1.UserDaoImpl"/>
    <!--定义切面-->
    <bean class="demo1.MyAspectJAnno"/>
</beans>

看下运行结果:
在这里插入图片描述
是不是超级简单?

4、@Before前置通知

@Before
可以在方法中传入JoinPoint对象,用来获得切点信息:
在这里插入图片描述
看下打印结果:
在这里插入图片描述

5、@AfterReturning后置通知

@AfterReturning
也很简单,和前置差不多,比如在查找方法后增加后置增强:

    @AfterReturning(value = "execution(* demo1.UserDaoImpl.findin(..))")
    public void afterReturning(JoinPoint joinPoint) {
        System.out.println("后置通知=========="+joinPoint);
    }

在这里插入图片描述
当然后置通知还可以返回参数,比如我们把findin方法改成了返回值为String的方法,然后,只需这样配置:
在这里插入图片描述
切记returning后的名字和afterReturning方法中的参数名字必须一样才行,看下打印结果:
在这里插入图片描述
这里就是我返回的String

6、@Round环绕通知

  • around方法的返回值是目标代理方法的返回值
  • 参数为ProceedingJoinPoint可以调用拦截目标方法执行
    环绕通知可以在某个方法前后进行增强,当然也可以不执行这个方法,看个例子:
    @Around(value = "execution(* demo1.UserDaoImpl.delete(..))")
    public Object round(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("环绕前增强===========");
        Object obj = joinPoint.proceed();
        System.out.println("环绕后增强===========");
        return obj;
    }

看一下打印结果:
在这里插入图片描述

7、@AfterThrowing异常抛出通知

  • 通过throwing属性,可以设置发生异常对象参数
    必须目标方法抛出异常后才会执行:
    在这里插入图片描述
    经典错误:
    @AfterThrowing(value = "execution(* demo1.UserDaoImpl.update())",throwing = "e")
    public void AfterThrowing(Throwable e) {
        System.out.println("异常抛出通知"+e.getMessage());
    }

然后就可以在遇到错误时打印错误信息了:
在这里插入图片描述

8、@After最终通知

    @After(value = "execution(* demo1.UserDaoImpl.findin())")
    public void Final() {
        System.out.println("最终通知=======================================");
    }

这样就可以完成最终通知,不管会不会报错都会在这个方法后执行:
在这里插入图片描述

9、@Pointcut为切点命名

  • 在每个通知内定义切点,会造成工作量巨大,不易维护,对于重复的切点,可以使用@Pointcut进行定义
  • 切点方法: private void无参数方法,方法名为切点名
  • 当通知有多个切点时,可是使用“||”进行连接
    使用方法:
    @Pointcut(value = "execution(* demo1.UserDaoImpl.findin())")
    private void demo1() {}

只定义一个空方法,然后这个切点就是只增强findin();方法的,然后我们在需要增强findin的通知方法名写成demo1()就可以了:

    @After(value = "demo1()")
    public void Final() {
        System.out.println("最终通知=======================================");
    }

这样就是在findin方法执行后执行最终通知:
在这里插入图片描述
可以看跟以前配置一样,这样就很方便的再次进行了解耦。

10、基于XML的方式开发AOP

目标类还是UserDao,我们看看切面类怎么写:

package demo2;

public class MySpringAdvicor {

    public void before() {
        System.out.println("-*-*-*-*-*-*XML前置增强通知*-*-*-*-*-*-*-");
    }
}

巨简单,什么都不用配置,因为要去配置文件配置,看看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">

    <!--设置目标类-->
    <bean id="userDao" class="demo2.UserDaoImpl"/>

    <!--设置切面类-->
    <bean id="myAdvisor" class="demo2.MySpringAdvicor"/>

    <!--配置切面类-->
    <aop:config>
        <!--设置切入点-->
        <aop:pointcut id="pointcut1" expression="execution(* demo2.UserDao.delete(..))"/>
        <!--设置增强方式-->
        <aop:aspect ref="myAdvisor">
            <aop:before method="before" pointcut-ref="pointcut1"/>
        </aop:aspect>
    </aop:config>
</beans>

需要设置切面类,标签是aop:config,内部一个是aop:aspect表示的是切面是哪个,aop:pointcut表示切入点是哪个类,看看运行结果:
在这里插入图片描述

原文地址:https://www.cnblogs.com/taobean/p/12364250.html