代理模式

代理模式基本介绍

img


img



如果不使用代理模式,按照我们传统模式是Client直接调用TargetObject对象。

img



静态代理

img



思路分析图解

img



静态代理代码实现

package com.sky.proxy.staticproxy;

// 接口
public interface ITeacherDao {

    void teach(); // 授课的方法
}

package com.sky.proxy.staticproxy;

/**
 * 目标对象
 */
public class TeacherDao implements ITeacherDao {

    @Override
    public void teach() {
        System.out.println(" 老师授课中 。。。。。");
    }
}

package com.sky.proxy.staticproxy;

/**
 * 代理对象
 */
public class TeacherDaoProxy implements ITeacherDao {

    private ITeacherDao target; // 目标对象

    // 通过创建构造器,进行目标对象的设置
    public TeacherDaoProxy(ITeacherDao target) {
        this.target = target;
    }

    @Override
    public void teach() {
        System.out.println(" 开始代理 。。。。。"); // 可以添加额外的功能
        target.teach(); // 核心方法
        System.out.println(" 提交 。。。。。"); // 可以添加额外的功能
    }
}
package com.sky.proxy.staticproxy;

/**
 * 客户端
 */
public class Client {

    public static void main(String[] args) {
        TeacherDaoProxy proxy = new TeacherDaoProxy(new TeacherDao()); // 代理对象 和 目标对象
        proxy.teach();
    }
}

 开始代理 。。。。。
 老师授课中 。。。。。
 提交 。。。。。

****  

静态代理的优缺点

img



动态代理

img



动态代理应用实例

img


img



代码实现

package com.sky.proxy.dynamicproxy;

/**
 * 接口
 */
public interface ITeacherDao {

    void teach(); // 授课方法
    void sayHi(String name); //
}

package com.sky.proxy.dynamicproxy;

/**
 * 目标对象
 */
public class TeacherDao implements ITeacherDao {

    @Override
    public void teach() {
        System.out.println(" 老师授课中 。。。。 ");
    }

    @Override
    public void sayHi(String name) {
        System.out.println(" hello " + name);
    }
}

package com.sky.proxy.dynamicproxy;

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

/**
 * 代理工厂
 */
public class ProxyFactory {

    private Object target; // 聚合一个目标对象(也就是被代理的对象)

    // 构造器,对target进行初始化
    public ProxyFactory(Object target) {
        this.target = target;
    }

    // 给目标对象生成一个代理对象

    /**
     * newProxyInstance(ClassLoader loader,
     *                                           Class<?>[] interfaces,
     *                                           InvocationHandler h)
     *         throws IllegalArgumentException
     *
       说明:
          1.ClassLoader loader:指定当前目标对象使用的类加载器,获取加载器的方法 固定
          2.Class<?>[] interfaces,目标对象实现的接口类型,使用泛型方法确认类型
          3.InvocationHandler h:事件处理,执行目标对象的方法时,会触发事件处理器方法,会把
                                当前执行的目标对象方法作为参数传入。
     * @return
     */
    public Object getProxyInstance(){

        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println(" JDK代理开始。。。 ");
                        // 反射机制调用目标对象的方法
                        Object returnVal = method.invoke(target, args);
                        System.out.println(" JDK代理提交。。。 ");
                        return returnVal;
                    }
                });
    }
}

package com.sky.proxy.dynamicproxy;

/**
 * 客户端
 */
public class Client {
    public static void main(String[] args) {

        // 创建目标对象
        ITeacherDao target = new TeacherDao();

        // 给目标对象,创建代理对象,可以转成ITeacherDao
        ITeacherDao proxyInstance = (ITeacherDao)new ProxyFactory(target).getProxyInstance();

        System.out.println(" proxyInstance = " + proxyInstance);
        System.out.println(" proxyInstance = " + proxyInstance.getClass());

        // 通过代理对象,调用目标对象中的方法
        proxyInstance.teach();
        proxyInstance.sayHi(" JERRY ");

    }
}

 JDK代理开始。。。 
 JDK代理提交。。。 
 proxyInstance = com.sky.proxy.dynamicproxy.TeacherDao@5cad8086
 proxyInstance = class com.sun.proxy.$Proxy0
 JDK代理开始。。。 
 老师授课中 。。。。 
 JDK代理提交。。。 
 JDK代理开始。。。 
 hello  JERRY 
 JDK代理提交。。。

****  

Cglib代理

img



Cglib代理实现步骤


1)需要引入Cglib的jar包

img

以上是教学视频中引入的jar包,我是引入的下面的jar包

jar://D:/test/cglib-nodep-3.3.0.jar!/

两者最终实现的效果都是一样的。

1)在内存中动态构建子类,注意代理的类不能为final,否则会报错。java.lang.IllegalArgumentException.

2)目标对象的方法如果为final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法。


案例类图

img



代码实现

package com.sky.proxy.cglibproxy;

/**
 * 目标对象
 */
public class TeacherDao {

    public String teach() {
        System.out.println(" 老师授课中 。。。。我是cglib代理,不需要实现接口  ");
        return " hello ";
    }


}

package com.sky.proxy.cglibproxy;

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 ProxyFactory implements MethodInterceptor {

    private Object target; // 聚合一个目标对象(也就是被代理的对象)

    // 构造器,对target进行初始化
    public ProxyFactory(Object target) {
        this.target = target;
    }

    // 返回一个代理对象 是 target 对象的代理对象
    public Object getProxyInstance(){
        // 1.创建一个工具类
        Enhancer enhancer = new Enhancer();

        // 2.设置父类
        enhancer.setSuperclass(target.getClass());

        // 3.设置回调函数
        enhancer.setCallback(this); // 这里的this就是intercept方法自己

        // 4.创建子类对象,即代理对象
        return enhancer.create();

    }

    // 重写intercept方法,会调用目标对象的方法
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {

        System.out.println(" cglib代理模式。。。开始 ");
        Object returnVal = method.invoke(target,objects);
        System.out.println(" cglib代理模式。。。提交 ");

        return returnVal;

    }


}

package com.sky.proxy.cglibproxy;

/**
 * 客户端
 */
public class Client {
    public static void main(String[] args) {


        TeacherDao target = new TeacherDao();

        TeacherDao proxyInstance = (TeacherDao) new ProxyFactory(target).getProxyInstance();

        String result = proxyInstance.teach();
        System.out.println(" 返回结果 : " + result);

    }
}

 cglib代理模式。。。开始 
 老师授课中 。。。。我是cglib代理,不需要实现接口  
 cglib代理模式。。。提交 
 返回结果 :  hello 

****  

代理模式的变体

img


posted on 2022-12-07 09:33  ~码铃薯~  阅读(19)  评论(0编辑  收藏  举报

导航