• JavaEE互联网轻量级框架整合开发(书籍)阅读笔记(4):JDK动态代理+拦截器


    一、拦截器的理解

      学习拦截器之前需要对动态代理和反射有一定的基础。

      官方说法:

              java里的拦截器是动态拦截Action调用的对象。它提供了一种机制可以使开发者可以定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行,同时也提供了一种可以提取action中可重用部分的方式。在AOP(Aspect-Oriented Programming)中拦截器用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作。 

          简单来说,就是拦截器可以提供一个在方法调用之前的方法,调用之后的方法,方便我们在方法执行的前后做拦截判或其他业务处理。

    二、Jdk动态代理+拦截器

    创建一个普通接口:HelloWorld.java

    1 package com.xfwl.proxy.jdk;
    2 
    3 public interface HelloWorld {
    4     public void  sayHelloWorld();
    5 }

     创建一个上面皆接口的实现子类:HelloWorldImpl.java

    1 package com.xfwl.proxy.jdk;
    2 
    3 public class HelloWorldImpl implements HelloWorld {
    4 
    5     public void sayHelloWorld() {
    6         System.out.println("Hello World!");
    7     }
    8 }

     创建一个拦截器的接口:Interceptor.java

    package com.xfwl.interceptor;
    
    import java.lang.reflect.Method;
    
    /**
     * 定义一个拦截器接口
     * @function  
     * @author 小风微凉
     * @time  2018-7-9 下午2:20:35
     */
    public interface Interceptor {
        /**
         * 拦截器-真实方法调用之前before
         * @param proxy 代理对象
         * @param target 真实对象
         * @param method 真实方法
         * @param args 运行参数
         * @return 返回boolean  false则执行around(),true则不执行around()
         */
        public boolean before(Object proxy,Object target,Method method,Object[] args);
        /**
         * before()返回 false则执行around(),true则不执行around()
         * @param proxy 代理对象
         * @param target 真实对象
         * @param method 真实方法
         * @param args 运行参数
         */
        public void around(Object proxy,Object target,Method method,Object[] args);
        /**
         * before/around执行之后执行after()
         * @param proxy 代理对象
         * @param target 真实对象
         * @param method 真实方法
         * @param args 运行参数
         */
        public void after(Object proxy,Object target,Method method,Object[] args);
    }

     创建上面拦截器接口的实现子类:MyInterceptor.java

     1 package com.xfwl.interceptor;
     2 
     3 import java.lang.reflect.Method;
     4 /**
     5  * 拦截器实现子类
     6  * @function 理解拦截器之前需要理解动态代理+反射机制 
     7  * @author 小风微凉
     8  * @time  2018-7-9 下午2:25:34
     9  */
    10 public class MyInterceptor implements Interceptor {
    11 
    12     @Override
    13     public boolean before(Object proxy, Object target, Method method,Object[] args) {
    14         System.out.println("反射方法前逻辑!");        
    15         return false;
    16     }
    17 
    18     @Override
    19     public void around(Object proxy, Object target, Method method, Object[] args) {
    20         System.out.println("取代了被代理对象的方法!");    
    21     }
    22 
    23     @Override
    24     public void after(Object proxy, Object target, Method method, Object[] args) {
    25         System.out.println("反射方法后逻辑!");
    26     }
    27 }

     创建一个动态代理类:InterceptorJdkProxy.java

     1 package com.xfwl.interceptor;
     2 
     3 import java.lang.reflect.InvocationHandler;
     4 import java.lang.reflect.Method;
     5 import java.lang.reflect.Proxy;
     6 /**
     7  * JDK动态代理实现类
     8  * @function  在代理类中嵌入拦截器,关键点还是动态代理
     9  * @author 小风微凉
    10  * @time  2018-7-9 下午2:29:21
    11  */
    12 public class InterceptorJdkProxy implements InvocationHandler {
    13     //真实对象
    14     private Object target=null;
    15     //拦截器全称
    16     private String interceptorClass=null;
    17     //动态代理类构造器
    18     public InterceptorJdkProxy(){}
    19     public InterceptorJdkProxy(Object target,String interceptorClass){
    20         this.interceptorClass=interceptorClass;
    21         this.target=target;
    22     }
    23     /**
    24      *  给真实独享绑定代理对象
    25      * @param target  真实对象
    26      * @param interceptorClass  拦截器的全称
    27      * @return 代理对象【占位】
    28      */
    29     public  Object bind(Object target,String interceptorClass){
    30         return Proxy.newProxyInstance(
    31                 target.getClass().getClassLoader(),//真实对象的类加载器
    32                 target.getClass().getInterfaces(), //真实对象的实现接口
    33                 new InterceptorJdkProxy(target, interceptorClass)//实现了InvocationHandler接口的实现类,一般为当前代理类对象
    34         );            
    35     }    
    36     /**
    37      * 通过代理对象调用方法,首先进入这个方法
    38      * @param proxy 代理对象
    39      * @param method 方法
    40      * @param args 运行参数
    41      * @return 
    42      */
    43     @Override
    44     public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {
    45         //判断当前代理是否使用了拦截器
    46         if(interceptorClass==null){
    47             //没有拦截器,则直接执行真实对象的方法
    48             return method.invoke(this.target, args);
    49         }
    50         Object result=null;
    51         //通过反射拿到拦截器对象
    52         Interceptor interceptor =(Interceptor)Class.forName(interceptorClass).newInstance(); 
    53         //调用前置方法
    54         if(interceptor.before(proxy, args, method, args)){
    55             //反射真实对象原有的方法
    56             result=method.invoke(target, args);
    57         }else{
    58             //返回false,执行around方法
    59             interceptor.around(proxy, args, method, args);
    60         }
    61         //调用后置方法
    62         interceptor.after(proxy, args, method, args);        
    63         return result;
    64     }
    65 }

     创建一个测试类:TestInterceptor.java.

     1 package com.xfwl.interceptor;
     2 
     3 import com.xfwl.proxy.jdk.HelloWorld;
     4 import com.xfwl.proxy.jdk.HelloWorldImpl;
     5 
     6 /**
     7  * 拦截器测试
     8  * @function  测试一下拦截器是如何起作用的,
     9  * @author 小风微凉
    10  * @time  2018-7-9 下午2:19:15
    11  */
    12 public class TestInterceptor {
    13 
    14     /**  
    15      * @param args
    16      */
    17     public static void main(String[] args) {
    18         //拿到代理对象,并绑定真实对象
    19         HelloWorld proxy=(HelloWorld) new InterceptorJdkProxy().bind(
    20                                                 new HelloWorldImpl(), 
    21                                                 "com.xfwl.interceptor.MyInterceptor"
    22                                                 );
    23         //执行代理逻辑
    24         proxy.sayHelloWorld();
    25 
    26     }
    27 
    28 }

     测试结果:

    运行条件【1】:

    1 @Override
    2     public boolean before(Object proxy, Object target, Method method,Object[] args) {
    3         System.out.println("反射方法前逻辑!");        
    4         return false;
    5     }

     运行结果:

    反射方法前逻辑!
    取代了被代理对象的方法!
    反射方法后逻辑!

     运行条件【2】:

    1 @Override
    2     public boolean before(Object proxy, Object target, Method method,Object[] args) {
    3         System.out.println("反射方法前逻辑!");        
    4         return true;
    5     }

     运行结果:

    反射方法前逻辑!
    Hello World!
    反射方法后逻辑!

     从上面可以看出,拦截器生效了!

  • 相关阅读:
    对MySql查询缓存及SQL Server过程缓存的理解及总结
    PhpStorm中如何使用database工具,详细操作方法
    zookeeper 操作命令
    关于 php for zookeeper
    摘抄 <关于 作为>
    php 各种扩展
    http与tcp
    PHP 优化之php -fpm 进程
    MYSQL explain详解[转载]
    各种注释[转载]
  • 原文地址:https://www.cnblogs.com/newwind/p/9283934.html
Copyright © 2020-2023  润新知