我是如何学习Spring的(三)--AspectJ

Aspect概述

AspectJ是一个面向切面的框架,它扩展了Java语言。AspectJ定义了AOP语法所以它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件。

  • AspectJ是一个基于Java语言的AOP框架
  • Spring2.0以后新增了对AspectJ切点表达式支持
  • AspectJ注解 是AspectJ1.5新增功能,通过JDK5注解技术,允许直接在Bean类中定义切面
  • 常用自定义内容开发。例如:性能监控等
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
//自定义切面类
public class MyAspect {

public void mybefore(){
System.out.println("前置通知");
}
}


//Service接口类
public interface UserService {

public void addUser();
public void update();
}

//Service实例
public class UserServiceImpl implements UserService{

public void addUser() {
System.out.println("addUser");
}

public void update() {
System.out.println("update");
}
}

//测试类
@Test
public void Test01(){
String xmlPath = "com/jessyon/aspectj/beans.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);

//从spring获得bean数据
UserService userService = (UserService) applicationContext.getBean("userService");
userService.addUser();
userService.update();
}

//beans.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="userService" class="com.jessyon.aspectj.UserServiceImpl"></bean> //配置一个Service类
<bean id="MyAspect" class="com.jessyon.aspectj.MyAspect"></bean> //配置一个自定义切面类
<aop:config> //配置aop
<aop:aspect ref="MyAspect"> //配置切面类,将自定义切面类注入进来

//定义切点,切点为包名为com.jessyon.aspectj下的任意参数,任意返回值的任意方法
<aop:pointcut expression="execution(* com.jessyon.aspectj.*.*(..))" id="myPointcut"/>
<aop:before method="mybefore" pointcut-ref="myPointcut"/> //定义切面类为前置通知,将myPointcut注入
</aop:aspect>
</aop:config>
</beans>


//测试结果(在每个方法执行前,都会打印"前置通知")

前置通知
addUser
前置通知
update

切入点表达式

execution(表达式) 用于确定方法(可以为不同的方法进行确定)
修饰符
public 修饰符公共

   *            任意修饰符
返回值
   String        返回字符串
   *            返回任意
包    
   com.jessyon.service                    指定包(某一个模块)
   com.jessyon.*.service                子模块(子文件夹)任意
   com.jessyon.service..                service目录当前目录 ,以及子目录(孙子)
   com.jessyon.*.service..                jessyon下所有的子模块,service目录所有目录
类
   UserService                指定类名
   User*                    以User开头类
   *Service                以Service结尾类
   *                        任意类
方法
   addUser                    指定方法
   add*                    add开头方法
   *User                    以User结尾方法
   *                        任意方法
参数列表
   ()                        没有参数
   (int)                    一个参数
   (int,int)                两个参数
   (..)                    参数任意

AspectJ通知类型

定义6中通知类型,掌握1种,知道4种,了解1种。

  • before:前置通知(应用:各种校验) 在方法执行前执行,如果通知抛出异常,阻止方法运行
  • afterReturning:后置通知(应用:常规数据处理) 方法正常返回后执行,如果方法中抛出异常,通知无法执行。必须在方法执行后才执行,所以可以获得方法的返回值。
  • around:环绕通知(应用:十分强大,可以做任何事情) 方法执行前后分别执行,可以阻止方法的执行
  • afterThrowing:抛出异常通知(应用:包装异常信息) 方法抛出异常后执行,如果方法没有抛出异常,无法执行
  • after:最终通知(应用:清理现场) 方法执行完毕后执行,无论方法中是否出现异常
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    public class MyAspect{

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

    public void myAfterReturning(JoinPoint joinPoint,Object ret){
    System.out.println("后置通知:" + joinPoint.getSignature().getName() + " , " + ret);
    }

    public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{
    System.out.println("环绕前");
    //执行目标方法
    Object obj = joinPoint.proceed();

    System.out.println("环绕后");
    return obj;
    }

    public void myAfterThrowing(JoinPoint joinPoint, Throwable e){
    System.out.println("抛出异常通知:" + joinPoint.getSignature().getName() + " , " + e.getMessage());
    }

    public void myAfter(JoinPoint joinPoint){
    System.out.println("最终"+ joinPoint.getSignature().getName() );
    }

    }


    //注解版本
    @Component
    @Aspect
    public class MyAspect{

    //定义:公共切入点表达式。之后使用直接调用方法名
    @Pointcut("execution(* com.jessyon.annotation.*.*(..))")
    private void myPointCut(){}

    //@Before("execution(* com.jessyon.annotation.*.*(..))")
    public void myBefore(JoinPoint joinPoint){
    System.out.println("前置通知 :" + joinPoint.getSignature().getName());
    }

    //@AfterReturning(value="execution(* com.jessyon.annotation.*.*(..))",returning="ret")
    public void myAfterReturning(JoinPoint joinPoint,Object ret){
    System.out.println("后置通知:" + joinPoint.getSignature().getName() + " , " + ret);
    }

    //@Around("myPointCut()")
    public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{
    System.out.println("环绕前");
    //执行目标方法
    Object obj = joinPoint.proceed();

    System.out.println("环绕后");
    return obj;
    }

    //@AfterThrowing(value="myPointCut()",throwing="e")
    public void myAfterThrowing(JoinPoint joinPoint, Throwable e){
    System.out.println("抛出异常通知:" + joinPoint.getSignature().getName() + " , " + e.getMessage());
    }
    @After("myPointCut()")
    public void myAfter(JoinPoint joinPoint){
    System.out.println("最终"+ joinPoint.getSignature().getName() );
    }
    }
    <!-- 注解aspectj 必须进行配置 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>