zoukankan      html  css  js  c++  java
  • java 动态代理—— Mybaties 拦截器链基本原理实现

    1.摘要

      Mybaties 中有个分页插件,之前有特意的去了解了一下原理 :https://www.cnblogs.com/jonrain0625/p/11168247.html,从了解中得知分页插件是基于Mybaties的拦截器去实现的,这个插件就是一个拦截器,和别的拦截器组成了Mybaties的拦截器链,然后所有的拦截器都对Executor 这个类 做了动态代理。本次主要的再次去学习下这个动态代理,去实现一个最基本的拦截器链的效果。当然还有spring aop 等很多地方都是基于动态代理去实现的,关于Aop可以在 :https://www.cnblogs.com/lcngu/p/5339555.html 去了解。本次也是基于这篇文章,及代码去学习和实现 拦截器链。

    2.java动态代理

      java中代理模式分静态代理和动态代理,而动态代理的实现有两种实现方法,一种是基于JDK 用 接口方法去实现 ,一种是基于CGLIB 基于类去实现 ,了解可以看:https://www.cnblogs.com/rinack/p/7742682.html 。

      2.1 JDK 代理的基本使用:

        1.创建代理类的接口

        2.实现代理类执行的接口 InvocationHandler

        3.生成代理对象:Proxy.newProxyInstance(loader, interfaces, h);

        4.使用代理对象

        

    3.示列  

      示列实现对user类的log方法拦截 ,在执行log方法之前,拦截器链中 LogIntercept1 和LogIntercept2 对log 方法拦截 ,做业务逻辑,拦截器链优点的很好体现是,实现耦合,可以高度的做到对内修改 。

      3.1  新建代理类接口 和代理类

      

    public interface Log {
        public void log();
    }

     

    public class User  implements Log{
        String name = "user1";
        public void log() {
            System.out.println("user1 ----- 登陆");
        }
    }

      3.2  新建 InvocationHandler 的实现类

        为了封装 , 在bin方法中调用 Proxy.newProxyInstance 创建代理对象 ,把代理对象  和拦截器注入到代理对象,在 invoke方法中用拦截器代理执行。

      

    public class Handler implements InvocationHandler{
        //调用对象
        private Object proxy;
        //目标对象
        private Intercept intercept;
        
        
        private Handler(Intercept target,Object proxy) {
            this.intercept=target;
            this.proxy=proxy;
        }
        public static Object bind(Intercept target,Object proxy){
            return Proxy.newProxyInstance(
                    proxy.getClass().getClassLoader()
                    , proxy.getClass().getInterfaces(), new Handler(target,proxy));
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable {
            return intercept.intercept(this.proxy,method,args);
        }
    }

      3.3 创建拦截器 

        拦截器和拦截器的实现,偷懒写在一个文件中

      

    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    
    public interface Intercept {
        Object intercept(Object o, Method m, Object[]  os );
    }
    class LogIntercept1 implements Intercept {
    
        @Override
        public Object intercept(Object o, Method m, Object[] os) {
            try {
                System.out.println("LogIntercept1 拦截登陆操作 做相关业务逻辑");
                return m.invoke(o,os);
            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
                e.printStackTrace();
                return null;
            }
        }
        
    }
    class LogIntercept2 implements Intercept {
    
        @Override
        public Object intercept(Object o, Method m, Object[] os) {
            try {
                System.out.println("LogIntercept2 拦截登陆操作,做相关业务逻辑");
                return m.invoke(o,os);
            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
                e.printStackTrace();
                return null;
            }
        }
    }

     3.4 创建一个代理工厂 

        在类中根据拦截器的数量,对代理类做循环。每次代理都把拦截器传入代理对象中 。

      

    package 设计模式.com.pox.logPoxy;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class ProxyFactory {
        
        List<Intercept> InterceptChain = new ArrayList<Intercept>() {
            private static final long serialVersionUID = 1L;
    
            {
                add(new LogIntercept1());
                add(new LogIntercept2());
            }
        };
        
        
        public  Object  proxy(Class<?> classz) throws Exception {
            try {
                Object obj = classz.newInstance();
                return InterceptAll(obj);
            } catch (InstantiationException | IllegalAccessException e) {
                throw new RuntimeException("代理异常");//抛出个异常,不另外设计异常类了,用RuntimeException 代替
            }
        }
        
        /** 拦截器代理
         * @param obj
         * @return
         */
        private Object InterceptAll(Object obj) {
            if(InterceptChain.isEmpty()) {
                return obj;
            }
            for (Intercept intercept : InterceptChain) {
                obj = Handler.bind(intercept,obj);
            }
            return obj;
        }
        
        // 一下是单列的创建模式
        public ProxyFactory(){
            if(inner.proxyFactory != null) {
                throw new RuntimeException("不允许创建多个实例");
            }
        }
        public static ProxyFactory getProxyFactory() {
            return  inner.proxyFactory;
        }
        private static class inner{
            static ProxyFactory proxyFactory = new ProxyFactory();
        }
    }

      3.5 测试

    public class Test {
        public static void main(String[] args) throws Exception {
            ProxyFactory proxyFactory = ProxyFactory.getProxyFactory();
            Log user = (Log) proxyFactory.proxy(User.class);
            user.log();
        }
    }
    /**
    ouput :
    LogIntercept2 拦截登陆操作
    LogIntercept1 拦截登陆操作
    user1 ----- 登陆
    */

    以上就是一个简单的拦截器链实现,可以去查阅Mybaties的拦截器链,其原理是一样的,如果业务需要增加个拦截器链,实现接口 Intercept ,添加到代理工厂 ProxyFactory 拦截器链 InterceptChain中即可,实现高度的解耦功能。

  • 相关阅读:
    基本MVVM 和 ICommand用法举例(转)
    WPF C# 命令的运行机制
    628. Maximum Product of Three Numbers
    605. Can Place Flowers
    581. Shortest Unsorted Continuous Subarray
    152. Maximum Product Subarray
    216. Combination Sum III
    448. Find All Numbers Disappeared in an Array
    268. Missing Number
    414. Third Maximum Number
  • 原文地址:https://www.cnblogs.com/jonrain0625/p/11431511.html
Copyright © 2011-2022 走看看