1. 额外功能的详解

    1.1 MethodBeforeAdvice接口分析

    1. - 该接口作用:额外功能运行在原始方法执行之前,进行额外操作
    1. public class Before implements MethodBeforeAdvice {
    2. /*
    3. 作用:需要把运行在原始方法之前执行的额外功能书写在before方法中
    4. Method:额外功能所增加给的的原始方法
    5. Object[]:额外功能所增加给的那个原始方法的参数
    6. Object:额外功能所增加给的那个原始对象
    7. */
    8. @Override
    9. public void before(Method method, Object[] args, Object target) throws Throwable {
    10. System.out.println("Before.before");
    11. }
    12. }
    1. - before方法的三个参数在实战中如何使用?
    2. - before方法的三个参数在实战中根据需要选择使用,不一定都用,也可能都不用

    1.2 MethodInterceptor(方法拦截器)

    1. - MethodBeforeAdvice执行在原始方法执行之前,而MethodInterceptor在原始方法执行之前、之后或前后执行
    1. public class Around implements MethodInterceptor {
    2. /*
    3. * invoke方法的作用:额外功能书写在invoke中
    4. * 额外功能可以根据需要执行在原始方法执行之前或之后
    5. * 确定:原始方法如何运行
    6. * 参数:MethodInvocation Method:原始方法所附加给的那个方法
    7. * invocation.proceed()代表原始方法运行
    8. * 返回值:原始方法执行后的返回值(原始方法返回值)
    9. * */
    10. @Override
    11. public Object invoke(MethodInvocation invocation) throws Throwable {
    12. System.out.println("--------Around.before.log--------");//运行在原始方法执行之前
    13. Object ret = invocation.proceed(); //原始方法执行
    14. System.out.println("--------Around.after.log--------"); //运行在原始方法执行之后
    15. return ret;
    16. }
    17. }
    1. - 额外功能运行在原始方法执行之前
    1. @Override
    2. public Object invoke(MethodInvocation invocation) throws Throwable {
    3. System.out.println("--------Around.before.log--------");//运行在原始方法执行之前
    4. Object ret = invocation.proceed(); //原始方法执行
    5. return ret;
    6. }
    1. - 额外功能运行在原始方法执行之后
    1. @Override
    2. public Object invoke(MethodInvocation invocation) throws Throwable {
    3. Object ret = invocation.proceed(); //原始方法执行
    4. System.out.println("--------Around.after.log--------"); //运行在原始方法执行之后
    5. return ret;
    6. }
    1. - 额外功能运行在原始方法执行之前、之后
    1. @Override
    2. public Object invoke(MethodInvocation invocation) throws Throwable {
    3. System.out.println("--------Around.before.log--------");//运行在原始方法执行之前
    4. Object ret = invocation.proceed(); //原始方法执行
    5. System.out.println("--------Around.after.log--------"); //运行在原始方法执行之后
    6. return ret;
    7. }
    1. - 额外方法运行在原始方法抛出异常时
    1. @Override
    2. public Object invoke(MethodInvocation invocation) throws Throwable {
    3. Object ret = null;
    4. try {
    5. ret = invocation.proceed();
    6. } catch (Throwable throwable) {
    7. System.out.println("--------Around.Exception.log---------");
    8. throwable.printStackTrace();
    9. }
    10. return ret;
    11. }
    1. - MethodInterceptor方法可以影响原始方法的返回值
    2. - 原始方法的返回值直接作为invoke方法的返回值,不会影响原始方法的返回值
    3. - 原始方法的返回值不直接作为invoke方法的返回值,则会影响原始方法的返回值
    1. 切入点详解

    切入点决定额外功能加入的位置(方法)
    <aop:pointcut id="pc" expression="execution(* *(..))" />
    其中:execution( (..)) 匹配了所有方法

    • execution() 切入点函数
      • *(..) 切入点表达式

    2.1 切入点表达式

    • 方法切入点

      • 定义一个方法: public void add(int a,int b);

      表达式: (..)

    其中:第一个 代表 修饰符与返回值
    第二个
    代表 方法名
    () 代表 参数表
    .. 代表对参数没有要求 (对类型没有要求,对数量没有要求)

    1. - 定义login方法作为切入点:
    2. 方法定义: `public boolean login(String name,String password);`<br /> 表达式: `* login(..)`
    3. - 定义login方法为切入点且login方法有两个字符串类型的形参:

    方法定义: public boolean login(String name,String password);
    表达式: * login(String,String)
    注意:

    1. 1. java.lang包中的类型,必须写全限定名
    2. 1. `..`可以与具体的参数类型连用,如`* ``login(String,..)`表达式表示第一个参数为String类型,其余参数随意
    3. - 精准方法切入点限定

    修饰符 返回值 包.类.方法(参数)
    (..)
    image.png

    • 类切入点
      • 定义:指定特定类作为切入点(额外功能加入的位置),自然这个类中的所有方法加入额外功能
      • 语法1:类中所有方法都加入额外功能

    * com.baizhi.proxy.UserServiceImpl.*(..)

    1. - 语法2:忽略包

    情况一:类只存在于一级包,如com.UserServiceImpl
    * *.UserServiceImpl.*(..)
    情况二:类存在于多级包,如com.baizhi.proxy.UserServiceImpl
    * *..UserServiceImpl.*(..)
    image.png

    • 包切入点表达式
      • 定义:指定包作为切入点的位置,自然这个包中的所有类的所有方法都加入额外功能
      • 语法一:切入点包中的所有类都必须在proxy包中,而不能在其子包中

    * com.baizhi.proxy.*.*(..)

    1. - 语法二:切入点包中的所有类在proxy包或其子包中

    * com.baizhi.proxy..*.*(..)
    image.png
    2.2 切入点函数
    切入点函数:用于执行切入点表达式

    • execution
      • 最为重要的切入点表达式,功能最全
      • 执行:方法切入点表达式、类切入点表达式、包切入点表达式
      • 弊端:execution执行表达式时,书写比较麻烦
      • 注意:其他函数仅仅为了简化execution书写表达式,功能是一样的
    • args
      • 作用:主要用于函数(方法)参数匹配
      • 切入点:方法的参数必须是两个字符串类型
      • 表达式:args(String,String)
    • within
      • 作用:主要用于类、包切入点表达式匹配
      • 切入点:类或包
      • within(*..类名)
      • within(包名..*)
    • @annotation
      • 为具有特殊注解的方法加入额外功能
      • <aop:pointcut id=" " expression="@annotation(注解的全限定名)" />
    • 切入点函数的逻辑运算
      • 作用:整合多个切入点函数一起配合工作,以实现更为复杂的功能
      • and(与)操作:同时操作(同时满足)
        • 例:execution( login(String,String))——> execution( login(..)) and args(String,String)
        • 注意:与操作不能用于同种类型的切入点函数
      • or(或)操作:
        • 例:execution( login(..)) or execution( register(..))
    1. 总结