zoukankan      html  css  js  c++  java
  • 设计模式:代理模式

    代理的概念:简单的理解就是通过某一个对象创建一个代理对象,不直接引用原本的对象,而是由创建的代理对象来控制对原对象的引用。即为原本的对象提供一种代理,以控制对这个对象的访问。

    代理对象在客服端和目标对象之间起到中介作用,使用代理模式主要有两个目的:一保护目标对象,二增强目标对象。

    静态代理:显式声明被代理对象

    由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。

     

     

     

    在分布式业务场景中,我们通常会对数据库进行分库分表,分库分表之后使用 Java 操作时,就可能需要配置多个数据源,我们通过设置数据源路由来动态切换数据源。(静态代理)

    动态代理:动态配置和替换被代理对象

    在程序运行时,运用反射机制动态创建而成,无需手动编写代码。动态代理不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java反射机制可以生成任意类型的动态代理类。

    接口类

    委托类

    代理类

    代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。利用了java的反射机制。

    测试类:编制与调用  

    JDK动态代理

    a. 面向接口的,必须提供一个委托类和代理类都要实现的接口,只有接口中的方法才能够被代理。 

    b. JDK动态代理的实现主要使用java.lang.reflect包里的Proxy类和InvocationHandler接口。 

    InvocationHandler接口:invoke()

    每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到

    了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由 InvocationHandler这个接口的 invoke 方法来进行调用。同时在invoke的方法里 我们可以对被代理 对象的方法调用做增强处理(如添加事务、日志、权限验证等操作)。

     public interface InvocationHandler {

         //Object proxy:指被代理的对象。

         //Method method:要调用的方法。(指代的是我们所要调用代理对象的某个方法的Method对象)

         //Object[] args:方法调用时所需要的参数。(指代的是调用真实对象某个方法时接受的参数)

    public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;

          before();//增强

          method.invoke(this.target,args);

          after();//增强

    }

    Proxy类: newProxyInstance()

    Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类

    ClassLoader loader:类加载器

    Class<?>[] interfaces:得到全部的接口

    InvocationHandler h:得到InvocationHandler接口的子类实例

    public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException 

    写法:Jdk动态代理实现了被代理对象的接口,代理类没有同时实现接口重写其中的findlove方法,利用反射可以动态实现多个方法(接口中的方法才能被代理),代理类需要实现InvocationHandler接口invoke()方法和调用Proxy类的 newProxyInstance()方法(反射)。 JDKMepo类背下。

    ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    高仿真 JDK Proxy 手写实现

    JDK Proxy 采用字节重组,重新生的对象来替代原始的对象以达到动态代理 的目的。JDK Proxy 生成对象的步骤如下: 字节码重组

    1、拿到被代理对象的引用,并且获取到它的所有的接口,反射获取。

    2、JDK Proxy 类重新生成一个新的类、同时新的类要实现被代理类所有实现的所有的接口。

    3、动态生成 Java 代码,把新加的业务逻辑方法由一定的逻辑代码去调用(在代码中体现)。

    4、编译新生成的 Java 代码.class。

    5、再重新加载到 JVM 中运行

     

     

    ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 

    CGLib 和 JDK 动态代理对比

    1.JDK 动态代理是实现了被代理对象的接口,CGLib 是继承了被代理对象。 

    2.JDK 和 CGLib 都是在运行期生成字节码,JDK 是直接写 Class 字节码,CGLib 使用 ASM框架写 Class 字节码,Cglib 代理实现更复杂,生成代理类比 JDK 效率低

    3.JDK 调用代理方法,是通过反射机制调用,CGLib 是通过 FastClass 机制直接调用方法,CGLib 执行效率更高。

    代理模式与 Spring

    代理模式在 Spring 源码中的应用先看 ProxyFactoryBean 核心的方法就是 getObject()方法,我们来看一下源码:

    getObject()方法中,主要调用 getSingletonInstance()和 newPrototypeInstance(); Spring 的配置中,如果不做任何设置,那么 Spring 代理生成的 Bean 都是单例对象。如果修改 scope 则每次创建一个新的原型对象。Spring 利用动态代理实现 AOP 有两个非常重要的类,一个是 JdkDynamicAopProxy 类 和 CglibAopProxy 类,来看一下类图:

    Spring 中的代理选择原则

    1、当 Bean 有实现接口时,Spring 就会用 JDK 的动态代理

    2、当 Bean 没有实现接口时,Spring 选择 CGLib。

    3、Spring 可以通过配置强制使用 CGLib,只需在 Spring 的配置文件中加入如下代码:  <aop:aspectj-autoproxy proxy-target-class="true"/>

    静态代理和动态的本质区别

    1、静态代理只能通过手动完成代理操作,如果被代理类增加新的方法,代理类需要同步新增,违背开闭原则。

    2、动态代理采用在运行时动态生成代码的方式,取消了对被代理类的扩展限制,遵循开闭原则。

    3、若动态代理要对目标类的增强逻辑扩展,结合策略模式,只需要新增策略类便可完成,无需修改代理类的代码。

    代理模式的优缺点

    使用代理模式具有以下几个优点:

    1、代理模式能将代理对象与真实被调用的目标对象分离。

    2、一定程度上降低了系统的耦合度,扩展性好。

    3、可以起到保护目标对象的作用。

    4、可以对目标对象的功能增强。 

    当然,代理模式也是有缺点的:

    1、代理模式会造成系统设计中类的数量增加。

    2、在客户端和目标对象增加一个代理对象,会造成请求处理速度变慢。

    3、增加了系统的复杂度。

  • 相关阅读:
    多表联合查询,利用 concat 模糊搜索
    order by 中利用 case when 排序
    Quartz.NET 3.0.7 + MySql 动态调度作业+动态切换版本+多作业引用同一程序集不同版本+持久化+集群(一)
    ASP.NET Core 2.2 基础知识(十八) 托管和部署 概述
    ASP.NET Core 2.2 基础知识(十七) SignalR 一个极其简陋的聊天室
    ASP.NET Core 2.2 基础知识(十六) SignalR 概述
    ASP.NET Core 2.2 基础知识(十五) Swagger
    ASP.NET Core 2.2 基础知识(十四) WebAPI Action返回类型(未完待续)
    linux磁盘管理 磁盘查看操作
    linux磁盘管理 文件挂载
  • 原文地址:https://www.cnblogs.com/LPJ-BLOG/p/12442931.html
Copyright © 2011-2022 走看看