您的位置:首页 > 编程语言 > Java开发

静态代理与动态代理

2018-03-14 13:24 148 查看
*需要知道关于反射的相关知识
*读黄勇先生的《架构探险——从零开始写Java Web框架》的感想笔记
*第一次写博客,如有错误,欢迎指正,大家互相交流学习。
-----------------------------------------------------------------------------------------------------
一、引言
    代理模式(Proxy Pattern)是通过一个代理类来代理业务类完成业务类不需要实现的非业务逻辑代码。这样的编程模式具有良好的扩展性,代理类和业务类分工明确,业务类不需要实现非它职责的事务,代理类不仅能够在客户端和目标对象中起到中介作用,还能很好的保护业务类。这个过程有点类似于经纪人和明星,明星只需负责完成演出活动,而经纪人则需要签约广告,拉赞助。

二、静态代理和动态代理
    以明星(Star)和经纪人(Agent)为例,简单的描述如何实现代理模式。

    1.静态代理
        关于明星与经纪人的UML图如下:
    


            新建一个People接口:public interface People {
public void work();
}
           Agent实现类:
public class Agent implements People {
private People people;
public Agent(){
this.people=new Star();
}
@Override
public void work() {
//代理类所需要完成的非业务逻辑
System.out.println("签约商演……");
people.work();
//代理类所需要完成的非业务逻辑
System.out.println("获取商演报酬。");
}
}
        Star实现类:
public class Star implements People {

@Override
public void work() {
//业务类所需要的业务代码逻辑
System.out.println("……完成演出活动……");
}
}
          用一个main方法来测试一下:public static void main(String[] args) {
//测试类:用于测试静态代理模式
Agent agent=new Agent();
agent.work();
}        运行后打印结果如下:
签约商演……
……完成演出活动……
获取商演报酬。
         通过上述类,实现了简单的代理模式。理解代理模式,关键还是在于代理二字。Agent类内部维护了一个私有的成员people,通过面向对象的多态性,我们可以访问到实现了People接口的Star类中的Work方法。那么问题来了,如果这个明星所在的娱乐公司的董事长需要一个秘书,总经理又需要一个助手……总而言之,有很多不同的类需要代理,那么是否需要一一的为这些类编写代理类。如果真的这么做了,一旦你遇到规模较大的项目,你可能会陷入一大堆代理类带来的麻烦。甚至后期维护,也会让你束手缚脚的。
       2.动态代理
      动态代理能在运行时动态地生成代理类,能够很好的解决上面的问题。Java提供了类Proxy和接口InvocationHandler来实现动态代理。通过实现接口InvocationHandler的类来包装业务类的实例,然后通过JDK提供的Proxy类的静态方法newProxyInstance()来生成对应的代理类实例,最后再调用代理类的方法。
        关于明星与经纪人的动态代理UML图如下:

   


        利用原先在静态代理中使用的接口People和其实现类Star,再新创建一个实现InvocationHandler接口的类DynamicProxy,代码如下:
public class DynamicProxy implements InvocationHandler {
private Object target;//存放业务对象
public DynamicProxy(Object target){
this.target=target;
}
@Override
public Object invoke(Object proxy,
Method method, Object[] args) throws Throwable {
//proxy是代理类的实例,method是需执行的方法,args是方法所需参数
//代理类所需要完成的非业务代码逻辑
Before();
Object result=method.invoke(target, args);
//代理类所需要完成的非业务代码逻辑
After();
return result;
}
public void Before(){
System.out.println("签约商演……");
}
public void After(){
System.out.println("……获取商演报酬");
}
//newProxyInstance的输出参数是Object类型,向下转型成T会发生编译警告
@SuppressWarnings("unchecked")//该注解会忽略编译警告
public <T>T getProxy(){
/*getProxy封装了newProxyInstance方法,
* 有利于在测试类中反复调用,提高代码复用性。
*/
return  (T) Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
this);
}

}

         编写测试类:
public static void main(String[] args) {
//测试类:测试动态代理的实现
People star=new Star();
DynamicProxy dynamicProxy=new DynamicProxy(star);
People starProxy=dynamicProxy.getProxy();
starProxy.work();
/*代理类的相关信息*/
System.out.println("---------代理类的相关信息-----------");
Class<?> cls=starProxy.getClass();
System.out.println("代理类的全限定名:"+cls);
System.out.println("代理类的成员方法:");
Method[] methods= cls.getDeclaredMethods();
for(Method method:methods){
System.out.println(method);
}
System.out.println("代理类的父类:"+cls.getSuperclass());
Class<?>[] interfaces=cls.getInterfaces();
for(Class<?> itce:interfaces){
System.out.println("代理类实现接口:"+itce);
}
}
         运行结果如下:签约商演……
……完成演出活动……
……获取商演报酬
---------代理类的相关信息-----------
代理类的全限定名:class com.sun.proxy.$Proxy0
代理类的成员方法:
public final boolean com.sun.proxy.$Proxy0.equals(java.lang.Object)
public final java.lang.String com.sun.proxy.$Proxy0.toString()
public final int com.sun.proxy.$Proxy0.hashCode()
public final void com.sun.proxy.$Proxy0.work()
代理类的父类:class java.lang.reflect.Proxy
代理类实现接口:interface com.staticproxy.People         从运行的结果来看,代理类的类名为$Proxy0,父类是Proxy,实现了People接口。动态代理能够根据你所传的参数在运行时动态的生成了相应的代理类,大大提高了代码复用性。
三、结论
        1.代理模式能够保证业务类的安全性,业务类只需关注其业务逻辑。
        2.静态代理和动态代理最大的区别就是在于代理类生成时机不同。静态代理编译时已经确定,并拥有对应的字节码文件。而动态代理则根据Java的反射机制在运行时动态的生成代理类,没有相应的字节码文件。

        3.实现动态代理需要InvocationHandler接口和Proxy类。

        4.动态代理实现了业务代码和非业务代码的解耦,提高代码复用性,实现了程序的高内聚,低耦合。

        5.动态代理需要业务类实现接口。

        6.在实际应用中,动态代理能够在不改变原代码的基础上,为其添加验权、日志打印等功能。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Java Dynamic Proxy