Java中的代理模式

Posted BoildWater

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java中的代理模式相关的知识,希望对你有一定的参考价值。

一、什么是代理模式?

? 这里不做过多的理论解释,相关资料一大堆,只简单说下我理解的代理模式,代理模式的意思就是你想完成的工作不用自己完成,交给代理去帮你去完成。代理模式的案例生活中很常见,比如:毕业了在城市里工作,需要租房,大部分人都会接触到中介,通过中介租房,这里的中介在代理模式中就充当了代理的角色,中介代理真实房东带你去看房,有些权利大的中介,甚至会代理真实房东和你签合同。

1.代理模式有什么好处?

1).中介隔离

? 还以上面租房为例:我是一位真实房东,家里有很多房产,打工是不可能打工的,平时就靠收收房租维持生活这样子。但是最近正好赶上毕业季,天天有租客联系我租房、看房,楼上楼下的跑是真累啊,而且还租不出去几套房子,这样的生活不能再持续下去了。于是我拨通了呗柯公寓的电话,希望呗柯公寓能够代理我的房子,帮我租出去,这样每天我就可以边收房租边好好呆在王者峡谷,不用每天去跟租客接触了。

2).在遵循开闭原则的情况下,增加功能

? 和呗柯公寓谈好价格后,我就等着房子租出去后,收租就行了,某一间房1500元每月,这是我跟呗柯公寓说好的价格。于是呗柯公寓的中介开始工作了,为了让租客对房子有一个很好的第一印象,负责的中介认真地打扫了整个房间,毕竟自己付出了劳动,也得给自己点回报,于是中介将房租价格加价200,打算以1700的价格出租出去,很快哈,房子就被租出去了,在我和租客签完合同后,中介又热心地帮助租客提运行李

? 在上面租房的整个过程中,如果是我本人跟租客进行交涉,那么在签合同前,我不会打扫房间,也不会加价,也不会在合同签好之后,帮助租客提运行李,这些都是中介的附加行为,而我跟中介的唯一要求就是房子租出去签好合同,并且价格1500就行,中介的这些附加行为就相当于在不影响我的要求下(遵循开闭原则),增加的功能。

二、静态代理

? 静态代理是代理模式的一种,之所以会被称为静态代理,是因为还有个动态代理与之相对,下面直接以代码为例描述静态代理。

两个单词
Landlord:房东
Agency:中介
/**
 * 房东接口,不管每个月要1500还是每个月3000、5000的房东,都要签合同
 */
public interface LandlordInterface {

    void sign();
}

/**
 * 每月要1500元的一个真实房东
 */
public class Landlord implements LandlordInterface{

    @Override
    public void sign() {
        System.out.println("和租客签合同,1500元每月...");
    }
}

/**
 * 中介
 */
public class Agency implements LandlordInterface{

    private Landlord landlord;

    public Agency(Landlord landlord) {
        this.landlord = landlord;
    }

    @Override
    public void sign() {
      	// 在和租客签合同前,中介的"附加行为"
        System.out.println("打扫房间...");
        System.out.println("将房间价格加价200...");
      	// 房东和租客签合同
        landlord.sign();
      	// 在和租客签合同后,中介的"附加行为"
        System.out.println("帮租客提运行李...");
    }
}

/**
 * 模拟租房过程的一个测试类
 */
public class Test {

    public static void main(String[] args) {
        Landlord landlord = new Landlord();
        // 中介要完成房东的要求,要完成哪个房东要求?所以需要在构造方法中传入这个租金为1500元的房东
        Agency agency = new Agency(landlord);
        // 签合同
        agency.sign();
    }
}

运行测试类的结果:

打扫房间...
将房间价格加价200...
真实房东和租客签合同,1500元每月...
帮租客提运行李...

? 以上代码描述的就是一个静态代理的过程,简单并且很容易理解。但是,如果这位房东不想自己收租了,于是把收租的权利也交给了中介,那么中介就要给自己添加一条收租行为;如果房东不想收水电费了,中介还要给自己添加一条收水电费的行为;如果房东...... 只要房东一有要求,那么中介类就要修改自己的行为(修改代码)。很显然,这种静态代理模式不是我们经常会用到的。

三、动态代理

? 动态代理分为JDK动态代理和Cglib动态代理,与静态代理相比较,从代码的角度看,代理类不再需要我们手动去创建了,而是根据被代理对象的需求动态生成一个代理对象。

1.JDK动态代理

? JDK动态代理是Java提供的一种动态代理Api,要使用JDK动态代理,被代理对象需要实现一个接口,下面用代码演示一下动态代理的过程。

/**
 * 房东接口
 */
public interface LandlordInterface {

    void sign();
}

/**
 * 每月要1500元的一个真实房东
 */
public class Landlord implements LandlordInterface{

    @Override
    public void sign() {
        System.out.println("和租客签合同,1500元每月...");
    }
}

/**
 * 使用JDK动态代理,需要编写一个类实现InvocationHandler接口
 */
public class MyInvocationHandler implements InvocationHandler {

    /**
     * 被代理的对象(比如房东)
     */
    private Object target;

    public MyInvocationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      	// 中介每次在执行房东的任务前,都会加收租客费用
        System.out.println("加价收取租客费用...");
      	// 执行房东的任务(即执行房东对象对应的方法)
        Object result = method.invoke(target, args);
        return result;
    }
}

/**
 * 模拟租房过程的一个测试类
 */
public class Test {
    public static void main(String[] args) {

        Landlord landlord = new Landlord();
        MyInvocationHandler invocationHandler = new MyInvocationHandler(landlord);
      	// 动态生成一个代理对象
        LandlordInterface proxy = (LandlordInterface) Proxy.newProxyInstance(
            landlord.getClass().getClassLoader(), 
            landlord.getClass().getInterfaces(), 
            invocationHandler);
      	// 执行签合同方法
        proxy.sign();
    }
}

? 如果房东只有一个签合同行为,动态代理和静态代理相比,虽然不用去写代理类了,但是需要编写一个InvocationHandler的实现类,这里并没有体现动态代理的动态性、便利性,但是,如果房东还将收水费、收电费、收房租也代理给中介,那么就能看到动态代理的便利性了。

/**
 * 房东接口
 */
public interface LandlordInterface {

    void sign();
    
    void waterCharge();
}

/**
 * 每月要1500元的一个真实房东
 */
public class Landlord implements LandlordInterface{

    @Override
    public void sign() {
        System.out.println("和租客签合同,1500元每月...");
    }
  
  	@Override
    public void waterCharge() {
        System.out.println("收水费,每月10元...");
    }
}

? 这里,又给房东添加了一个收水费的行为,此时中介想要代理收水费行为并从中牟利,不需要修改任何代码,直接在测试类中使用即可。

/**
 * 模拟租房过程的一个测试类
 */
public class Test {
    public static void main(String[] args) {

        Landlord landlord = new Landlord();
        MyInvocationHandler invocationHandler = new MyInvocationHandler(landlord);
      	// 动态生成一个代理对象
        LandlordInterface proxy = (LandlordInterface) Proxy.newProxyInstance(
            landlord.getClass().getClassLoader(), 
            landlord.getClass().getInterfaces(), 
            invocationHandler);
      	// 执行签合同方法
        proxy.sign();
      	// 执行收水费方法
        proxy.waterCharge();
    }
}

? 如果使用静态代理的方式,还需要在中介类中添加对应的waterCharge()方法。

2.Cglib动态代理

? 通过上面JDK动态代理的实例可以看到,JDK动态代理依赖于被代理类对象(房东)需要实现一个接口(房东接口),如果被代理对象没有实现接口,那么就无法使用JDK动态代理了,这也是JDK动态代理和Cglib动态代理的区别之处。Cglib(Code Generation Library)是一个开源项目,是一个强大的,高性能,高质量的Code生成类库,它可以动态地扩展Java类。Cglib动态代理示例:

<!-- 使用cglib动态代理需要引入cglib依赖或者加入cglib相关jar包 -->
<dependency>
  <groupId>cglib</groupId>
  <artifactId>cglib</artifactId>
  <version>2.2</version>
</dependency>
/**
 * 每月要1500元的一个真实房东 需要注意:本类没有实现接口
 */
public class Landlord {

    public void sign() {
        System.out.println("和租客签合同,1500元每月...");
    }
}

/**
 * 使用Cglib动态代理,需要编写一个类实现MethodInterceptor接口
 */
public class MyMethodInterceptor implements MethodInterceptor {

    private Enhancer enhancer = new Enhancer();

  	/**
  	 * clazz是被代理对象的类类型
  	 */
    public Object getProxy(Class<?> clazz){
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        return enhancer.create();
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable 		{
      	// 中介每次在执行房东的任务前,都会加收租客费用
        System.out.println("加价收取租客费用...");
      	// 执行房东的任务(即执行房东对象对应的方法)
        Object result = methodProxy.invokeSuper(obj, args);
        return result;
    }
}

/**
 * 模拟租房过程的一个测试类
 */
public class Test {
    public static void main(String[] args) {
      	MyMethodInterceptor myMethodInterceptor = new MyMethodInterceptor();
      	// 动态生成一个代理对象
        Landlord proxy = (Landlord) myMethodInterceptor.getProxy(Landlord.class);
      	// 执行签合同方法
        proxy.sign();
    }
}

题外话

? 本文拿中介租房作为一个代理模式的例子举例,对于中介加价的行为可能冒犯了中介从事者,我在此表示歉意。中介和我一样都是打工人,也很不容易,我第一次租房就是通过中介,接触到不少中介,并没有觉得租房过程有什么不舒服的地方,反倒他们的热情会让我愧疚我的租金给少了。。。还望看到这里的同学不要对中介有敌意。

以上是关于Java中的代理模式的主要内容,如果未能解决你的问题,请参考以下文章

详解 Java 中的三种代理模式!

java中的动态代理

代理模式(动态)

详解 Java 中的三种代理模式

Java RMI地址解析问题

java中的动态代理