java动态链模式和责任链模式

java动态链模式和责任链模式

很多框架的技术原理都涉及到java动态链模式和责任链模式,比如spring和mybatis。

动态代理模式

代理,顾名思义,代为处理。先来看看名词解释:
代理就是定义一个行为和某类(class)的对象相似,而又潜在地表示了所有继承自该类的对象的东西,我们把这种类的对象叫做代理(surrogate)
来源代理(百度百科)。
来看一下最常用的代理技术:

  • JDK代理技术(JDK自带代理技术)
  • CGLIB代理技术(第三方代理技术)

JDK代理技术

jdk代理技术是java.lang.reflect包提供的方式,它必须通过一个接口才能产生代理对象,所以必须先创建对象,所以先对接口进行定义。

    public interface HelloWorld{
        void sayHelloWorld();
    }

然后我们来创建一个是实现类:

    public class HelloWorldImpl implements HelloWorld{
        @override
        public void sayHelloWorld(){
            System.out.println("Hello World!");
        }
    }

实现动态代理,分成两步走,第一步,实现接口java.lang.reflect.InvocationHandler,它有一个invoke方法,用于提供接口数组用于下挂代理对象

    public class JdkProxyExample implements InvocationHandler{
    //真实对象
    private object target = null;
    /**
    *建立代理对象和真实对象的代理关系,并返回对象
    *@param target 真实对象
    *@return 代理对象
    */
    public object bind(Object target){
        this.target = target;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterface(),this);
    /**
    *代理对象逻辑
    *@param proxy 代理对象
    *@param method 当前调度方法
    *@param args 当前方法参数
    *@return 代理结果返回
    *@throws Throwable 异常
    */
    @override
    public Object invoke(Object proxy,Method method,Object[] args)throws Throwable{
        System.out.println("进入代理逻辑方法");
        System.out.println("在调度真实对象之前的服务");
        Object object = method.invoke(target,args);
        System.out.println("在调度真实对象之后的服务");
        return object;
    }
    }

第一步建立对象和代理对象之间的联系,也就是使用了bind方法用如下语句
Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterface(),this);
生成代理对象,通过目标类的类加载器,和目标类的挂在接口。用当前对象this作为代理逻辑方法的现实方法,它必须实现InvocationHandler接口的invoke方法。
第二步实现代理逻辑方法。invoke方法可以实现代理逻辑。

这样我们进行HelloWorld proxy= (HelloWorld)jdk . bind(new HelloWorldImpl());
生成的就是proxy代理对象,调用方法proxy . sayHelloWorld();就会输出:

    进入代理逻辑方法
    在调度真实对象之前的服务
    Hello World
    在调度真实对象之后的服务

这样通过代理,我们做到了什么事情呢?
你可以看到,我们并没有修改HelloWorldImpl类的sayHello()方法,但是执行出来的代理方法增添了新的内容!如果把目标对象比喻成棒棒糖,那么,代理操作就是在糖外面再裹了一层糖浆!

CGLIB代理技术

下面来讲代理的另一种实现方式。
上面讲的JDK代理,必须要有挂在的接口,也就是说目标的被代理对象必须要有实现的接口。
如果目标对象没有接口,是一个普通类怎么办呢?
我们可以用CGLB技术。CGLB使用抽象类来实现代理。来个简单的例子:

    public class SampleClass {
        public void test(){
            System.out.println("hello world");
        }

        public static void main(String[] args) {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(SampleClass.class);
            enhancer.setCallback(new MethodInterceptor() {
                @Override
                public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
                    System.out.println("before method run...");
                    Object result = proxy.invokeSuper(obj, args);
                    System.out.println("after method run...");
                    return result;
                }
            });
            SampleClass sample = (SampleClass) enhancer.create();
            sample.test();
        }
    }

如果把两个类实现同一个接口的这种行为,看作是当兄弟,那么一个类继承另一个类的行为可以被看作当儿子所以JDK的代理和CGLB的差别就是当兄弟和当儿子的区别(都是针对目标对象而言)。
CGLB的代理实际上是用Enhance对象调用setSuperclass()设置目标类为父类,setCallback()为实际执行的逻辑方法,然后返回代理对象。

拦截器

动态代理比较难理解,所以设计者设计了一个拦截器,实现代理,这样开发人员就不需要关心动态代理是怎么实现的。
一般来说,拦截器是这样的

    public interfa ce Interceptor {
    public boolean before (Obje ct pr , oxy , 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) ;
    }

拦截器的作用就是他的名字,拦截。把代理看作一种拦截行为。
回头看代理的逻辑实现,可以分为,原方法执行前,原方法执行,原方法执行后。三个部分。当然原方法实际上是可以不执行的。
而拦截器实际上就是把这几个部分拿出来并且加工了一下。
before()在原方法执行前执行,返回boolean,为true是调用原方法,false调用around()方法,之后调用after()方法。

Created with Raphaël 2.1.2 before() 是否为true 原方法 after() around() yes no

这样依赖,我们就只能看见拦截器,而看不见内部的动态代理了。
也就是说设计者提供了接口,封装了内部原理,而开发人员负责实现接口,提供实际逻辑

责任链模式

上面说到,设计者会用拦截器去替换动态代理,提供对应的接口给开发者,从而降低开发难度。
但是拦截器可以有很多个,比如生病报销,需要将材料一层层的上报。也像是捕鱼,有的鱼篓有好几节长。
当一个对象在一条链上被多个拦截器拦截处理(当然也可以存在拦截器,而不做任何处理)时,我们把这样的设计模式称之为责任链模式
内部也就会有多个代理对象。
这时候你可能就知道了,联想到之前的,我们说代理就是在棒棒糖(原对象方法)上裹了一层糖,那么责任链就是按照顺序裹了一层有一层。类比请假:
拦截器模式
而拦截的方法执行就像是从中穿过的一条线的顺序:拦截器的执行
这样看是不是像穿过了一个裹了一层有一层的糖衣的棒棒糖呢?

总结

意图:避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。
优点: 1、降低耦合度。它将请求的发送者和接收者解耦。 2、简化了对象。使得对象不需要知道链的结构。 3、增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。 4、增加新的请求处理类很方便。
缺点: 1、不能保证请求一定被接收。 2、系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用。 3、可能不容易观察运行时的特征,有碍于除错。

猜你喜欢

转载自blog.csdn.net/xl_1851252/article/details/81455547
今日推荐