动态代理和拦截器

一、概述

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();
    }
}
 


      

原文地址:https://www.cnblogs.com/dongtian-blogs/p/10803258.html

时间: 2024-11-14 05:17:44

动态代理和拦截器的相关文章

由浅入深分析mybatis通过动态代理实现拦截器(插件)的原理

最近在用mybatis做项目,需要用到mybatis的拦截器功能,就顺便把mybatis的拦截器源码大致的看了一遍,为了温故而知新,在此就按照自己的理解由浅入深的理解一下它的设计. 和大家分享一下,不足和谬误之处欢迎交流.直接入正题. 首先,先不管mybatis的源码是怎么设计的,先假设一下自己要做一个拦截器应该怎么做.拦截器的实现都是基于代理的设计模式设计的,简单的说就是要创造一个目标类的代理类,在代理类中执行目标类的方法并拦截执行拦截器代码. 那么我们就用JDK的动态代理设计一个简单的拦截器

java 动态代理—— Mybaties 拦截器链基本原理实现

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

Java进阶学习第24天——动态代理与类加载器

文档版本 开发工具 测试平台 工程名字 日期 作者 备注 V1.0 2016.06.17 lutianfei none 动态代理 代理对象存在的价值:主要用于拦截对真实业务对象的访问. 代理对象有什么方法? 现在要生成某一个对象的代理对象,这个代理对象通常也要编写一个类来生成,所以首先要编写用于生成代理对象的类. 如何编写生成代理对象的类,两个要素: 代理谁 如何生成代理对象 代理谁? 设计一个类变量,以及一个构造函数,记住代理类 代理哪个对象. 如何生成代理对象? 设计一个方法生成代理对象(在

day19_java基础加强_动态代理+注解+类加载器

一.动态代理 1.1.代理模式 ? ? 什么是代理模式及其作用? ? ? ? ? Proxy Pattern(即:代理模式),23种常用的面向对象软件的设计模式之一.? ? ? ? 代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问.? ? ? ? 在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用.? ? 优点:? ? ? ? (1) 职责清晰,真实的角色就是实现实际的业务逻辑,不用关心其他非本职责的事务,通过后期的代理完成一件

拦截器和过滤器区别

比如动态代理就是拦截器的简单实现, public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = null; System.out.println("before invoke method :" + method.getName()); result = method.invoke(this.targetObj, args); System.out

struts2拦截器与过滤器

转载:http://www.cnblogs.com/JohnLiang/archive/2011/12/15/2288376.html 过滤器,是在java web中,你传入的request,response提前过滤掉一些信息,或者提前设置一些参数,然后再传入servlet或者struts的 action进行业务逻辑,比如过滤掉非法url(不是login.do的地址请求,如果用户没有登陆都过滤掉),或者在传入servlet或者 struts的action前统一设置字符集,或者去除掉一些非法字符

(转)过滤器和拦截器的区别

1.拦截器是基于java的反射机制的,而过滤器是基于函数回调 2.过滤器依赖与servlet容器,而拦截器不依赖与servlet容器 3.拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用 4.拦截器可以访问action上下文.值栈里的对象,而过滤器不能 5.在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次 拦截器 :是在面向切面编程的就是在你的service或者一个方法,前调用一个方法,或者在方法后调用一个方法比如动态代理就是拦截器的

拦截器和过滤器的区别

拦截器和过滤器都可以用来实现横切关注功能,其区别主要在于: 1.拦截器是基于java反射机制的,而过滤器是基于函数回调的. 2.过滤器依赖于servlet容器,而拦截器不依赖于servlet容器. 3.拦截器只能对Action请求起作用,而过滤器则可以对几乎所有请求起作用. 4.拦截器可以访问Action上下文.值栈里的对象,而过滤器不能. 5.在Action的生命周期中,拦截器可以多次调用,而过滤器只能在容器初始化时被调用一次. 过滤器,是在java web中,你传入的request,resp

拦截器与过滤器的区别

过滤器,是在java web中,你传入的request,response提前过滤掉一些信息,或者提前设置一些参数,然后再传入servlet或者struts的 action进行业务逻辑,比如过滤掉非法url(不是login.do的地址请求,如果用户没有登陆都过滤掉),或者在传入servlet或者 struts的action前统一设置字符集,或者去除掉一些非法字符 拦截器,是在面向切面编程的就是在你的service或者一个方法,前调用一个方法,或者在方法后调用一个方法比如动态代理就是拦截器的简单实现