设计模式-代理模式

1、概念

为其他对象提供一种代理以控制这个对象的访问,在某些情况下一个对象不能直接访问那个对象时,代理就起到了客户端和被代理对象(委托类)中介作用。 代理类和委托类都有同样接口。

可以不用动原来类的逻辑,再次增加一些功能,符合开闭原则。真正的业务还是交给被代理对象处理的,因此在其委托被代理对象处理业务前后实现一些公共逻辑服务,例如加入缓存或日志等功能,无须修改原来的类就可以使用代理进行实现。

2、示例程序

静态代理模式:

类图:
在这里插入图片描述
Printable: 代理类和被代理类实现同样的接口

PrintProxy:代理类,里面有被代理类,具体逻辑委托被代理类进行处理

Printer:被代理类,可以在其内做一些访问权限控制,额外的业务处理,日志处理

Main:看到的是代理类,并不知道具体处理业务逻辑的类,降低耦合性

代码实现:

Printable.java

package proxy.print;
 
public interface Printable {
    public void setName(String name);
 
    public String getName();
 
    public void print(int count);
 
    public void SetColor(int color);
}

Printer.java

package proxy.print;
 
public class Printer implements Printable {
 
    private String name;
 
    private int color;
 
    @Override
    public void setName(String name) {
        this.name = name;
    }
 
    @Override
    public String getName() {
        return this.name;
    }
 
    @Override
    public void print(int count) {
        System.out.println("---------" + this.name + "------");
        for (int i = 0; i < count; i++) {
            System.out.println("....");
            try {
                Thread.sleep(1000L);
            } catch (Exception e) {
 
            }
        }
        System.out.println("-------------------");
    }
 
    @Override
    public void SetColor(int color) {
        this.color = color;
    }
}

PrintProxy.java

package proxy.print;
 
public class PrintProxy implements Printable {
 
    private Printable printable;
 
    public void setPrintable(Printable printable) {
        this.printable = printable;
    }
 
    @Override
    public void setName(String name) {
        System.out.println("开始执行setName()");
        long currentTimeMillis = System.currentTimeMillis();
        printable.setName(name);
        System.out.println("执行完成,执行耗时:" + (System.currentTimeMillis() - currentTimeMillis) + "ms");
    }
 
    @Override
    public String getName() {
        return printable.getName();
    }
 
    @Override
    public void print(int count) {
        System.out.println("开始执行print()");
        long currentTimeMillis = System.currentTimeMillis();
        printable.print(count);
        System.out.println("执行完成,执行耗时:" + (System.currentTimeMillis() - currentTimeMillis) + "ms");
    }
 
    @Override
    public void SetColor(int color) {
        printable.SetColor(color);
    }
}

Main.java

package proxy.print;
 
public class Main {
    public static void main(String[] args) {
        PrintProxy printProxy = new PrintProxy();
        printProxy.setPrintable(new Printer());
        printProxy.setName("Case 01");
        printProxy.print(3);
    }
}

Jdk动态代理模式:

要求被代理类必须要实现接口,因为JDK动代理实现是通过实现接口方式来实现的。需要实现 InvocationHandler接口(在invoke方法中实现一些额外的逻辑,添加一些新功能),通过

Proxy.newProxyInstance(Hello.class.getClassLoader(), HelloImpl.class.getInterfaces(), new MyInvocationHandler(new HelloImpl()))

实现步骤:

1.定义一个接口Hello

2.编写该接口的实现类HelloImpl

3.编写InvocationHandler接口的实现类MyInvocationHandler,构造h类对象的时候可以把要代理的对象target传入,target完成实际的动作。在里面的invoke方法里编写自己想实现的逻辑,然后再调用实际要完成的动作就可以。

4.调用Proxy.newProxyInstance方法,传递的三个参数分别是代理类的类加载器、代理类要实现的接口列表、InvocationHandler实现类的实例。

这样就生成了HelloImpl类 的 对 象 ,由于HelloImpl类实现了ProxyObj接口,所以可以将对象强制转型成Hello

再说一下Proxy.newProxyInstance方法的实际过程:

1.使用传入的InvocationHandler实例参数将Proxy类的h实例初始化,注意,如果传入空对象的话,会抛出空指针错误,即h不能为空。

2.运行时生成代理Class,即$Proxy0

3.利用上面动态生成的$Proxy0类,构造出该类的对象,并返回,完成sayHello()方法。

类图:

在这里插入图片描述
Hello.java


package proxy.jdk;
 
public interface Hello {
 
    public void sayHello();
 
}

HelloImpl.java

package proxy.jdk;
 
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
 
import static java.lang.Class.forName;
 
public class HelloImpl implements Hello {
 
    @Override
    public void sayHello() {
        System.out.println("Hello, xixi!");
    }
 
/*
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, ClassNotFoundException {
//        Constructor<HelloImpl> constructor1 = HelloImpl.class.getConstructor();
//        Constructor<HelloImpl> constructor2 = HelloImpl.class.getConstructor(String.class);
//        Constructor<HelloImpl> constructor3 = HelloImpl.class.getConstructor(Integer.class);
//        System.out.println("do nothing");
 
        HelloImpl hello = new HelloImpl();
        Method method = Hello.class.getMethod("sayHello");
        method.invoke(hello);
        System.out.println("do nothing");
 
    }*/
}

MyInvocationHandler.java

package proxy.jdk;
 
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
 
public class MyInvocationHandler implements InvocationHandler {
  
    /** 目标对象 */
    private Object target;
  
    public MyInvocationHandler(Object target){
        this.target = target;
    }
  
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 
        System.out.println("------插入前置通知代码-------------");
        // 执行相应的目标方法
        Object rs = method.invoke(target, args);
        System.out.println("------插入后置处理代码-------------");
        return rs;
    }
}

Main.java

package proxy.jdk;
 
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;
 
public class Main {
 
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//        Hello hello = new HelloImpl();
//        hello.sayHello();
 
        // =========================第一种==========================
        // 1、生成$Proxy0的class文件
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        // 2、获取动态代理类
        Class proxyClazz = Proxy.getProxyClass(HelloImpl.class.getClassLoader(), Hello.class);
        // 3、获得代理类的构造函数,并传入参数类型InvocationHandler.class
        Constructor constructor = proxyClazz.getConstructor(InvocationHandler.class);
        // 4、通过构造函数来创建动态代理对象,将自定义的InvocationHandler实例传入
        Hello Hello1 = (Hello) constructor.newInstance(new MyInvocationHandler(new HelloImpl()));
        // 5、通过代理对象调用目标方法
        Hello1.sayHello();
 
 
        //Object proxyInstance = Proxy.newProxyInstance(Hello.class.getClassLoader(), HelloImpl.class.getInterfaces(), new MyInvocationHandler(new HelloImpl()));
 
 
        // ==========================第二种=============================
        /**
         * Proxy类中还有个将2~4步骤封装好的简便方法来创建动态代理对象,
         *其方法签名为:newProxyInstance(ClassLoader loader,Class<?>[] instance, InvocationHandler h)
         */
        Hello Hello2 = (Hello) Proxy.newProxyInstance(Hello.class.getClassLoader(), // 加载接口的类加载器
                new Class[]{Hello.class}, // 一组接口
                new MyInvocationHandler(new HelloImpl())); // 自定义的InvocationHandler
        Hello2.sayHello();
    }
}

$Proxy0

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
 
package com.sun.proxy;
 
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import proxy.jdk.Hello;
 
public final class $Proxy0 extends Proxy implements Hello {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m0;
 
    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }
 
    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }
 
    public final void sayHello() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }
 
    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }
 
    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }
 
    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m3 = Class.forName("proxy.jdk.Hello").getMethod("sayHello");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

CGLIB动态代理:

CGLIB(Code Generation Library)实现动态代理,并不要求被代理类必须实现接口,底层采用asm字节码生成框架生成代理类字节码(该代理类继承了被代理类)。所以被代理类一定不能定义为final class并且对于final 方法不能被代理。

实现代码:

package proxy.cglib;
 
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import proxy.jdk.Hello;
import proxy.jdk.HelloImpl;
 
import java.lang.reflect.Method;
 
public class CglibProxyFactory implements MethodInterceptor {
 
    private Hello target;
 
 
    public Object getProxy(Hello hello) {
        target = hello;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(hello.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }
 
 
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("Cglib动态代理开始执行");
        Object invoke = method.invoke(target, objects);
        System.out.println("Cglib动态代理执行完成");
        return invoke;
    }
 
 
    public static void main(String[] args) {
 
       // System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        CglibProxyFactory proxyFactory = new CglibProxyFactory();
        Hello proxy = (Hello) proxyFactory.getProxy(new HelloImpl());
        proxy.sayHello();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值