zoukankan      html  css  js  c++  java
  • 静态代理和动态代理

    一、代理模式

    定义:代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象。这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。这种类型的设计模式属于结构型模式。

    代理模式主要包含三个角色,即抽象主题角色(Subject)、委托类角色(被代理角色,Proxied)以及代理类角色(Proxy),如上图所示:

    抽象主题角色:可以是接口,也可以是抽象类;
    委托类角色:真实主题角色,业务逻辑的具体执行者;
    代理类角色:内部含有对真实对象RealSubject的引用,负责对真实主题角色的调用,并在真实主题角色处理前后做预处理和后处理。

    二、静态代理

    所谓静态代理是指,在程序运行前,由程序员创建或特定工具自动生成源代码并对其编译生成.class文件。静态代理的实现只需要三步:首先,定义业务接口;其次,实现业务接口;然后,定义代理类并实现业务接口;最后便可通过客户端进行调用。例如,

    1.创建接口

    1 package DesignPattern.staticproxy;
    2 
    3 public interface ITeacherDao {
    4     void teach();
    5 }
    View Code

    2.目标类实现接口

    package DesignPattern.staticproxy;
    
    public class TeacherDao implements ITeacherDao{
        @Override
        public void teach() {
            System.out.println("老师正在授课……");
        }
    }
    View Code

    3.代理类实现接口,对目标类添加扩展功能

     1 package DesignPattern.staticproxy;
     2 
     3 public class TeacherDaoProxy implements ITeacherDao {
     4     private ITeacherDao target;
     5 
     6     public TeacherDaoProxy(ITeacherDao target) {
     7         this.target = target;
     8     }
     9     @Override
    10     public void teach() {
    11         System.out.println("开始代理,完成某些操作……");
    12         target.teach();
    13         System.out.println("提交……");
    14     }
    15 }
    View Code

    4.客户端调用

     1 package DesignPattern.staticproxy;
     2 
     3 public class client {
     4     public static void main(String[] args) {
     5 //        创建目标对象(被代理对象)
     6         ITeacherDao teacherDao = new TeacherDao();
     7 //        TeacherDao teacherDao = new TeacherDao();
     8 //        创建代理对象,同时将被代理对象传递给代理对象
     9         TeacherDaoProxy teacherDaoProxy = new TeacherDaoProxy(teacherDao);
    10 //         通过代理对象调用被代理对象的方法
    11         teacherDaoProxy.teach();
    12     }
    13 }
    View Code

    静态代理优缺点

    优点:可以做到在符合开闭原则的情况下对目标对象进行功能扩展。

    开闭原则:开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。简单来说:就是为了使程序的扩展性好,易于维护和升级。

    缺点:

    1)代理类和委托类实现了相同的接口,代理类通过委托类实现了相同的方法。这样就出现了大量的代码重复。如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。

    2)代理对象只服务于一种类型的对象,如果要服务多类型的对象。势必要为每一种对象都进行代理,静态代理在程序规模稍大时就无法胜任了。如上的代码是只为UserManager类的访问提供了代理,但是如果还要为其他类如Department类提供代理的话,就需要我们再次添加代理Department的代理类。

    三、jdk动态代理

    如何解决静态代理的缺点呢? 这里就得说说动态代理了。

    在动态代理中我们不再需要再手动的创建代理类,我们只需要编写一个动态处理器就可以了。真正的代理对象由JDK再运行时为我们动态的来创建。(利用反射机制在运行时创建代理类。)

    1.创建接口

    1 package DesignPattern.Dynamicproxy;
    2 
    3 public interface ITeacherDao {
    4     void teach();
    5     void sayHello(String name);
    6 }
    View Code

    2.目标类实现接口

     1 package DesignPattern.Dynamicproxy;
     2 
     3 public class TeacherDao implements ITeacherDao{
     4     @Override
     5     public void teach() {
     6         System.out.println("老师授课中……");
     7     }
     8 
     9 
    10     @Override
    11     public void sayHello(String name) {
    12         System.out.println("hello!"+name);
    13     }
    14 }
    View Code

    3.动态代理

     1 package DesignPattern.Dynamicproxy;
     2 import java.lang.reflect.InvocationHandler;
     3 import java.lang.reflect.Method;
     4 import java.lang.reflect.Proxy;
     5 public class ProxyFactory {
     6     //维护一个目标对象,Object
     7     private Object target;
     8 //构造器,对target进行初始化
     9     public ProxyFactory(Object target) {
    10         this.target = target;
    11     }
    12 //给目标对象生成一个代理对象
    13     public Object getProxyInstance(){
    14         //说明
    15         /*
    16          *  public static Object newProxyInstance(ClassLoader loader,
    17                                           Class<?>[] interfaces,
    18                                           InvocationHandler h)
    19 
    20             //1. ClassLoader loader : 指定当前目标对象使用的类加载器, 获取加载器的方法固定
    21             //2. Class<?>[] interfaces: 目标对象实现的接口类型,使用泛型方法确认类型
    22             //3. InvocationHandler h : 事情处理,执行目标对象的方法时,会触发事情处理器方法, 会把当前执行的目标对象方法作为参数传入
    23          */
    24         return Proxy.newProxyInstance(target.getClass().getClassLoader(),
    25                 target.getClass().getInterfaces(),
    26                 new InvocationHandler() {
    27                     @Override
    28                     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    29                         System.out.println("JDK代理开始……");
    30                         //反射机制调用目标对象的方法
    31                         Object returnVal = method.invoke(target,args);
    32                         System.out.println("JDK代理提交……");
    33                         return returnVal;
    34                     }
    35                 });
    36     }
    37 }
    View Code

    4..客户端调用

     1 package DesignPattern.Dynamicproxy;
     2 
     3 public class client {
     4     public static void main(String[] args) {
     5         //创建目标对象
     6         ITeacherDao target = new TeacherDao();
     7         //给目标对象,创建代理对象,可以转成ITeacherDao
     8         ITeacherDao proxyInstance =(ITeacherDao)new ProxyFactory(target).getProxyInstance();
     9         // proxyInstance=class com.sun.proxy.$Proxy0 内存中动态生成了代理对象
    10         System.out.println("proxyInstance:"+proxyInstance.getClass());
    11         //通过代理对象调用目标对象的方法
    12         proxyInstance.teach();
    13         proxyInstance.sayHello("Tom");
    14     }
    15 }
    View Code

    优缺点:

    优点:

    相对于静态代理,动态代理大大减少了我们的开发任务,同时减少了对业务接口的依赖,降低了耦合度。

    缺点:

    代理对象不需要实现接口,但是目标对象一定要实现接口,否则不能用JDK动态代理。

  • 相关阅读:
    MySQL命令2
    MySQL命令1
    前端之HTML1
    linux命令之df dh
    python call java jar
    redis-py中的坑
    YARN应用程序的开发步骤
    Yarn的服务库和事件库使用方法
    SSH无密码验证
    在centos 6.5 在virtual box 上 安装增强版工具
  • 原文地址:https://www.cnblogs.com/jingpeng77/p/12973211.html
Copyright © 2011-2022 走看看