代理设计模式

代理设计模式

定义

代理模式就是设置一个中间代理来控制访问原目标对象,以达到增强原对象的功能和简化访问方式。

静态代理

以买车为例,客户去买车,不会直接去工厂买,去4S点买,而车是从工厂生产运输到4S店,4S店会有上保险,上牌服务这些服务就是一些增强服务,这就是一个静态代理的前提,那就是真实类和代理类要实现同一个接口,在代理类中实现真实类的方法同时可以进行真实类方法的增强处理,在一个代理类中就可以完成对多个真实对象的注入工作
例:

车工厂接口

public interface ICarFactory {
    void saleCar();
}

车工厂类实现车工厂接口

public class CarFactory implements ICarFactory {

    @Override
    public void saleCar() {
        System.out.println("工厂销售汽车!");
    }
}

代理类实现车工厂接口

public class CarProxy implements ICarFactory{

    private ICarFactory icarFactory;

   public CarProxy (ICarFactory icarFactory){
        this.icarFactory = icarFactory;
    }

    @Override
    public void saleCar() {
        System.out.println("4S店汽车买保险");
        icarFactory.saleCar();
        System.out.println("4S店交车");
    }
}

测试类

public class DLtext {
    public static void main(String[] args) {
        ICarFactory factory = new CarFactory();
        CarProxy carProxy = new CarProxy(factory);
        carProxy.saleCar();
    }
}
4S店汽车买保险
工厂销售汽车!
4S店交车

优点:可以在不修改目标对象的前提下扩展目标对象的功能

缺点:如果需要代理多个类,每个类都会有一个代理类,会导致代理类无限制扩展;如果类中有多个方法,同样的代理逻辑需要反复实现、应用到每个方法上,一旦接口增加方法,目标对象与代理对象都要进行修改

所以静态代理不怎么常用

动态代理

从静态代理的代码中可以发现,静态代理的缺点显而易见,那就是当真实类的方法越来越多的时候,这样构建的代理类的代码量是非常大的,所以就引进动态代理.

动态代理允许使用一种方法的单个类(代理类)为具有任意数量方法的任意类(真实类)的多个方法调用提供服务,看到这句话,可以容易的联想到动态代理的实现与反射密不可分。
JAVA 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为 java 语言的反射机制。

1.jdk动态代理(接口代理)
    Jdk代理涉及到java.lang.reflect包中的InvocationHandler接口和Proxy类,核心方法是

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable 

jdk动态代理过程中实际上代理的是接口,是因为在创建代理实例的时候,依赖的是java.lang.reflect包中Proxy类的newProxyInstance方法,该方法的生效就恰恰需要这个参数;

public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException{
        ……
        }

下面以案例来说明jdk动态代理的完整过程:涉及两套接口及其实现类,一个代理类,以及一个测试类

//接口1
public interface Animal {
    void wakeup();
    void sleep();
}

//实现类1
public class Cat implements Animal {
    private String name;
    public Cat() {
    }
    public Cat(String name) {
        this.name = name;
    }
    @Override
    public void wakeup() {
        System.out.println("小猫"+name+"早晨醒来啦");
    }
    @Override
    public void sleep() {
        System.out.println("小猫"+name+"晚上睡觉啦");
    }
}

//实现类2
public class Dog implements Animal {
    private String name;
    public Dog() {
    }
    public Dog(String name) {
        this.name = name;
    }
    @Override
    public void wakeup() {
        System.out.println("小狗"+name+"早晨醒来啦");
    }
    @Override
    public void sleep() {
        System.out.println("小狗"+name+"晚上睡觉啦");
    }
}
//接口2
public interface Person {
    void wakeup();
    void sleep();
}
//实现类1
public class Student implements Person{
    private String name;
    public Student() {
    }
    public Student(String name) {
        this.name = name;
    }
    @Override
    public void wakeup() {
        System.out.println("学生"+name+"早晨醒来啦");
    }
    @Override
    public void sleep() {
        System.out.println("学生"+name+"晚上睡觉啦");
    }
}
//实现类2
public class Doctor implements Person {
    private String name;
    public Doctor() {
    }
    public Doctor(String name) {
        this.name = name;
    }
    @Override
    public void wakeup() {
        System.out.println("医生"+name+"早晨醒来啦");
    }
    @Override
    public void sleep() {
        System.out.println("医生"+name+"晚上睡觉啦");
    }
}

//代理类

public class JDKDynamicProxy implements InvocationHandler {
    private Object bean;
    public JDKDynamicProxy(Object bean) {
        this.bean=bean;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String methodname=method.getName();
        if (methodname.equals("wakeup")){
            System.out.println("早安~~~");
        }else if(methodname.equals("sleep")){
            System.out.println("晚安~~~");
        }
        return method.invoke(bean,args);
    }
}

//测试类

	public class TestJDKDynamicProxy {
    public static void main(String[] args) {
        JDKDynamicProxy proxy = new JDKDynamicProxy(new Student("张三"));
        //创建代理实例
        Person student = (Person) Proxy.newProxyInstance(proxy.getClass().getClassLoader(), new Class[]{Person.class}, proxy);
        student.wakeup();
        student.sleep();
        
        proxy = new JDKDynamicProxy(new Doctor("王教授"));
        Person doctor = (Person) Proxy.newProxyInstance(proxy.getClass().getClassLoader(), new Class[]{Person.class}, proxy);
        doctor.wakeup();
        doctor.sleep();
        
        proxy = new JDKDynamicProxy(new Dog("旺旺"));
        Animal dog = (Animal) Proxy.newProxyInstance(proxy.getClass().getClassLoader(), new Class[]{Animal.class}, proxy);
        dog.wakeup();
        dog.sleep();
  
        proxy = new JDKDynamicProxy(new Cat("咪咪"));
        Animal cat = (Animal) Proxy.newProxyInstance(proxy.getClass().getClassLoader(), new Class[]{Animal.class}, proxy);
        cat.wakeup();
        cat.sleep();
    }
}

在执行过程中,为两个接口分别生成了编译以后的虚拟代理类$Proxy0.class 和 $Proxy1.class,下面以接口1的动态代理过程,讲述jdk动态代理的来龙去脉

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.sun.proxy;

import com.deer.test.com.deer.vo.Person;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0 extends Proxy implements Person {
    private static Method m1;
    private static Method m4;
    private static Method m2;
    private static Method m3;
    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 wakeup() throws  {
        try {
            super.h.invoke(this, m4, (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 void sleep() throws  {
        try {
            super.h.invoke(this, m3, (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"));
            m4 = Class.forName("com.deer.test.com.deer.vo.Person").getMethod("wakeup");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("com.deer.test.com.deer.vo.Person").getMethod("sleep");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

整个调用过程如下(省去本人由于自身原因走的弯路,直接说梳理结果):
从测试类中可以看出,一共创建了四个代理实例,然后每个代理实例对应接口的实现类,道理相同,这里只分析Student类的实现过程

图片: Alt

总结对比:
1.静态代理中,代理类和真实类实现的是同一个接口,重写同样的方法;jdk动态代理中,代理类和真实类关系不大,代理类实现无侵入式的代码扩展。
2.静态代理中当接口中方法增加的时候,在代理类代码量也会增加,显然是不妥的;jdk动态代理解决了这个问题,当业务增加,代理类的代码不会增加。
3.jdk动态代理实现的是jdk自带InvocationHandler接口,实现了这个接口的类也叫拦截器类,也叫代理类。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中的代理设计模式是一种结构型设计模式。它允许一个对象(代理)代替另一个对象(被代理对象)来访问其方法。代理对象可以通过实现与被代理对象相同的接口或继承相同的父类来完成这个任务。 代理对象可以在不改变被代理对象的基本逻辑的情况下,为其添加额外的功能,例如记录日志、缓存数据、权限控制等。代理对象还可以对被代理对象的方法进行验证或重写。 在Java中,代理模式有两种实现方式:静态代理和动态代理。静态代理需要手动编写代理类,而动态代理则是在运行时动态生成代理对象。 静态代理示例代码: ```java public interface Subject { void doSomething(); } public class RealSubject implements Subject { public void doSomething() { System.out.println("RealSubject doSomething"); } } public class ProxySubject implements Subject { private RealSubject realSubject; public ProxySubject() { realSubject = new RealSubject(); } public void doSomething() { System.out.println("Before doSomething"); realSubject.doSomething(); System.out.println("After doSomething"); } } public class Client { public static void main(String[] args) { Subject subject = new ProxySubject(); subject.doSomething(); } } ``` 动态代理示例代码: ```java public interface Subject { void doSomething(); } public class RealSubject implements Subject { public void doSomething() { System.out.println("RealSubject doSomething"); } } public class ProxyHandler implements InvocationHandler { private Object target; public ProxyHandler(Object target) { this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Before " + method.getName()); Object result = method.invoke(target, args); System.out.println("After " + method.getName()); return result; } } public class Client { public static void main(String[] args) { Subject realSubject = new RealSubject(); ProxyHandler proxyHandler = new ProxyHandler(realSubject); Subject proxySubject = (Subject) Proxy.newProxyInstance(realSubject.getClass().getClassLoader(), realSubject.getClass().getInterfaces(), proxyHandler); proxySubject.doSomething(); } } ``` 以上是两种代理模式的示例代码。静态代理需要手动编写代理类,但是代理对象的生成在编译时就已经完成。动态代理则是在运行时动态生成代理对象,可以避免代码重复。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值