静态代理模式、动态代理模式(实现、对比)

一、代理模式包含的角色

1、抽象角色:声明真实对象和代理对象的公共接口。

2、代理角色:代理真实对象,实现真实对象想要实现的功能(方法);另外,可附加自身功能(方法)。在代理真实对象的过程中,为了实现代理,应包含一个真实对象的成员变量,通过此成员变量去实例化真实对象,通过实例去调用真实对象的方法,以此来实现对真实对象的调用,实现代理。

3、真实角色:代理角色所代表的真实对象,是我们最终要引用的对象。

可以中介租房的例子来强化理解:

在租房过程中,中介扮演了代理角色,房主代表了真实角色,抽象角色就是把房子租出去。房客只能从中介这里得到房主出租房屋的信息,房主也只能从中介这里得到房客租用房屋的信息。中介在促成房主和房客的交易后,自身会收取一定的中介费,这就是代理对象附加的功能。


二、代理模式的实现

1、静态代理模式

(1)抽象角色

package com.lpp.proxy;
//抽象角色提供真实角色和代理角色的公共接口,这里用抽象类来定义,也可以用接口来定义
public abstract class Subject
{
    public abstract void service();
}

(2)真实角色

package com.lpp.proxy;

public class Service extends Subject
{

    //真实角色提供最终要实现的方法
    public void service()
    {
        System.out.println("can support a service");
        
    }
}

(3)代理角色

package com.lpp.proxy;

public class ProxyService extends Subject
{

//通过在代理类中引入真实角色的成员变量,借此得到真实角色的实例
    private Service service;
    private void beforeService()
    {
        System.out.println("before Service");
    }
    public void service()
    {
        this.beforeService();//在代理过程前后可以附加其他代理功能
        if(service == null)
        {
            service = new Service(); 
        }     
        service.service();
        this.afterService();//在代理过程前后可以附加其他代理功能
    }
    private void afterService()
    {
        System.out.println("after Service");
    }
    
}

(4)Client端

package com.lpp.proxy;

public class Client
{

//客户端通过代理对象得到真实对象提供的服务
    public static void main(String[] args)
    {
        ProxyService proxyService = new ProxyService();
        proxyService.service();
    }
}

结果:

before Service
can support a service
after Service



2、动态代理模式

动态类是在运行过程中自动生成的,不是自己定义的。

在静态代理中,一个真实对象中的方法对应一个代理对象,当真实对象中有多个方法时,需要的代理对象也会相应增加,造成类的数量的集聚膨胀。动态代理模式中,一个代理对象可以代理多个真实对象。

动态代理类位于java.lang.reflect包下,一般主要涉及到1个列和1个接口,如下:

(1)接口InvocationHandler

java.lang.reflect

Interface InvocationHandler

接口InvocationHandler只有一个方法:Object invoke(Object proxy,Method method, Object[] args) throws Throwable

其中,第一个参数proxy为代理类,第二个参数Method为被代理的方法,第三个参数args为第二个参数Method的参数数组。

(2)类Proxy

  • Proxy类中的重要属性和方法

java.lang.reflect

Class Proxy

类Proxy为动态代理类,其定义如下public class Proxy extends Objectimplements Serializable

类Proxy中有一个成员变量(属性)protected InvocationHandler  可见,利用此属性在代理类中可方便引入真实对象中的方法,实现真实对象的功能。

类Proxy的构造函数如下:

protected Proxy(InvocationHandler h)
可知传入InvocationHandler类型的变量,能够方便定义出一个真实对象的实例。

类Proxy中重要的方法有:

public static Class<?> getProxyClass(ClassLoader loader,Class<?>... interfaces) throws IllegalArgumentException

获得一个代理类,第一个参数是一个类装载器,第二个参数是真实类所拥有的全部接口的数组。

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

返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用代理类在Subject接口中声明过的所有方法)


  • 动态代理的代码编写要点

动态代理对象中通过重写InvocationHandler的invoke()方法,对真实对象中的方法实现调用;Client类中通过使用Proxy类中的newProxyInstance()方法一次性生成代理,此代理又可当作被代理类使用,调用真实对象的方法,完成代理功能。


动态代理的步骤:

1、创建抽象对象、和真实对象:计同静态代理。抽象对象提供代理对象和真实对象的公共接口;真实对象定义代理对象要实现的方法。

2、创建代理对象:创建一个实现几口InvocationHandler的类,然后实现InvocationHandler中的invoke方法。

3、创建代理(Client端):通过Proxy的静态方法

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

创建代理,返回被代理对象(即真实对象),通过返回值调用真实对象的方法,即完成一次动态代理。
  • 动态代理代码示例

(1)抽象对象(和静态代理差不多)

package com.lpp.proxy;

interface Subject
{
    public void service();
}

(2)真实对象(和静态代理完全相同)

package com.lpp.proxy;

public class Service implements Subject
{
    public void service()
    {
        System.out.println("can support a service");        
    }
}

(3)代理对象(和静态代理不同)

package com.lpp.proxy;

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

public class ProxyService implements InvocationHandler
{
    private Object sub;
    //构造方法
    public ProxyService(Object obj)
    {
        this.sub = obj;        
    }
    private void beforeService()
    {
        System.out.println("before Service");
    }
    
    //重写接口InvocationHandler中的invoke方法
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable
    {
        this.beforeService();
        
        //调用真实对象中的方法,实现真实对象的功能
        method.invoke(sub,args);
        
        this.afterService();
        return null;        
    }
    private void afterService()
    {
        System.out.println("after Service");
    }
}

(4)Client类的实现(和静态代理不同)

package com.lpp.proxy;

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

public class Client
{
    public static void main(String[] args) throws Exception
    {
        Service service = new Service();
        //因为ProxyService类实现了InvocationHandler接口,因此可以利用多态性为InvocationHandler实例化
        InvocationHandler handler = new ProxyService(service);
        Class<?> classType = handler.getClass();
        //一次性生成代理实例,返回结果可作为真实对象使用
        Subject subject = (Subject)Proxy.newProxyInstance(classType.getClassLoader(),Service.class.getInterfaces(),handler);
        //调用真实对象的方法,完成真实对象的功能
        subject.service();
    }
}

结果:

before Service
can support a service
after Service


总结:

动态代理类可解决静态代理类中类的集聚膨胀问题,两者区别在于代理对象的定义。动态代理类是在运行过程中生成的,是一个动态类。在静态代理中,代理对象和真实对象共同的接口可以用抽象类或接口的形式来定义,而动态代理中,只能以接口的形式来定义,因为Proxy类中newProxyInstance()的第二个参数是代理类在Subject中定义的所有接口的数组。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值