JAVA代理

1. 代理模式

  • Proxy Pattern,又称为委托模式,为设计模式的一种

  • 为目标对象提供了一个代理,这个代理可以控制对目标对对象的访问
    • 外界不用直接访问目标对象,而是访问代理对象,由代理对象再调用目标对象
    • 代理对象中可以添加监控和审查处理

2. 静态代理

  • 代理对象持有目标对象的句柄,成员变量

  • 所有调用目标对象的方法,都调用代理对象的方法
  • 对每个方法都需要静态编码

public interface Subject{
    public void request();
}

//原对象
class SubjectImpl implements Subject{
  public void request(){
      System.out.println("I am dealing the request.");
  }
}

//代理对象
class StaticProxy implements Subject{
    //实际目标对象
    private Subject subject;
    public StaticProxy(Subject subject){
        this.subject = subject;
    }
    public void request(){
        System.out.println("PreProcess");
        subject.request();
        System.out.println("PostProcess");
    }
    public static void main(String args[]){
        //创建实际对象
        SubjectImpl subject = new SubjectImpl();
        //把实际对象封装到代理对象中
        StaticProxy p = new StaticProxy(subject);
        p.request();
    }
}

3. 动态代理

  • 代理处理器持有目标对象的句柄

  • 代理处理器实现InvocationHandler接口
    • 实现invoke方法
    • 所有的代理对象方法调用,都会转发到invoke方法来
    • invoke的形参method,就是指代理对象方法的调用
    • 在invoke内部,可以根据method,使用目标对象不同的方法来响应请求

public interface Subject{
    public void request();
}

//目标对象
class SubjectImpl implements Subject{
  public void request(){
      System.out.println("I am dealing the request.");
  }
}

/**
 * 代理类的调用处理器
 */
class ProxyHandler implements InvocationHandler{
    private Subject subject;
    public ProxyHandler(Subject subject){
        this.subject = subject;
    }
    
    //此函数在代理对象调用任何一个方法时都会被调用。
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        System.out.println(proxy.getClass().getName());
        //定义预处理的工作,当然你也可以根据 method 的不同进行不同的预处理工作
        System.out.println("====before====");
        Object result = method.invoke(subject, args);
        System.out.println("====after====");
        return result;
    }
}
//动态代理模式
public class DynamicProxyDemo {
    public static void main(String[] args) {
        //1.创建目标对象
        SubjectImpl realSubject = new SubjectImpl();    
        
        //2.创建调用处理器对象
        ProxyHandler handler = new ProxyHandler(realSubject); 
        
        //3.动态生成代理对象
        Subject proxySubject = 
                (Subject)Proxy.newProxyInstance
                  (SubjectImpl.class.getClassLoader(),
                   SubjectImpl.class.getInterfaces(), handler); 
        //proxySubject真实类型com.sun.proxy.$Proxy0
        //proxySubject继承Proxy类,实现Subject接口
        //newProxyInstance的第二个参数,就是指定代理对象的接口
        
        //4.客户端通过代理对象调用方法
        //本次调用将自动被代理处理器的invoke方法接收
        proxySubject.request();    
        
        System.out.println(proxySubject.getClass().getName());
        System.out.println(proxySubject.getClass().getSuperclass().getName());
    }
}
/*result:
com.sun.proxy.$Proxy0
====before====
I am dealing the request.
====after====
com.sun.proxy.$Proxy0
java.lang.reflect.Proxy
*/

动态代理是怎样调用invoke()方法?

  1. 通过Proxy.newProxyInstance()动态代理生成对象,com.sun.proxy.$Proxy0代理类由JDK自己生成,生成一个继承Proxy和实现subject接口的代理类。

  2. 然后把得到的$Proxy0实例强制转型为Subject,并将引用赋给subject。
  3. 接着$Proxy0调用父类Proxy的构造器,为h赋值。
  4. 当执行subject.request()方法时,就调用了$Proxy0类中的request()方法,进而调用父类Proxy中的h的invoke()方法.即InvocationHandler.invoke()。
public final class $Proxy0 extends Proxy implements subject { 

    //....
    public final void request() {  
        try {  
            super.h.invoke(this, m3, null);  
            return;  
        } catch (Error e) {  
        } catch (Throwable throwable) {  
            throw new UndeclaredThrowableException(throwable);  
        }  
    } 
    //.....
}

JDK动态代理文件$Proxy0.class的生成和查看

invoke()调用问题

代理对象

  1. 通常和目标对象实现同样的接口(可另实现其他的接口)
  2. 实现多个接口
    1. 接口的排序非常重要
    2. 当多个接口里面有方法同名,则默认以第一个接口的方法调用
  3. 根据给定的接口,由Proxy类自动生成的对象
  4. 类型 com.sun.proxy.$Proxy0,继承自java.lang.reflect.Proxy
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java代理模式是一种结构型设计模式,其目的是为其他对象提供一种代理以控制对这个对象的访问。代理对象可以在客户端和目标对象之间充当中介,以便于客户端访问目标对象时,可以在不改变目标对象的情况下添加一些额外的功能,比如安全性、远程访问、缓存等。 在Java中,代理模式可以通过两种方式实现:静态代理和动态代理。静态代理需要手动编写代理类,而动态代理可以在运行时通过反射机制动态生成代理类,更加灵活。 举个例子,假设我们有一个接口`Subject`,其中定义了一些方法。我们希望在调用这些方法时,增加一些额外的日志记录功能。我们可以编写一个代理类`SubjectProxy`,在代理类中实现接口方法并调用目标对象的方法,同时在方法前后添加日志记录的代码。客户端则通过代理类访问目标对象。 静态代理示例代码如下: ```java public interface Subject { void doSomething(); } public class RealSubject implements Subject { @Override public void doSomething() { System.out.println("RealSubject do something."); } } public class SubjectProxy implements Subject { private Subject realSubject; public SubjectProxy(Subject realSubject) { this.realSubject = realSubject; } @Override public void doSomething() { System.out.println("Before do something."); realSubject.doSomething(); System.out.println("After do something."); } } public class Client { public static void main(String[] args) { Subject realSubject = new RealSubject(); Subject subjectProxy = new SubjectProxy(realSubject); subjectProxy.doSomething(); } } ``` 动态代理示例代码如下: ```java public class SubjectHandler implements InvocationHandler { private Object target; public SubjectHandler(Object target) { this.target = target; } @Override 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(); InvocationHandler handler = new SubjectHandler(realSubject); Subject subjectProxy = (Subject) Proxy.newProxyInstance(realSubject.getClass().getClassLoader(), realSubject.getClass().getInterfaces(), handler); subjectProxy.doSomething(); } } ``` 无论是静态代理还是动态代理代理模式都可以在不改变目标对象的情况下,为其添加额外的功能,提高代码的可复用性和灵活性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值