代理模式—设计模式

设计模式中的代理模式

为某个对象提供一个代理,从而控制这个代理的访问。代理类和委托类具有共同的父类或父接口,这样在任何使用委托类对象的地方都可以使用代理类对象替代。代理类负责请求的预处理、过滤、将请求分配给委托类处理、以及委托类处理完请求的后续处理。

代理模式分为两种:

      ①.静态代理

      ②.动态代理

一、静态代理

由程序员创建或工具生成代理类的源码,再编译代理类。所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。

例如:

抽象角色

public interface AbstractSubject {
     void doSomething();
}

代理角色 

public class ProxySubject implements AbstractSubject{
     private AbstractSubject  real ;
     public ProxySubject(AbstractSubject  real) {
         this.real=real ;
    }
     @Override
     public void doSomething() {

         real.doSomething();
    }

     public void doOtherthing() {

    }
}

真实角色 

public class RealSubject implements AbstractSubject{
     @Override
     public void doSomething() {
        System.out.println( "真实角色被使用" );
    }
}

客户端 

public class Client {
     public static void main(String[]  args ) {
        RealSubject real = new  RealSubject();
        ProxySubject proxy = new  ProxySubject( real );
         proxy.doSomething();
    }
} 

静态代理的优缺点

优点: 业务类只需要关注业务逻辑本身,保证了业务类的重用性。这是代理的共有优点。
缺点:代理对象的一个接口只服务于一种类型的对象,如果要代理的方法很多,势必要为每一种方法都进行代理,静态代理在程序规模稍大时就无法胜任了。如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。 

二、动态代理

动态代理类的源码是程序在运行期间由JVM根据反射等机制动态生成的,所以不存在代理类的字节码文件。代理角色和真实角色的联系在程序运行时确定。

动态代理相关JavaAPI:

① .java.lang.reflect.Proxy

这是Java动态代理机制生成的所有代理类的父类,它提供了一组静态的方法来为一组接口动态的生成代理类及其对象。

Proxy类的静态方法:

//方法 1: 该方法用于获取指定代理对象所关联的调用处理器  
static InvocationHandler getInvocationHandler(Object proxy )  
//方法 2:该方法用于获取关联于指定类装载器和一组接口的动态代理类的类对象  
static Class getProxyClass(ClassLoader loader,Class[] interfaces)  
//方法 3:该方法用于判断指定类对象是否是一个动态代理类  
static boolean isProxyClass(Class cl )    
//方法 4:该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
static Object newProxyInstance(ClassLoader loader,  Class[] interfaces, InvocationHandler  h )

② .java.lang.reflect.InvocationHandler

这是调用处理器接口,它自定义了一个 invoke 方法,用于集中处理在动态代理类对象上的方法调用,通常在该方法中实现对委托类的代理访问。每次生成动态代理类对象时都要指定一个对应的调用处理器对象。

InvocationHandler核心方法:

//该方法负责集中处理动态代理类上的所有方法调用。第一个参数既是代理类实例,第二个参数是被调用的方法对象  
//第三个方法是调用参数。调用处理器根据这三个参数进行预处理或分派到委托类实例上反射执行   
Object invoke(Object proxy, Method  method,Object[] args )

③ .java.lang.reflect.ClassLoader

这是类装载器类,负责将类的字节码装载到 Java 虚拟机(JVM)中并为其定义类对象,然后该类才能被使用。Proxy 静态方法生成动态代理类同样需要通过类装载器来进行装载才能使用,它与普通类的唯一区别就是其字节码是由 JVM 在运行时动态生成的而非预存在于任何一个 .class 文件中。每次生成动态代理类对象时都需要指定一个类装载器对象 。

 动态代理实现步骤:

①  实现InvocationHandler接口创建自己的调用处理器 。

②  给Proxy类提供ClassLoader和代理接口类型数组创建动态代理类 。

③  执行真实角色具体任务。

例如:

创建自己的调用处理器

public class SubjectHandler implements InvocationHandler{
    AbstractSubject real;
    public SubjectHandler(AbstractSubject real){
        this.real=real;
    }

    @Override
    public Object invoke(Object obj, Method method, Object[] args)throws Throwable {
        System.out.println("代理类预处理任务");
        //利用反射机制将请求分派给委托类处理。Method的invoke返回Object对象作为方法执行结果。  
        //因为示例程序没有返回值,所以这里忽略了返回值处理
        method.invoke(real, args);
        System.out.println("代理类后续处理任务");
        return null;
    }
}

客户端

public class Client {

    public static void main(String[] args) {
        RealSubject real=new RealSubject();
        SubjectHandler handler=new SubjectHandler(real);
        //生成代理类对象
        AbstractSubject proxy=(AbstractSubject) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{AbstractSubject.class},handler);
        proxy.doSomething();

    }
}

动态代理的优缺点

优点:
  动态代理与静态代理相比较,最大的好处是接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理(InvocationHandler.invoke)。这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。
缺点:
  Proxy 已经设计得非常优美,但是还是有一点点小小的遗憾之处,那就是它始终无法摆脱仅支持 interface 代理的桎梏,因为它的设计注定了这个遗憾。回想一下那些动态生成的代理类的继承关系图,它们已经注定有一个共同的父类叫 Proxy。Java 的继承机制注定了这些动态代理类们无法实现对 class 的动态代理,原因是多继承在 Java 中本质上就行不通。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值