设计模式——动态代理

本文说明:在学习《Java EE互联网轻量级框架整合开发》此书时,里面提到了几种设计模式,我在学习这几种设计模式时写了笔记,放上来让大家共同学习,如果有错误,望指出。

本文章由两部分组成:

JDK动态代理的基本概念+关键代码讲解+完整例子

CGLIB动态代理的完整例子

JDK动态代理的基本概念+关键代码讲解+完整例子

动态代理主要用来向已经实现的方法或逻辑的前后动态加入逻辑,比如日志等,Spring中就用到了动态代理。动态代理主要有两种,分别是JDK动态代理和CGLIB动态代理。两者的唯一区别是需要接口和不需接口。其中,JDK需要接口,CGLIB不需接口。二者很相似,掌握其中之一便能掌握另一个。

基本概念+关键代码讲解

基本构成:目标接口,目标类(继承目标接口),JDK动态代理逻辑实现类,测试类

【目标接口和类】:可能被插入逻辑的代码;

【JDK动态代理逻辑实现类】:关键类;

【测试类】:测试动态代理已经实现的代码。

下面主要讲讲【JDK动态代理逻辑实现类】。

此类首先需要实现 java.lang.reflect 包里面的接口 InvocationHandler,进而实现(重写)方法 invoke()。实现方法invoke()有什么作用?它其实就是实现对目标类的方法前后插入动态逻辑的一串代码。使用时,得先用目标类作为参数得到代理对象proxy,当我们通过proxy调用目标类的方法时,JDK自动帮我们寻找到此重写方法invoke的逻辑进行相应代替。当然为了不覆盖原有的目标类方法,需要我们在invoke()方法里面调用原有方法,这时就用到了反射。

上一段话说明,我们需要在这个类里面实现两个方法,第一个方法是使用目标类得到代理对象proxy(我们称为bind方法),第二个方法是重写invoke()方法。

实现bind()方法非常简单,我们清楚输入是目标类,输出是代理proxy,这个proxy就是 java.lang.reflect 包的 Proxy类,如何生成Proxy对象?需要调用 Proxy.newInstance()方法,参数如下:

//参数说明:
//target就是我们的目标类对象
//this就是重写了invoke()方法的类的对象,在这里就是【JDK动态代理逻辑实现类】的对象
Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);

所以bind()方法的完整代码为:

public Object bind(Object target) {
    this.target = target;
    return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}

重写invoke()方法前,我们先看看IDEA自动生成的invoke()方法的参数是什么:

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
}

前面已经说过invoke得包含原有逻辑,可以看到这里有个方法参数method以及它对应的参数列表args,通过这两个对象加上我们在此类的bind()方法得到的对象target,我们可以用反射(反射参照“设计模式——反射”这一篇)得到原有方法逻辑,核心代码如下:

Object returnObj = method.invoke(target, args);

所以invoke()方法全部代码如下:

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    System.out.println("进入逻辑方法之前");
    System.out.println("在调度真实对象之前的服务");
    Object returnObj = method.invoke(target, args);
    System.out.println("在调度真实对象之后的服务");
    return returnObj;
}

实现完这个类后,使用时,new一个此类对象,然后通过它调用bind方法,传入target对象,得到proxy对象再Cast为目标接口对象,通过目标接口对象调用方法,运行可知已经实现了JDK动态代理。完整代码如下。

完整代码

//包括1个接口3个类,分别为目标接口,目标类,关键类,测试类

//目标接口
package com.amiao.design_pattern.dynamic_proxy.jdk;
public interface HelloWorld {
    public void sayHelloWorld();
}

//目标类
package com.amiao.design_pattern.dynamic_proxy.jdk;
public class HelloWorldImpl implements HelloWorld {
    public void sayHelloWorld() {
        System.out.println("Hello World");
    }
}

//关键类
package com.amiao.design_pattern.dynamic_proxy.jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

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("进入逻辑方法之前");
        System.out.println("在调度真实对象之前的服务");
        Object returnObj = method.invoke(target, args);
        System.out.println("在调度真实对象之后的服务");
        return returnObj;
    }
}

//测试类
package com.amiao.design_pattern.dynamic_proxy.jdk;
public class TestMain {
    public static void main(String args[]) {
        JdkProxyExample jdk = new JdkProxyExample();
        HelloWorld proxy = (HelloWorld) jdk.bind(new HelloWorldImpl());
        proxy.sayHelloWorld();
    }
}

/*
* 测试结果
* 进入逻辑方法之前
* 在调度真实对象之前的服务
* Hello World
* 在调度真实对象之后的服务
* */

CGLIB动态代理的完整例子

//包括3个类,目标类,CGLIB动态代理逻辑实现关键类,测试类

//目标类
package com.amiao.design_pattern.dynamic_proxy.cglib;
public class ReflectTarget {
    public void saySomething() {
        System.out.println("Hello, I'm reflect target");
    }
}

//关键类
package com.amiao.design_pattern.dynamic_proxy.cglib;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CglibProxyExample implements MethodInterceptor {

    public Object getProxy(Class cls) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(cls);
        enhancer.setCallback(this);
        return enhancer.create();
    }

    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("进入逻辑方法之前");
        System.out.println("在调度真实对象之前的服务");
        Object returnObj = methodProxy.invokeSuper(proxy, args);
        System.out.println("在调度真实对象之后的服务");
        return returnObj;
    }
}

//测试类
package com.amiao.design_pattern.dynamic_proxy.cglib;
public class TestMain {
    public static void main(String args[]) {
        CglibProxyExample cglib = new CglibProxyExample();
        ReflectTarget proxy = (ReflectTarget) cglib.getProxy(ReflectTarget.class);
        proxy.saySomething();
    }
}

/*
* 测试结果
* 进入逻辑方法之前
* 在调度真实对象之前的服务
* Hello, I'm reflect target
* 在调度真实对象之后的服务
* */

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值