栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

简单理解JDK动态代理使用拦截器和责任链模式

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

简单理解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;
    }

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

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/643918.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号