Java中的代理模式

一、什么是代理模式?

我们在生活中可能会听见一些xxx代理之类的概念,比如水果商代理、饮品商代理等等。那么我们可以这么理解,本来厂家A生产的东西是自己要卖,但是由于厂家不精通这种销售业务,所以就交给销售商B去卖。B理解为A的代理商。
通过这种方式,可以产家生产出的东西价值达到了最大化。可能这么说不容易理解,下面用代码举例子的方式进行描述。

二、静态代理

1、生产对象

Apple是产家生产的,是要被出售的。我们暂时称为被代理的对象。

public class Apple {
    private String name ;
    public Apple(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "Apple{" +
                "name='" + name + '\'' +
                '}';
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

2、厂家出售接口

厂家生产的Apple要 出售,但是自己出售的价格比较低。所以就需要代理商去出售这些苹果。产家只按统一价格给代理商,至于代理商怎么卖,就不关厂家的事情了。

public interface Producter {
    String sell( Apple apple );
}

3、厂家自己出售

public class ProducterSell implements Producter{
    @Override
    public String sell(Apple apple) {
        System.out.println("我是厂家,我要出售的是" + apple );
        return null;
    }
}

4、代理商出售

public class Agent implements Producter{
    private ProducterSell producter;
    public Agent(ProducterSell producter) {
        this.producter = producter;
    }
    //代理的出售  加入了自己的输出
    @Override
    public String sell(Apple apple) {
        System.out.println("我是代理商A,我要出售的东西是" + apple );
        producter.sell( apple );
        return null ;
    }
}

5、用户接触

public class Customer {
    public static void main(String[] args) {
        Apple apple = new Apple("红富士");
        Agent agent = new Agent( new ProducterSell() );
        agent.sell( apple );
    }
}

输出结果:

我是代理商A,我要出售的东西是Apple{name=‘红富士’}
我是厂家,我要出售的是Apple{name=‘红富士’}

通俗的讲,有两种方式的销售。一种是厂家自己销售,一种是代理商销售。那么厂家销售结果不行,卖不出去的时候,是不是需要一个牌子比较响亮的代理商去出售自家东西。
这里原本是厂家要出售的是Apple,但是在main方法中,用户选择了代理商出售的Apple。归根结底,出售还是厂家的出售,只不过多了一个环节。
这种模式就是我们所说的代理,也就是静态代理。
静态代理就是在编译的时候就把接口、实现类、代理类变成class文件。

三、动态代理机制

在静态代理中,代理商要怎么出售,得自己去实现。如果厂家的出售模式增加,代理就得跟着增加。这种模式就非常的不灵活而且麻烦。所以就产生了一种动态代理机制。
相比静态代理,动态代理更加灵活。不需要去针对每个厂商去创建代理。动态代理是在运行时动态产生类字节码,并加载JVM中。

3.1、JDK的动态代理

3.1.1 创建动态代理

还是以上面的例子,我们定义一个动态的代理商。

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

public class JDKAgentHandler implements InvocationHandler {
    /**
     * 代理类中的真实对象
     */
    private final Object target ;
    public JDKAgentHandler( Object target ){
        this.target = target ;
    }
    
    //invoke() 方法: 当我们的动态代理对象调用原生方法的时候,最终实际上调用到的是 invoke() 方法
    //然后invoke() 方法代替我们去调用了被代理对象的原生方法。
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("方法执行前 :" + method.getName() );
        Object result = method.invoke( target , args );
        System.out.println("方法执行后 :" + method.getName() );
        return result;
    }
}

在这个类中的invoke方法中有三个参数

  • Object proxy 动态生成的代理类
  • Method method 与代理类对象调用的方法对应
  • Object[] args 当前method方法的参数

其他文章已经说过反射,所以这里不做过多的深究。

3.1.2 造一个用来获取代理对象的工厂类

public class JdkProxyFactory {
    //getProxy() :主要通过类方法方法获取某个类的代理对象
    public static Object getProxy( Object target ){
        ClassLoader loader = target.getClass().getClassLoader();  
        Class<?>[] interfaces = target.getClass().getInterfaces(); 
        JDKAgentHandler handler = new JDKAgentHandler( target );
        Object obj = Proxy.newProxyInstance(loader, interfaces, handler) ;
        return obj ;
    }
}
3.1.2 测试动态代理

我们还是用这个用户类进行测试,从而对比其中的区别

public class Customer {
    public static void main(String[] args) {
        Apple apple = new Apple("红富士");
        Agent agent = new Agent( new ProducterSell() );
        agent.sell( apple );

        Producter proxy = (Producter)JdkProxyFactory.getProxy( new ProducterSell() );
        proxy.sell( apple );
    }
}

输出结果:

我是代理商A,我要出售的东西是Apple{name=‘红富士’}
我是厂家,我要出售的是Apple{name=‘红富士’}
方法执行前 :sell
我是厂家,我要出售的是Apple{name=‘红富士’}
方法执行后 :sell

这个例子我们能直观感受到,不用再去手动自己挨个创建代理类。这个只是JDK的动态代理,还有一种CGLIB动态代理,由于要引入jar包,所以暂时不做介绍。

四、对比

1、 动态代理比静态代理更加灵活

动态代理不需要去实现接口,就能直接代理实现类。而且也不需要针对每个目标类都创建一个代理类。

2、JVM

静态代理是在编译的时候,将这些类编译成为字节码文件。而动态代理是在运行时生成类字节码文件,通过类加载器加载到JVM中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值