第十六章 Spring动态代理详解

1.额外功能详解#

  • MethodBeforeAdvice分析

    public class Before implements MethodBeforeAdvice {
        /*
            作用: 把需要在原始方法执行之前运行的额外功能,书写在before方法中
    
            Method: 增加额外功能的那个原始方法
    
            Object[]: 增加额外功能的那个原始方法的参数
    
            Object: 增加额外功能的原始方法所在的原始对象 
            
            这些参数根据需要进行使用
         */
        @Override
        public void before(Method method, Object[] args, Object target) throws Throwable {
            System.out.println("-----log:MethodBeforeAdvice-------");
        }
    }
    
  • MethodInterceptor(方法拦截器)

    public class Arround implements MethodInterceptor {
    
        /*
            invoke方法: 将额外功能书写在invoke方法中,额外功能可以运行在原始方法之前 之后 以及前后都可以运行
    
            MethodInvocation: 额外功能所增加的那个原始方法
    
            invocation.proceed()--->运行对应的原始方法
            由这个方法,就可以区分额外功能的运行时机:
                    额外功能写在invocation.proceed()之前,表示先运行额外功能,再运行原始方法
                    额外功能写在invocation.proceed()之后.表示先运行原始方法,再运行额外功能
                    额外功能写在invocation.proceed()之前和之后,表示额外功能前后都执行
    
             返回值: Object: 原始方法的返回值
                    invocation.proceed()代表原始方法的运行,我们只要返回该方法的执行结果即可
    
         */
        @Override
        public Object invoke(MethodInvocation invocation) throws Throwable {
    
            //额外方法
            Object proceed = invocation.proceed();
            //额外方法
            return proceed;
        }
    }
    
    Spring工厂配置与MethodBeforeAdvice一样
    
    事务在原始方法执行之前之后,都要运行
    
    额外功能可能运行在原始方法抛出异常的时候
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        Object proceed = null;
        try {
            proceed = invocation.proceed();
        } catch (Throwable e) {
            System.out.println("原始方法抛出异常时运行额外方法!");
            e.printStackTrace();
        }
        return proceed;
    }
    
    MethodInterceptor影响原始方法的返回值:
    	原始方法的返回值(invocation.proceed()),直接作为invoke方法的返回值返回,MethodInterceptor不会影响原始方法的返回值
    	
    	invoke方法中,不要将原始方法的返回值作为invoke方法的返回值返回即可
    

2.切入点详解#

切入点决定额外功能加入的位置(哪些方法)

<aop:pointcut id="before" expression="execution(* *(..))"/>

1. execution(): 切入点函数
2. * *(..): 切入点表达式

2.1 切入点表达式#

  1. 方法切入点表达式

    image

    * *(..)  --->所有方法
    
    *  -->修饰符返回值
    *  -->方法名
    ()  -->参数列表
    ..  -->对于参数没有要求(个数,类型都没有要求)
    
    • 定义login方法作为切入点

      * login(..)
      
    • 定义login方法, 且login方法有两个字符串类型的参数, 作为切入点

      * login(String,String)
      
      # 注意: 非java.lang包中的类型,必须写全限定名
      * register(com.dong.proxy.User)
      
      # 注意: ..可以和具体的参数连用
      * login(String,..)  -->login(String) login(String,String) login(String,com.dong.proxy.User)
      
    • 这种切入点表达式不精准(同名干扰)

      image

    • 精准的切入点表达式

      修饰符返回值 包.类.方法(参数)
      
      	*       com.baizhiedu.a.UserServiceImpl.login(String,String)
      

      image

  2. 类切入点

    指定类作为额外功能的切入点,这个类中所有方法都会添加额外功能
    在调用这个类时,会添加额外功能,在调用其他类时,不会添加额外功能
    
    • 语法1

      # UserServiceImpl类中所有方法加入额外功能
      * com.baizhiedu.a.UserServiceImpl.*(..)
      
    • 语法2

      # 忽略包,给不同包中的同名类中的所有方法添加额外功能
      1. 类只存在一级包中 com.UserServiceImpl
      * *.UserServiceImpl.*(..)
      
      2. 类在多级包 com.baizhiedu.proxy.UserServiceImpl
      * *..UserServiceImpl.*(..)
      
  3. 包切入点表达式

    指定包作为额外功能的切入点,包中所有类所有方法,都将加入额外功能
    
    • 语法1

      * com.baizhiedu.proxy.*.*(..)
      
      # 注意: 切入点包中的所有类,必须在proxy包中,不能在proxy包的子包中
      
    • 语法2

      # 让当前包的子包生效
      
      * com.baizhiedu.proxy..*.*(..)
      

2.2 切入点函数#

用于执行切入点函数
  1. execution

    最为重要的切入点函数,功能最全
    可以执行 方法切入点表达式 类切入点表达式 包切入点函数
    
    弊端: execution执行切入点表达式,书写麻烦
    
    注意: 其他切入点函数 简化的是execution书写复杂度,功能一致
    
  2. args

    作用: 主要用于方法参数的匹配
    
    切入点: 必须是两个字符串类型的参数
    
    execution(* *(String,String))
    args(String,String)
    
  3. within

    作用: 主要用于类\包切入点表达式的匹配
    
    切入点: UserServiceImpl这个类
    
    execution(* *..UserServiceImpl.*(..))
    
    within(*..UserServiceImpl)
    
    切入点: com.baizhiedu.proxy这个包
    
    execution(* com.baizhiedu.proxy..*.*)
    
    within(com.baizhiedu.proxy..)
    
  4. @annotation

    作用: 为具有特殊注解的方法加入额外功能
    
    切入点: 加有com.baizhiedu.Log这个注解的方法
    
    @annotation(com.baizhiedu.Log)
    
  5. 切入点函数的逻辑运算

    指的是 整合多个切入点函数一起配合工作,进而完成更为复杂的需求
    
    • and与操作

      案例: 方法名为login,同时有两个字符串参数
      
      1. execution(* login(String,String))
      
      2. execution(* login(..)) and args(String,String)
      
      注意: 与操作不能用于同种类型的切入点函数
      
    • or或操作

      案例: register方法和login方法作为切入点
      
      execution(* register(..)) or execution(* login(..))
      

作者:苏无及

出处:https://www.cnblogs.com/suwuji/p/16508285.html

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   苏无及  阅读(413)  评论(0编辑  收藏  举报
more_horiz
keyboard_arrow_up light_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示