IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 简单理解JDK动态代理使用拦截器和责任链模式 -> 正文阅读

[Java知识库]简单理解JDK动态代理使用拦截器和责任链模式

目录

?1.拦截器

?1.1在JDK代理中使用拦截器:

2.责任链模式

?2.1定义责任链拦截器接口


由于动态代理一般都比较难理解,程序设计者会设计一个拦截器接口供开发者使用,开发者只要知道拦截器接口的方法、含义和作用即可,无须知道动态代理是怎么实现的。用JDK动态代理来实现一个拦截器的逻辑,为此先定义拦截器接口Interceptor

?1.拦截器

package service;

import java.lang.reflect.Method;

public interface Interceptor {
    boolean before(Object proxy, Object target, Method method,Object []args);

    void around(Object proxy, Object target, Method method,Object []args);

    void after(Object proxy, Object target, Method method,Object []args);
}

这里定义了3个方法,before、around、after方法,分别给予这些方法如下逻辑定义。

  • 3个方法的参数为:proxy代理对象、target真实对象、method方法、args运行方法参数?
  • before方法返回boolean值,它在真实对象前调用。当返回为true时,则反射真实对象的方法;当返回为false时,则调用around方法。
  • 在反射真实对象方法或者around方法执行之后,调用after方法。

?实现类代码:

package service.serviceimpl;

import service.Interceptor;

import java.lang.reflect.Method;

public class MyInterceptor implements Interceptor {

    @Override
    public boolean before(Object proxy, Object target, Method method, Object[] args) {
        System.out.println("反射方法前逻辑");
        return false;//不调用真实对象方法,为true调用
    }

    @Override
    public void around(Object proxy, Object target, Method method, Object[] args) {
        System.out.println("反射方法逻辑");//before为false调用
    }

    @Override
    public void after(Object proxy, Object target, Method method, Object[] args) {
        System.out.println("取代了真实对象方法");
    }
}

?1.1在JDK代理中使用拦截器:

package classtext;

import service.Interceptor;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class InterceptorJdkProxy implements InvocationHandler {
    Object target=null;//真实对象
    String interceptorClass=null;//拦截器全类名
    public InterceptorJdkProxy(Object target, 
String interceptorClass){
        this.target=target;
        this.interceptorClass=interceptorClass;
    }

    /**
     * 绑定真实对象,返回代理对象
     * @param target
     * @param interceptorClass
     * @return
     */
    public static Object bind(Object target, String interceptorClass){
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
new InterceptorJdkProxy(target, interceptorClass));
    }

    @Override
    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();
        if (interceptor.before(proxy,target,method,args)){
            result=method.invoke(proxy,args);//为true返回真实对象方法结束,
        }else {//否则执行around方法
            interceptor.around(proxy,target,method,args);
        }//调用after方法
        interceptor.after(proxy,target,method,args);
        return result;
    }
}

不明白方法参数看这篇:(2条消息) 一文搞懂两种最常用的动态代理:JDK和CGLIB_m0_56058975的博客-CSDN博客

流程图如下:

?

?开启测试:

package test;

import classtext.InterceptorJdkProxy;
import service.HelloWordService;
import service.serviceimpl.HelloWordServiceImpl;

public class InterceptorJdkProxyTest {
    public static void main(String[] args) {
        HelloWordService proxy=(HelloWordService)InterceptorJdkProxy.bind(new HelloWordServiceImpl()
        ,"service.serviceimpl.MyInterceptor");
        proxy.sayHello();
    }
}

运行结果如下:

反射方法前逻辑
反射方法逻辑
取代了真实对象方法

2.责任链模式

责任链模式可以理解为拦截器的升级版,举个例子:一个员工需要请假一周,如果把请假申请单看成一个对象,那么它需要经过项目经理、部门经理、人事等多个角色的审批,每个角色都有机会通过拦截这个申请单进行审批或者修改。这个时就要考虑提供项目经理、部门经理和人事的处理逻辑,所以需要提供3个拦截器,而传递的则是请假申请单

如图所示:

?

?当一个对象在一条链上被多个拦截器处理就被称为责任链模式(拦截器可以选择拦截或者不拦截),它用于一个对象在多个角色中传递的场景。还是刚才的例子,申请单走到项目经理那,经理可能把申请时间“一周”改为“5天”,从而影响了后面的审批,后面的审批都要根据前面的结果进行。这个时候可以考虑用层层代理来实现,就是当申请单(target)走到项目经理处,使用第一个动态代理proxy1。当它走到部门经理处,部门经理会得到一个在项目经理的代理 proxy1基础上生成的 proxy2来处理部门经理的逻辑。当它走到人事处,会在proxy2的基础生成proxy3。如果还有其他角色,依此类推即可。

?2.1定义责任链拦截器接口


public class Interceptorl implements Interceptor
        public boolean before(Object proxy, Object target, Method method, Object [ ]
                args)
System.out.println("【拦截器1】的before方法");
        return true;
public void around(Object proxy, object target, Method method, object[]
        args)
        System.out.println("【拦截器1】的aroud方法");
public void after(Object proxy, object target, Method method, object[]
        args)
        System.out.println("【拦截器1】的after方法");


------

public class Interceptorl implements Interceptor
        public boolean before(Object proxy, Object target, Method method, Object [ ]
                args)
System.out.println("【拦截器2】的before方法");
        return true;
public void around(Object proxy, object target, Method method, object[]
        args)
        System.out.println("【拦截器2】的aroud方法");
public void after(Object proxy, object target, Method method, object[]
        args)
        System.out.println("【拦截器2】的after方法");
-------------

public class Interceptorl implements Interceptor
        public boolean before(Object proxy, Object target, Method method, Object [ ]
                args)
System.out.println("【拦截器3】的before方法");
        return true;
public void around(Object proxy, object target, Method method, object[]
        args)
        System.out.println("【拦截器3】的aroud方法");
public void after(Object proxy, object target, Method method, object[]
        args)
        System.out.println("【拦截器3】的after方法");


?单元测试:

    public static void main(String[] args)
    Helloworld proxyl = (HelloWorld) InterceptorJdkProxy.bind(
            new
                    HelloWorldImpl(), "service.serviceimpl.Interceptor1");
            Helloworld proxy2 =
                    (Helloworld) InterceptorJdkProxy.bind(
                            proxy1, "service.serviceimpl.Interceptor2");
    Helloworld proxy3 = (Helloworld) InterceptorJdkProxy.bind(
            proxy2, "service.serviceimpl.Interceptor3");
proxy3.sayHelloworld();

测试结果如下:

【拦截器3】的before方法
【拦截器2】的before方法
【拦截器1】的before方法
sayHello
【拦截器1】的after方法
【拦截器2】的after方法
【拦截器3】的 after方法

before方法按照从最后一个拦截器到第一个拦截器的加载顺序运行,而after方法则按照从第一个拦截器到最后一个拦截器的加载顺序运行。
从代码中可见,责任链模式的优点在于我们可以在传递链上加入新的拦截器,增加拦截逻辑,其缺点是会增加代理和反射,而代理和反射的性能不高。

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-12-09 11:31:13  更:2021-12-09 11:31:57 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 6:26:33-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码