spring的AspectJ基于XML和注解(前置、后置、环绕、抛出异常、最终通知)

1、概念

(1)AspectJ是一个基于Java语言的AOP框架

(2)Spring2.0以后新增了对AspectJ切入点表达式的支持

(3)AspectJ是AspectJ1.5的新增功能,通过JDK5注解技术,允许在Bean类中定义切面。新版本的Spring框架建议使用AspectJ方式来开发AOP

2、切入点表达式

(1)execution():用语描述方法

语法:execution(修饰符、返回值、包、类、方法(参数)、异常)

修饰符:一般省略

public:公共方法

*:任意

返回值

void:没有返回值

String:返回值为字符串

*:返回值任意

方法:不能省略

参数

(..)参数任意

(2)案例:

 <aop:pointcut id="myPointCut" expression="execution(* pers.zhb.proxy.*.*(..))"></aop:pointcut>

(3)其他表达式

within:匹配包或者子包中的方法

this:匹配接口中代理对象中的方法

target:匹配实现接口的目标对象的方法

args:匹配参数格式符合标准的方法

bean:对指定bean所有的方法

2、AspectJ通知类型

(1)aop联盟定义通知类型:具有特性接口,必须实现,从而确定方法名称。
(2)aspectj通知类型:只定义类型名称。已经方法格式。
before:前置通知(应用:各种校验)

在方法执行前执行,如果通知抛出异常,阻止方法运行

afterRetuming:后置通知(应用:常规数据处理)

方法正常返回后执行,如果方法中抛出异常,通知无法执行

必须在方法执行后才执行,所以可以获得方法的返回值

around:环统通知(应用:十分强大,可以做任何事情)

方法执行前后分别执行,可以阻止方法的执行。
必须手动执行目标方法

afterThrowing:抛出异常通知(应用:包装异常信息)

方法抛出异常后执行,如果方法没有抛出异常,无法执行

after最终通知(应用:清理现场)

方法执行完毕后执行,无论方法中是否出现异常

3、导入jar包(四个)

aop联盟规范

 

spring aop实现

aspect规范

spring aspect实现

 

4、源码

(1)AspectJAfterThrowingAdvice

 (2)AspectJAfterAdvice

5、基于XML文件的配置(前置通知)

(1)目标类的接口和实现类:

public interface StudentService {
     void addStudent();
     void updateStudent();
     void deleteStudent();
}
public class StudentServiceImpl implements StudentService {
    @Override
    public void addStudent() {
        System.out.println("addStudent");
    }

    @Override
    public void updateStudent() {
        System.out.println("updateStudent");
    }

    @Override
    public void deleteStudent() {
        System.out.println("deleteStudent");
    }
}

(2)切面类(含有通知):

public class MyAspect {
    public void before(JoinPoint joinPoint){
        System.out.println("前置通知:"+ joinPoint.getSignature().getName());
    }
}

(3)配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns="http://www.springframework.org/schema/beans"
       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="studentService" class="pers.zhb.aspectxml.StudentServiceImpl"></bean>
    <!--切面类-->
    <bean id="myAspect" class="pers.zhb.aspectxml.MyAspect"></bean>
    <!--aop编程
    将切面类声明为切面,从而获得通知(方法)
    ref:切面类引用
    -->
    <aop:config>
        <aop:aspect ref="myAspect">
            <!--引入切面类,从中获得通知(方法)
                expression:切入点表达式
                id:名称,用于其他通知引用
            -->
            <aop:pointcut id="myPointCut" expression="execution(* pers.zhb.aspectxml.StudentServiceImpl.*(..))"></aop:pointcut>
            <!--
            method:通知,即方法名
            pointcut:切入点表达式,此表达式只能当前通知使用
            pointcut-ref:切入点的引用,可以和其它通知共享切入点
            -->
            <aop:before method="before" pointcut-ref="myPointCut"></aop:before>
        </aop:aspect>
    </aop:config>
</beans>

(4)测试类:

public class TestAspectXml {
    public static void main(String[] args) {
        ApplicationContext applicationContext=new
                ClassPathXmlApplicationContext("applicationContext.xml");
        //获得目标类
        pers.zhb.aspectxml.StudentService studentService= (StudentService) applicationContext.getBean("studentService");
        studentService.addStudent();
        studentService.deleteStudent();
        studentService.updateStudent();
    }
}
前置通知:addStudent
addStudent
前置通知:deleteStudent
deleteStudent
前置通知:updateStudent
updateStudent

6、基于XML文件的配置(后置通知)

(1)定义接口和接口的实现类:

public interface StudentService {
     void addStudent();
     void updateStudent();
     String deleteStudent();
}
public class StudentServiceImpl implements StudentService {
    @Override
    public void addStudent() {
        System.out.println("addStudent");
    }

    @Override
    public void updateStudent() {
        System.out.println("updateStudent");
    }

    @Override
    public String deleteStudent() {
        System.out.println("deleteStudent");
        return "nihao";
    }
}

(2)切面类:

public class MyAspect {
    public void before(JoinPoint joinPoint){
        System.out.println("前置通知:"+ joinPoint.getSignature().getName());
    }

    public void after(JoinPoint joinPoint,Object ret){//参数一:连接点描述
        //参数二:类型Object,参数名returning配置的
        System.out.println("后置通知:"+ joinPoint.getSignature().getName()+"   "+ret);
    }
}

(3)配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns="http://www.springframework.org/schema/beans"
       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="studentService" class="pers.zhb.aspectxml.StudentServiceImpl"></bean>
    <!--切面类-->
    <bean id="myAspect" class="pers.zhb.aspectxml.MyAspect"></bean>
    <!--aop编程
    将切面类声明为切面,从而获得通知(方法)
    ref:切面类引用
    -->
    <aop:config>
        <aop:aspect ref="myAspect">
            <!--引入切面类,从中获得通知(方法)
                expression:切入点表达式
                id:名称,用于其他通知引用
            -->
            <aop:pointcut id="myPointCut" expression="execution(* pers.zhb.aspectxml.StudentServiceImpl.*(..))"></aop:pointcut>
            <!--
            method:通知,即方法名
            pointcut:切入点表达式,此表达式只能当前通知使用
            pointcut-ref:切入点的引用,可以和其它通知共享切入点
            returning:通知方法第二个参数的名称
            -->
            <aop:before method="before" pointcut-ref="myPointCut"></aop:before>
            <aop:after-returning method="after" pointcut-ref="myPointCut" returning="ret"></aop:after-returning>

        </aop:aspect>
    </aop:config>
</beans>

(4)测试类:

public class TestAspectXml {
    public static void main(String[] args) {
        ApplicationContext applicationContext=new
                ClassPathXmlApplicationContext("applicationContext.xml");
        //获得目标类
        pers.zhb.aspectxml.StudentService studentService= (StudentService) applicationContext.getBean("studentService");
        studentService.addStudent();
        studentService.deleteStudent();
        studentService.updateStudent();
    }
}
前置通知:addStudent
addStudent
后置通知:addStudent   null
前置通知:deleteStudent
deleteStudent
后置通知:deleteStudent   nihao
前置通知:updateStudent
updateStudent
后置通知:updateStudent   null

7、基于XML文件的配置(环绕通知)

(1)切面类:

public class MyAspect {
    public void before(JoinPoint joinPoint){
        System.out.println("前置通知:"+ joinPoint.getSignature().getName());
    }

    public void after(JoinPoint joinPoint,Object ret){//参数一:连接点描述
        //参数二:类型Object,参数名returning配置的
        System.out.println("后置通知:"+ joinPoint.getSignature().getName()+"   "+ret);
    }
    public Object around(ProceedingJoinPoint proceedingJoinPoint)throws Throwable{
        //手动执行目标方法
        System.out.println("前");
        Object object=proceedingJoinPoint.proceed();
        System.out.println("后");
        return null;
    }
}

(2)配置文件:

 <aop:around method="around" pointcut-ref="myPointCut"></aop:around>

(3)测试结果:

前置通知:addStudent
前
addStudent
后
后置通知:addStudent   null
前置通知:deleteStudent
前
deleteStudent
后
后置通知:deleteStudent   null
前置通知:updateStudent
前
updateStudent
后
后置通知:updateStudent   null

8、基于XML文件的配置(抛出异常)

(1)定义目标类的接口和接口的实现类:

public interface StudentService {
     void addStudent();
     void updateStudent();
     String deleteStudent();
}

在方法中制造异常:

public class StudentServiceImpl implements StudentService {
    @Override
    public void addStudent() {
        System.out.println("addStudent");
    }

    @Override
    public void updateStudent() {
        int num=9/0;
        System.out.println("updateStudent");
    }

    @Override
    public String deleteStudent() {
        System.out.println("deleteStudent");
        return "nihao";
    }
}

(2)切面类:

public class MyAspect {
    public void before(JoinPoint joinPoint){
        System.out.println("前置通知:"+ joinPoint.getSignature().getName());
    }

    public void after(JoinPoint joinPoint,Object ret){//参数一:连接点描述
        //参数二:类型Object,参数名returning配置的
        System.out.println("后置通知:"+ joinPoint.getSignature().getName()+"   "+ret);
    }
    public Object around(ProceedingJoinPoint proceedingJoinPoint)throws Throwable{
        //手动执行目标方法
        System.out.println("前");
        Object object=proceedingJoinPoint.proceed();
        System.out.println("后");
        return null;
    }
    public void AfterThrowing(JoinPoint joinPoint,Throwable throwable){
        System.out.println("抛出异常的通知:"+throwable.getMessage());
    }
}

(3)配置文件:

 <aop:after-throwing method="AfterThrowing" pointcut-ref="myPointCut" throwing="throwable"></aop:after-throwing>

(4)测试:

前置通知:addStudent
前
addStudent
后
后置通知:addStudent   null
前置通知:deleteStudent
前
deleteStudent
后
后置通知:deleteStudent   null
前置通知:updateStudent
前
抛出异常的通知:/ by zero
Exception in thread "main" java.lang.ArithmeticException: / by zero

9、基于XML文件的配置(最终通知)

(1)目标类的接口和接口的实现类:

public interface StudentService {
     void addStudent();
     void updateStudent();
     String deleteStudent();
}
public class StudentServiceImpl implements StudentService {
    @Override
    public void addStudent() {
        System.out.println("addStudent");
    }

    @Override
    public void updateStudent() {
        int num=9/0;
        System.out.println("updateStudent");
    }

    @Override
    public String deleteStudent() {
        System.out.println("deleteStudent");
        return "nihao";
    }
}

(2)切面类:

public class MyAspect {
    public void before(JoinPoint joinPoint){
        System.out.println("前置通知:"+ joinPoint.getSignature().getName());
    }

    public void after(JoinPoint joinPoint,Object ret){//参数一:连接点描述
        //参数二:类型Object,参数名returning配置的
        System.out.println("后置通知:"+ joinPoint.getSignature().getName()+"   "+ret);
    }
    public Object around(ProceedingJoinPoint proceedingJoinPoint)throws Throwable{
        //手动执行目标方法
        System.out.println("前");
        Object object=proceedingJoinPoint.proceed();
        System.out.println("后");
        return null;
    }
    public void AfterThrowing(JoinPoint joinPoint,Throwable throwable){
        System.out.println("抛出异常的通知:"+throwable.getMessage());
    }

    public void myafter(JoinPoint joinPoint){
        System.out.println("最终通知");
    }
}

(3)配置文件:

 <aop:after method="myafter" pointcut-ref="myPointCut"></aop:after>

(4)测试结果:

前置通知:addStudent
前
addStudent
最终通知
后

后置通知:addStudent
null 前置通知:deleteStudent 前 deleteStudent 最终通知 后
后置通知:deleteStudent
null 前置通知:updateStudent 前 最终通知 抛出异常的通知:/ by zero Exception in thread "main" java.lang.ArithmeticException: / by zero

不管有没有异常都会执行最终通知。

10、基于注解的配置

(1)目标类的接口和接口的实现类:

public interface StudentService {
     void addStudent();
     void updateStudent();
     String deleteStudent();
}
import org.springframework.stereotype.Service;
@Service("studentService")
public class StudentServiceImpl implements StudentService {
    @Override
    public void addStudent() {
        System.out.println("addStudent");
    }

    @Override
    public void updateStudent() {
        int num=9/0;
        System.out.println("updateStudent");
    }

    @Override
    public String deleteStudent() {
        System.out.println("deleteStudent");
        return "nihao";
    }
}

(2)配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<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"
       xmlns="http://www.springframework.org/schema/beans"
       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">
    <!--扫描注解-->
    <context:component-scan base-package="pers.zhb.aspectxml"></context:component-scan>
    <!--确定aop注解生效-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

(3)切面:

@Component
@Aspect//声明切面
public class MyAspect {
    @Before("execution(* pers.zhb.aspectxml.StudentServiceImpl.*(..))")
    public void before(JoinPoint joinPoint){
        System.out.println("前置通知:"+ joinPoint.getSignature().getName());
    }

    //声明公共切入点
    @Pointcut("execution(* pers.zhb.aspectxml.StudentServiceImpl.*(..))")
    private void myPointCut(){

    }
    @AfterReturning(value = "myPointCut()",returning = "ret")
    public void after(JoinPoint joinPoint,Object ret){//参数一:连接点描述
        //参数二:类型Object,参数名returning配置的
        System.out.println("后置通知:"+ joinPoint.getSignature().getName()+"   "+ret);
    }

    @Around(value = "myPointCut()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint)throws Throwable{
        //手动执行目标方法
        System.out.println("前");
        Object object=proceedingJoinPoint.proceed();
        System.out.println("后");
        return null;
    }

@AfterThrowing(value = "execution(* pers.zhb.aspectxml.StudentServiceImpl.*(..))",throwing = "throwable")
    public void AfterThrowing(JoinPoint joinPoint,Throwable throwable){
        System.out.println("抛出异常的通知:"+throwable.getMessage());
    }

    @After(value = "myPointCut()")
    public void myafter(JoinPoint joinPoint){
        System.out.println("最终通知");
    }
}

(4)测试:

public class TestAspectXml {
    public static void main(String[] args) {
        ApplicationContext applicationContext=new
                ClassPathXmlApplicationContext("applicationContext.xml");
        //获得目标类
        pers.zhb.aspectxml.StudentService studentService= (StudentService) applicationContext.getBean("studentService");
        studentService.addStudent();
        studentService.deleteStudent();
        studentService.updateStudent();
    }
}
前
前置通知:addStudent
addStudent
后
最终通知
后置通知:addStudent   null
前
前置通知:deleteStudent
deleteStudent
后
最终通知
后置通知:deleteStudent   null
前
前置通知:updateStudent
最终通知
抛出异常的通知:/ by zero
Exception in thread "main" java.lang.ArithmeticException: / by zero
原文地址:https://www.cnblogs.com/zhai1997/p/12711155.html