动态代理

一种设计模式,为其他对象提供一种代理以控制对这个对象的访问。

package com.ddyblackhat.javase.proxy;

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

interface Subject {// 抽象类
    public void doSomething();
}

interface Say {
    public void saySomething();
}

class RealSubject implements Subject, Say {// 实现类

    @Override
    public void doSomething() {
        System.out.println("call doSomething()");
    }

    @Override
    public void saySomething() {
        // TODO Auto-generated method stub
        System.out.println("say something");
    }

}

// class SubjectProxy implements Subject{// 静态代理
//
// Subject subimpl = new RealSubject();
// @Override
// public void doSomething() {
// subimpl.doSomething();
// }
// @Override
// public void saySomething() {
// // TODO Auto-generated method stub
//
// }
//
// }

class ProxyHandler { // 动态代理
    private Object tar; // 要代理的对象

    public ProxyHandler(Object tar) {
        this.tar = tar;
    }

    public Object getProxy() {
        if (tar == null)
            throw new RuntimeException("tar is null");

        // 1. 准备目标对象的类加载器
        // ①获取目标对象的Class类对象
        Class<? extends Object> tarClass = this.tar.getClass();
        // ②获取类加载器对象
        ClassLoader loader = tarClass.getClassLoader();

        // 2. 准备目标对象所实现的接口类型的数组
        Class<?>[] interfaces = tarClass.getInterfaces();

        // 3. 准备InvocationHandler对象
         InvocationHandler h = new InvocationHandler() {

            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                // TODO Auto-generated method stub
                String className = tar.getClass().getName();
                String methodName = method.getName();
                Object result = null;
                try {
                    System.out.println("[日志][" + className + "]" + methodName + "开始...");
                    result = method.invoke(tar, args);
                    System.out.println("[日志][" + className + "]" + methodName + "正常结束...");
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    System.out.println("[日志][" + className + "]" + methodName + "异常结束...");
                    e.printStackTrace();
                } finally {
                    System.out.println("[日志][" + className + "]" + methodName + "最终结束...");
                }

                return result;
            }
        };

        Object o = Proxy.newProxyInstance(loader, interfaces, h);
        return o;
    }

}

public class ProxyTest {

    public static void main(String[] args) {
        // Subject sub = new SubjectProxy();
        // sub.doSomething();

        ProxyHandler proxy = new ProxyHandler(new RealSubject());
        Subject rs = (Subject) proxy.getProxy();
        Say say = (Say) proxy.getProxy();

        rs.doSomething();
        say.saySomething();
    }
}

输出:

[日志][com.ddyblackhat.javase.proxy.RealSubject]doSomething开始...
call doSomething()
[日志][com.ddyblackhat.javase.proxy.RealSubject]doSomething正常结束...
[日志][com.ddyblackhat.javase.proxy.RealSubject]doSomething最终结束...
[日志][com.ddyblackhat.javase.proxy.RealSubject]saySomething开始...
say something
[日志][com.ddyblackhat.javase.proxy.RealSubject]saySomething正常结束...
[日志][com.ddyblackhat.javase.proxy.RealSubject]saySomething最终结束...

使用java自带的动态代理实现,

  • 实现InvocationHandler 接口创建自己的调用处理器。
  • 通过Proxy.newProxyInstance创建代理类。需要传入3个参数。
    • classloader
    • interfaces
    • invocationHandler 对象。

代理角色

  • 抽象角色:声明真实对象和代理对象的共同接口,这样一来在任何使用目标对象的地方都可以使用代理对象。
  • 代理角色:代理对象内部含有目标对象的引用,从而可以在任何时候操作对象;代理对象提供一个与目标对象相同的接口,以便可以在任何时候替代目标对象。代理对象通常在客户端调动传递给目标对象之前或之后,执行某个操作,而不是单纯地将调用传递给目标对象,同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象的封装。
  • 真实角色:著作权归作者所有。定义了代理对象所代表的目标对象,代理角色所代表的真实对象,是我们最终要引用的对象,定义了代理对象所代表的目标对象。

    动态代理的作用

  • Proxy类的代码量被固定下来,不会因为业务的逐渐庞大而庞大
  • 可以实现AOP编程,实际上静态代理也可以实现,AOP可以算作是代理模式的一个典型应用
  • 解耦,通过参数就可以判断真实类,不需要事先实例化,更加灵活多变。

拓展

  1. 可以使用Properties属性文件配置要代理的类。
  2. 目标方法的前后动态的插入方法,而不是单一功能。(这个可以怎么实现?)