WHWW之代理模式(2)-动态代理

What:什么叫动态代理?

代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的,或者说一个代理类是在程序运行时才获取到目标对象的代理。动态代理又称jdk代理。

How:怎么实现动态代理?

WHWW之代理模式(2)-动态代理

/**
 * 抽象角色接口
 */
public interface Hello {

    /**
     * 打招呼
     */
  void sayHello();
}

/**
 * 目标对象角色类
 */
public class RealHello implements Hello {
    /**
     * 实现接口的方法
     */
    @Override
    public void sayHello() {
        System.out.println("你好");
    }
}

/**
 * 动态代理类
 */
public class DynamicProxy implements InvocationHandler {

    //目标对象
    private Object target;

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

    /**
     * 代理实现方法
     * @param proxy
     * @param method
     * @param args
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        Object result=method.invoke(target,args);
        after();
        return result;
    }

    /**
     * 在实现方法前可以做的事情
     */
    public  void  before(){
        System.out.println("摘下耳机");
    }

    /**
     * 在实现方法后做的事情
     */
    public void after(){
        System.out.println("戴上耳机");
    }


}
/**
 * 动态代理测试
 */

public class DynamicProxyTest {

    public static void main(String[] args) {
        Hello hello=new RealHello();
        hello.sayHello();
        System.out.println("=====================");
        System.out.println("动态代理:");
        DynamicProxy dynamicProxy=new DynamicProxy(hello);
//        通过反射加载hello,获取hello接口的方法,生成动态代理
        Hello helloProxy= (Hello) Proxy.newProxyInstance(hello.getClass().getClassLoader(),hello.getClass().getInterfaces(),dynamicProxy);
        helloProxy.sayHello();
    }
}

控制台输出:

你好
=====================
动态代理:
摘下耳机
你好
戴上耳机

Why:为什么要使用动态代理?

虽然静态代理可以实现我们某些需求,但其缺点也是让我们不想用它的原因,可以看《WHWW之代理模式(1)-静态代理》。因为程序员是追求高效的,动态代理是利用Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java反射机制可以生成任意类型的动态代理类。

Where:哪些地方有用到动态代理呢?

动态代理让我们在不直接访问某些对象的情况下,通过代理机制也可以访问被代理对象的方法,所以可以应用在很多地方。比如RPC框架,Spring AOP机制。

注:虽然代理对象(DynamicProxy)不需要实现接口,但是目标对象(RealHello)一定要实现接口(Hello),否则就不能用动态代理。