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中即可,实现高度的解耦功能。

  • 相关阅读:
    Python制作天气查询软件【python实战必学】
    Python妹子图爬虫实战项目【新手必学】
    Python超级无敌技巧分享
    PlaySound使用进阶
    【】2019
    【】风之忧伤
    delete[]和delete
    《windows程序设计 第五版》实例
    playsound函数用法
    【Python入门自学笔记专辑】——Python跳转语句和循环使用范围
  • 原文地址:https://www.cnblogs.com/jonrain0625/p/11431511.html
Copyright © 2011-2022 走看看