Java代理模式

x33g5p2x  于2021-10-04 转载在 Java  
字(3.8k)|赞(0)|评价(0)|浏览(305)

Java代理模式

在代理模式(Proxy Pattern)中,一个类代表另一个类的功能

意图: 为其他对象提供一种代理以控制对这个对象的访问

主要解决: 在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。

何时使用: 想在访问一个类时做一些控制

应用实例: 1、Windows 里面的快捷方式。2、买火车票不一定在火车站买,也可以去代售点。3、一张支票或银行存单是账户中资金的代理。支票在市场交易中用来代替现金,并提供对签发人账号上资金的控制

优点: 1、职责清晰。 2、高扩展性。 3、智能化。

缺点: 1、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。 2、实现代理模式需要额外的工作,有些代理模式的实现非常复杂。

使用场景: 按职责来划分,通常有以下使用场景: 1、远程代理。 2、虚拟代理。 3、Copy-on-Write 代理。 4、保护(Protect or Access)代理。 5、Cache代理。 6、防火墙(Firewall)代理。 7、同步化(Synchronization)代理。 8、智能引用(Smart Reference)代理。

注意事项: 代理模式是为了加以控制。 比如框架的AOP 日志 数据库请求异常回滚 …

静态代理

直接上代码 ,看完在总结

//代理接口
public interface Subject {
    //代理的方法
    public void doSomething();
}
//委托类
public class RealSubject implements Subject {
    @Override
    public void doSomething() {
        System.out.println( "我是被代理的方法" );
    }
}
//代理类
public class SubjectProxy implements Subject {
 private   Subject subimpl = new RealSubject();
   @Override
   public void doSomething() {//实现AOP
       System.out.println("前切面");
       subimpl.doSomething();
       System.out.println("后切面");
   }
}
public class Test {

    @org.junit.Test
    public void show(){

        Subject subject=new SubjectProxy();
        subject.doSomething();
    }
}

结果:

前切面我是被代理的方法
后切面

public class Test {

   @org.junit.Test
   public void show(){

       Subject subject=new SubjectProxy();
       subject.doSomething();
   }
}

发现问题了吗 ?

代理类和委托类实现了相同的接口,也就是说代理类和委托类实现了相同的方法。而且一个(代理接口和代理类) 只能代理1个委托类

因为代理类就一个代理方法 已经被一个委托类占用了 就没有方法来代理其他的类了.

如果多个类需要代理的话 那么你就要定义多个代理接口和代理类, 这样就会出现了大量的代码重复。 因为你需要保证代理的方法名称和委托类的方法名称相同 只有这样在调用的时候方法才不会弄错

如果 1万个类的话 是不是很就很困难了 ,这时候动态代理出来了

动态代理

动态代理是调用Proxy的newProxyInstance方法可以生成代理对象 ,来实现代理的

只能代理实现了接口的类,而没有实现接口的类就不能实现动态代理

先看代码

//接口 
public interface Subject {
    public void doSomething();
}
//委托类
public class RealSubject implements Subject {

    @Override
    public void doSomething() {
        System.out.println( "我是被代理的方法" );
    }

}

重点

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

//代理类 固定写法
public class ProxyHandler implements InvocationHandler {
    private Object tar;
    private static ProxyHandler proxy =null;

    public synchronized static ProxyHandler getProxy() {
        if (proxy==null){
            proxy=new ProxyHandler();
        }
        return proxy;
    }

    //绑定委托对象,并返回代理类
    public Object bind(Object tar) {
        this.tar = tar;
//绑定该类实现的所有接口,取得代理类

        ClassLoader classLoader = tar.getClass().getClassLoader();//类加载器。
        Class<?>[] interfaces = tar.getClass().getInterfaces();//对象所有接口
        return Proxy.newProxyInstance(classLoader, interfaces ,this);
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
     Object result = null;
        //这里就可以进行所谓的AOP编程了 比如调用方法前记录日志功能.
        // 在调用具体函数方法前,执行功能处理
        System.out.println("动态代理前切面");
        result = method.invoke(tar, args);
        //在调用具体函数方法后,执行功能处理
        System.out.println("动态代理后切面");
        return result;
    }
}
public class Test{
    	@Test
    public void show_dl(){
        Subject sub =(Subject) ProxyHandler.getProxy().bind(new RealSubject());
        sub.doSomething();
    }
}

前切面
我是被代理的方法
后切面

注意使用动态代码必须有接口 他是通过接口来找到 继承接口类的方法的

  1. Proxy类的代码量被固定下来,不会因为业务的逐渐庞大而庞大;
  2. 可以实现AOP编程,实际上静态代理也可以实现,总的来说,AOP可以算作是代理模式的一个典型应用;
  3. 解耦,通过参数就可以判断真实类,不需要事先实例化,更加灵活多变。
  4. 不好的地方 如果单独代理某些功能 就需要重新创建一个动态代理类 专门处理 这里可以使用静态代理来解决

总结:

动态代理 : 代理那些 通用的事件 所有类 都通用 的 (日志 ,异常结构…)

而静态代理: 代理那些特殊类需要 单独处理 或者是 需要动态代理事件的同时还需要别的事件

这时候肯定不能在动态代理里 添加事件 否则全部动态代理 的类都会受影响

方式1 :如果不需要动态代理 里的事件那么给委托类 写一个静态代理就行了

上面有代码这里就不写了

方式2:如果需要动态代理 里的事件 那么就将动态代理和静态代理组合一下就行了

//接口
public interface Subject {
    public void doSomething();//需要代理的方法
}

//委托类
public class RealSubject implements Subject {
   //重写需要代理的方法
    @Override
    public void doSomething() {
        System.out.println( "我是被代理的方法" );
    }
}

//创建一个 静态代理类 继承同一个接口
//代理类
public class SubjectProxy implements Subject {
   private Subject subimpl = new RealSubject();
   //重写需要代理的方法
    @Override
    public void doSomething() {//实现AOP
        System.out.println("我是静态代理前切面");
        subimpl.doSomething();
        System.out.println("我是静态代理后切面");
    }
}

//省略...ProxyHandler类上面有

//重点强调 传入的对象 不是委托类 而是静态代理类 此时可以把静态代理类当做 委托类就行了 
    @Test
    public void show_dl(){
        Subject sub =(Subject) ProxyHandler.getProxy().bind(new SubjectProxy());
        sub.doSomething();
    }

动态代理前切面
我是静态代理前切面
我是被代理的方法
我是静态代理后切面
动态代理后切面

注意顺序

相关文章

微信公众号

最新文章

更多