java——静态代理

代理模式

  代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问。

  在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

 

代理模式一般涉及到的角色

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

(为什么要有抽象角色?)因真实对象和代理对象可以实现相同的功能,但客户不能直接使用真实对象的功能,可通过代理对象的功能调用真是对象的功能,所以该功能(比如例子中的request())就在一个抽象类或者接口中声明。

  代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能够代替真实对象。

  同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。

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

 

用实例来说明

  首先是抽象角色类,可以定义一个接口或者抽象类: 

复制代码
/**
 * 真实对象和代理对象的共同接口
 * 
 */
public abstract class Subject
{
    public abstract void request();
}
复制代码

  之后是真实角色的类,实现接口,并完成实际工作:

复制代码
/**
 * 真实角色
 */
public class RealSubject extends Subject
{
    @Override
    public void request()
    {
        System.out.println("From Real Subject!");
    }
}
复制代码

  然后定义代理角色,内部包含对真实角色对象的引用,并且封装功能:

 

复制代码
/**
 * 代理角色
 * 
 */
public class ProxySubject extends Subject
{
    //代理角色对象内部含有对真实对象的引用
    private RealSubject realSubject;

    @Override
    public void request()
    {
        //在真实角色操作之前所附加的操作
        preRequest();
        if(null == realSubject)
        {
            realSubject = new RealSubject();
        }
        
        //真实角色所完成的事情
        realSubject.request();
        //在真实角色操作之后所附加的操作
        postRequest();
    }
    
    private void preRequest()
    {
        System.out.println("Pre Request.");
    }
    private void postRequest()
    {
        System.out.println("Post Request");
    }
}
复制代码

  在客户端进行调用时:

复制代码
/**
 * 客户类
 *  
 */
public class Client
{
    public static void main(String[] args)
    {
        Subject subject = new ProxySubject();
        subject.request();        
    }    
}
复制代码

  

由以上代码可以看出,客户实际需要调用的是RealSubject类的request()方法,现在用ProxySubject来代理RealSubject类,同样达到目的,同时还封装了其他的方法(preRequest(),postRequest()),可以处理一些其它问题。

问题

  如果要按照上述的方式(静态代理)使用代理模式,那么真实角色必须是实现已经存在的,并将其作为代理对象的内部属性。

  但是实际使用时,一个真实角色必须对应一个代理角色,但如果大量使用会导致类的急剧膨胀;此外,如果事先并不知道真实角色,该如何使用代理呢?这个问题可以通过Java的动态代理类来解决。

 

参考资料

  圣思园张龙老师Java SE系列视频教程。


  应用场景

现实世界中,秘书就相当于一个代理,老板开会,那么通知员工开会时间、布置会场、会后整理会场等等开会相关工作就可以交给秘书做,老板就只需要开会就行了,不需要亲自做那些事。同理,在我们程序设计中也可使用代理模式来将由一系列无关逻辑组合在一起的代码进行解耦合,比如业务代码中的日志代码就可以在代理中进行。Spring的AOP就是典型的动态代理应用。

  代理模式的应用形式

(1)远程代理(Remote Proxy) -可以隐藏一个对象存在于不同地址空间的事实。也使得客户端可以访问在远程机器上的对象,远程机器可能具有更好的计算性能与处理速度,可以快速响应并处理客户端请求。

(2)虚拟代理(Virtual Proxy) – 允许内存开销较大的对象在需要的时候创建。只有我们真正需要这个对象的时候才创建。

(3)写入时复制代理(Copy-On-Write Proxy) – 用来控制对象的复制,方法是延迟对象的复制,直到客户真的需要为止。是虚拟代理的一个变体。

(4)保护代理(Protection (Access)Proxy) – 为不同的客户提供不同级别的目标对象访问权限

(5)缓存代理(Cache Proxy) – 为开销大的运算结果提供暂时存储,它允许多个客户共享结果,以减少计算或网络延迟。

(6)防火墙代理(Firewall Proxy) – 控制网络资源的访问,保护主题免于恶意客户的侵害。

(7)同步代理(SynchronizationProxy) – 在多线程的情况下为主题提供安全的访问。

(8)智能引用代理(Smart ReferenceProxy) - 当一个对象被引用时,提供一些额外的操作,比如将对此对象调用的次数记录下来等。

(9)复杂隐藏代理(Complexity HidingProxy) – 用来隐藏一个类的复杂集合的复杂度,并进行访问控制。有时候也称为外观代理(Façade Proxy),这不难理解。复杂隐藏代理和外观模式是不一样的,因为代理控制访问,而外观模式是不一样的,因为代理控制访问,而外观模式只提供另一组接口。


### Java静态代理与动态代理的区别 #### 静态代理的特点 在静态代理中,客户端通过代理类间接调用实际业务逻辑的对象方法。这种方式下,代理类和真实主题都实现了相同的接口,并且代理类持有对真实主题的引用[^4]。 对于静态代理而言,一旦定义好了一个具体的代理类之后,在编译期就已经确定下来了;这意味着如果想要更改或增加新的行为时就需要重新创建一个新的代理类来满足需求[^1]。 ```java // 定义一个接口 public interface Service { void doSomething(); } // 实现该接口的真实服务提供者 class RealService implements Service { @Override public void doSomething() { System.out.println("Real service is doing something."); } } // 创建一个具体的服务代理类也实现同样的接口并持有一个指向真正执行者的引用 class StaticProxy implements Service { private final Service realService; public StaticProxy(Service realService) { this.realService = realService; } @Override public void doSomething() { // 增强前处理... System.out.println("Before calling the actual method"); // 调用真正的业务逻辑 realService.doSomething(); // 增强后处理... System.out.println("After calling the actual method"); } } ``` #### 动态代理的优势 相比之下,JDK 提供了一种更加灵活的方式——即所谓的“动态代理”。它允许程序在运行期间根据传入参数自动生成相应的代理实例而无需提前编写任何额外代码[^3]。 为了支持这种机制,Java SE API 提供了 `java.lang.reflect.InvocationHandler` 接口以及 `java.lang.reflect.Proxy` 类用于生成代理对象。当某个方法被调用时会触发 InvocationHandler 的 invoke 方法来进行拦截操作[^2]。 ```java import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; // 自定义 invocation handler 来指定如何响应来自代理对象的方法请求 class DynamicInvocationHandler implements InvocationHandler { private Object target; public DynamicInvocationHandler(Object target){ this.target=target; } @Override public Object invoke(Object proxy, Method method, Object[] args)throws Throwable{ // 执行前置增强逻辑 ... System.out.println("Before invoking " + method.getName()); // 将调用转发给原始的目标对象 var result=method.invoke(target,args); // 进行后续增强逻辑 ... System.out.println("After invoking " + method.getName()); return result; } } // 使用反射创建代理对象 Service dynamicProxyInstance=(Service) Proxy.newProxyInstance( RealService.class.getClassLoader(), new Class[]{Service.class}, new DynamicInvocationHandler(new RealService()) ); dynamicProxyInstance.doSomething(); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值