zoukankan      html  css  js  c++  java
  • 动态代理和拦截器

    一、概述 

    1、代理模式是常用的java设计模式,生成一个代理对象,来代替真正的对象,从而控制真实对象的访问。

            客户(调用者)----------商务(代理对象)-----------软件工程师(真正对象)

    2、我们需要在调用者调用对象之前就生成一个代理对象,而这个代理对象需要和真正对象建立代理关系

       -----代理对象和真正对象建立关系

       -----实现代理对象的代理逻辑方法

    3、常用的代理对象方法:JDK动态代理,CGLIB

    二、JDK动态代理

        JDK动态代理所用到的代理类在程序调用到代理类对象时才由JVM真正创建,JVM根据传进来的 业务实现类对象以及方法名 ,动态地创建了一个代理类的class文件并被字节码引擎执行,然后通过该代理类对象进行方法调用。

    1、需要借助接口生成代理对象

    public interface HelloWorld {
        public void sayHelloWorld();
    }
    public class HelloWorldImp implements HelloWorld{
        @Override
        public void sayHelloWorld() {
            System.out.println("你好");    
        }
    
    }

    2、实现代理逻辑类:需要实现java.lang,reflect.InvocationHandler接口,重写invoke方法

    package reflect;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    import org.junit.Test;
    
    public class JdkProxyExample implements InvocationHandler{
        //真实对象
        private Object target = null;
        //建立关系,返回代理对象
        public Object bind(Object target) {
            this.target = target;    
            return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                    target.getClass().getInterfaces(),this);        
        }
        
        @Override
        //处理代理实例上的方法调用并返回结果。当在与其关联的代理实例上调用方法时,将在调用处理程序上调用此方法。
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("调用真实对象服务之前的服务");
            Object obj = method.invoke(target, args);//相当于调用sayHelloWorld()
            System.out.println("调用真实对象服务之后的服务");
            return obj;
        }
        
        @Test
        public void testJdkProxyExample() {
            JdkProxyExample jdkProxyExample = new JdkProxyExample();
            HelloWorld proxy = (HelloWorld) jdkProxyExample.bind(new HelloWorldImp());
            proxy.sayHelloWorld();
        }
        
    }
    1、该方法返回指定接口的代理类的实例,该接口将方法调用分派给指定的invocationhandler代理     
    public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h)
                           throws IllegalArgumentException 
    参数:InvocationHandler是由代理实例的调用处理程序实现的接口。每个代理实例都有一个关联的调用处理程序。当在代理实例上调用方法时,
                  方法调用被编码并发送到其调用处理程序的invokemethod
    2、Object invoke(Object proxy, Method method,Object[] args) throws Throwable{}
      处理代理实例上的方法调用并返回结果。当在与其关联的代理实例上调用方法时,将在调用处理程序上调用此方法。
      参数:
    Object proxy :就是newProxyInstance返回的代理对象
         Method method : 当前调度的接口中的方法
        
    Object[] args : 调度方法中的参数

    通俗点说就是实现java.lang,reflect.InvocationHandler接口,重写invoke方法,但是重写invoke()需要给它三个参数
    参数一:Object proxy :需要通过newProxyInstance返回的获取参数proxy

    三、CGLIB动态代理

    1、cglib是针对类来实现代理的,原理是对指定的业务类生成一个子类,并覆盖其中业务方法实现代理。因为采用的是继承,所以不能对final修饰的类进行代理。 

     (1)首先定义一个y业务类Hello

    public class Hello {
         public void sayHello() {  
                System.out.println("hello...");  
            }  
    }

    (2)对指定的业务类生成一个子类,并覆盖其中业务方法实现代理。

    package reflect;
    
    import java.lang.reflect.Method;
    
    import org.junit.Test;
    
    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    
    public class CGLIBProxyExample implements MethodInterceptor{
        //生成代理对象
        public Object getProxy(Class cls) {
            //增强类
            Enhancer enhance = new Enhancer();
            //设置增强的父类,即业务类
            enhance.setSuperclass(cls);
            /*setCallback()设置哪个类是它的代理类,参数是this为当前对象,
             * 要求当前对象实现MethodInterceptor接口并实现方法intercept*/        
            enhance.setCallback(this);
            return enhance.create();
        }
        @Override
        public Object intercept(Object proxy,Method method,Object[]args,
                MethodProxy methodProxy) throws Throwable {
                System.out.println("前");
                Object result = methodProxy.invokeSuper(proxy, args);
                System.out.println("后");
                return result;
            
        }
        @Test
        public void testCGLIBProxyExample() {
            CGLIBProxyExample cglibProxyExample = new CGLIBProxyExample();
            Hello proxy = (Hello) cglibProxyExample.getProxy(Hello.class);
            proxy.sayHello();
        }
    }
    MethodInterceptor、 Enhancer在cglib-nodep-3.2.10.jar下

    四、拦截器

     1、因为拦截器可以进一步简化动态代理的使用方法,是程序变得更简单。

     2、实现步骤:(1)定义一个拦截器接口

                (2)定义拦截器的实现类

              (3)实现拦截器的逻辑

    public interface Interceptor {
        public boolean before(Object proxy,Object target,Method method,Object[] args);
        public void around(Object proxy,Object target,Method method,Object[] args);
        public void after(Object proxy,Object target,Method method,Object[] args);
    }
    package interceptor;
    
    import java.lang.reflect.Method;
    
    public class InterceptorImp implements Interceptor{
    
        @Override
        /*当返回值为true时,反射真实对象原来的方法
         * 当返回值为false时,则调用around方法
         */
        public boolean before(Object proxy, Object target, Method method, Object[] args) {
            System.out.println("反射方法前逻辑");
            return false;
        }
    
        @Override
       //对原来的方法不满意,进行调整
    public void around(Object proxy, Object target, Method method, Object[] args) { System.out.println("取代原方法的逻辑"); } @Override public void after(Object proxy, Object target, Method method, Object[] args) { System.out.println("调用原方法或around后还要执行的逻辑"); } }
    package interceptor;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;public class InterceptorJdkProxy implements InvocationHandler{
        private Object target;    
        private String interceptorClass = null;//定义拦截器类路径
        public InterceptorJdkProxy(Object target,String interceptorClass) {
            this.target = target;
            this.interceptorClass = interceptorClass;
        }
        
        public static Object bind(Object target,String interceptorClass) {
            return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                    target.getClass().getInterfaces(), 
                    new InterceptorJdkProxy(target,interceptorClass));
        }
        
        @Override
        //第一个参数proxy的获取通过Proxy.newProxyInstance()获取
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            if(interceptorClass==null) {
                //没有拦截器就直接反射原来方法
                return method.invoke(target, args);
            }
            //否则,通过反射生成拦截器
            Object result = null;
            Interceptor interceptor = (Interceptor) Class.forName(interceptorClass).newInstance();
            //判断before方法
            if(interceptor.before(proxy, target, method, args)) {
                result = method.invoke(target, args);
            }else {
                interceptor.around(proxy, target, method, args);
            }
            interceptor.after(proxy, target, method, args);
            return result;
        }
           
        
        public static void main(String[] args) {
            //没有使用代理
            HelloWorld helloWorld = new HelloWorldImp();
            helloWorld.sayHelloWorld();
            //使用了代理
            HelloWorld proxy = (HelloWorld) InterceptorJdkProxy.bind(new HelloWorldImp(),
                    "interceptor.InterceptorImp");
            proxy.sayHelloWorld();
        }
    }
     
    
    
    
    

          

  • 相关阅读:
    iis部署网站打不开
    微信小程序全选多选效果
    清除浮动
    IIS_常见问题及解决方法
    文字闪烁效果
    IIS 伪静态 脚本映射 配置方法
    批量删除QQ空间说说
    自定义input文件上传 file的提示文字及样式
    使用google api material icons在网页中插入图标
    jquery日期插件jquery.datePicker参数
  • 原文地址:https://www.cnblogs.com/dongtian-blogs/p/10803258.html
Copyright © 2011-2022 走看看