专栏首页卯金刀GG【Java设计模式】之代理模式

【Java设计模式】之代理模式

代理模式是Java常见的设计模式之一。所谓代理模式是指客户端并不直接调用实际的对象,而是通过调用代理,来间接的调用实际的对象。 为什么要采用这种间接的形式来调用对象呢?一般是因为客户端不想直接访问实际的对象,或者访问实际的对象存在困难,因此通过一个代理对象来完成间接的访问。

代理模式的UML图

从UML图中,可以看出代理类与真正实现的类都是继承了抽象的主题类,这样的好处在于代理类可以与实际的类有相同的方法,可以保证客户端使用的透明性。

代理模式的实现

代理模式可以有两种实现的方式,一种是静态代理类,另一种是各大框架都喜欢的动态代理。下面我们主要讲解一下这两种代理模式

1、静态代理

我们先看针对上面UML实现的例子,再看静态代理的特点。 Subject接口的实现

public interface Subject {
    void visit();
}

实现了Subject接口的两个类:

public class RealSubject implements Subject {

    private String name = "byhieg";
    @Override
    public void visit() {
        System.out.println(name);
    }
}
public class ProxySubject implements Subject{

    private Subject subject;

    public ProxySubject(Subject subject) {
        this.subject = subject;
    }

    @Override
    public void visit() {
        subject.visit();
    }
}

具体的调用如下:

public class Client {

    public static void main(String[] args) {
        ProxySubject subject = new ProxySubject(new RealSubject());
        subject.visit();
    }
}

通过上面的代理代码,我们可以看出代理模式的特点,代理类接受一个Subject接口的对象,任何实现该接口的对象,都可以通过代理类进行代理,增加了通用性。但是也有缺点,每一个代理类都必须实现一遍委托类(也就是realsubject)的接口,如果接口增加方法,则代理类也必须跟着修改。其次,代理类每一个接口对象对应一个委托对象,如果委托对象非常多,则静态代理类就非常臃肿,难以胜任。

2、动态代理(JDK)

动态代理有别于静态代理,是根据代理的对象,动态创建代理类。这样,就可以避免静态代理中代理类接口过多的问题。动态代理是实现方式,是通过反射来实现的,借助Java自带的java.lang.reflect.Proxy,通过固定的规则生成。 其步骤如下:

  1. 编写一个委托类的接口,即静态代理的(Subject接口)
  2. 实现一个真正的委托类,即静态代理的(RealSubject类)
  3. 创建一个动态代理类,实现InvocationHandler接口,并重写该invoke方法
  4. 在测试类中,生成动态代理的对象。

第一二步骤,和静态代理一样,不过说了。第三步,代码如下:

public class DynamicProxy implements InvocationHandler {
    private Object object;
    public DynamicProxy(Object object) {
        this.object = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = method.invoke(object, args);
        return result;
    }
}

第四步,创建动态代理的对象

Subject realSubject = new RealSubject();
DynamicProxy proxy = new DynamicProxy(realSubject);
ClassLoader classLoader = realSubject.getClass().getClassLoader();
Subject subject = (Subject) Proxy.newProxyInstance(classLoader, new  Class[]{Subject.class}, proxy);
subject.visit();

创建动态代理的对象,需要借助Proxy.newProxyInstance。该方法的三个参数分别是:

  • ClassLoader loader表示当前使用到的appClassloader。
  • Class<?>[] interfaces表示目标对象实现的一组接口。
  • InvocationHandler h表示当前的InvocationHandler实现实例对象。

JDK代理模式

public class ProxyFactory {  
      
    private Object obj;  
      
      
    public ProxyFactory(Object obj) {  
        super();  
        this.obj = obj;  
    }  
  
    public Object getTransactionProxyInstance(){  
          
        Object proxy = Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), new InvocationHandler() {  
            /** 
             * 三个参数:1、代理对象,2、目标对象的方法,3、目标对象的参数值列表 
             */  
            @Override  
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
                System.out.println("开启事务..."); //执行核心业务之前执行的内容  
                method.invoke(obj, args);      //执行目标对象方法,即核心业务  
                System.out.println("关闭事务..."); //执行核心业务之后执行的内容  
                return proxy;  
            }  
        });  
          
        return proxy;  
    }  
    
} 

3、动态代理(CGLIB)

JDK动态代理机制只能代理实现接口的类,一般没有实现接口的类不能进行代理。cglib就是针对类来实现代理的,它的原理是对指定目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。

使用cglib实现动态代理,完全不受代理类必须实现接口的限制,而且cglib底层采用ASM字节码生成框架,使用字节码技术生成代理类,比使用java反射效率要高。

需要引入两个jar包:cglib.jar,asm.jar

定义了一个拦截器,在调用目标方法之前,cglib回调MethodInterceptor接口方法拦截,来实现自己的业务逻辑,类似

于JDK中的InvocationHandler接口。

@Override  
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable ;

proxy:为cglib动态生成的代理实例

method:为上文中实体类所调用的被代理的方法调用

args:为method参数数值列表

methodProxy:为生成代理类对方法的代理引用

返回:从代理实例方法调用返回的值

其中,methodProxy.invokeSuper(obj,arg):

调用代理类实例上的proxy方法的父类方法

UserDaoImpl.java

public class CglibProxyFactory {  
      
    private Object obj;  
  
    public CglibProxyFactory(Object obj) {  
        super();  
        this.obj = obj;  
    }  
      
    public Object getProxyFactory(){  
        //Enhancer类是cglib中的一个字节码增强器,它可以方便的为你所要处理的类进行扩展  
        Enhancer enhancer = new Enhancer();  
        enhancer.setSuperclass(obj.getClass());//将目标对象所在的类作为Enhaner类的父类  
        enhancer.setCallback(new MethodInterceptor() {  
            //通过实现MethodInterceptor实现方法回调  
            @Override  
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {  
                System.out.println("事务开启...");  
                method.invoke(obj, args);  
                System.out.println("事务结束...");  
                  
                return proxy;  
            }  
        });  
          
        return enhancer.create();//生成目标对象并返回  
    }  
}  

测试类

public class TestCglibProxy {  
      
    @Test  
    public void test1(){  
        UserDaoImpl userDao = new UserDaoImpl();  
        UserDaoImpl userDaoProxy = (UserDaoImpl) new CglibProxyFactory(userDao).getProxyFactory();  
        userDaoProxy.save();  
        System.out.println("目标对象类型:"+userDao.getClass());  
        System.out.println("代理对象类型:"+userDaoProxy.getClass());  
    }  
      
      
}  

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Java开发中的23种设计模式详解

    结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

    用户5640963
  • springboot中rabbitmq的配置和使用【进阶一】

    用户5640963
  • 【算法-希尔排序】

    对关键字{10,20,8,25,35,6,18,30,5,15,28}序列进行希尔排序,取增量d =5时,排序结果为( )

    用户5640963
  • 代理模式三问—百度真题

    工欲善其事,必先利其器。项目开发过程中设计模式可以说就是这个利器,无论哪种语言,哪种项目架构,都离不开各种设计模式,今天就一起来看看代理模式:

    码上积木
  • 代理模式

    概述 代理模式,即ProxyPattern,java常用设计模式之一,动态代理实现了著名的AOP思想。代理模式的思想是为了提供额外的处理或者不同的操作而在实际对...

    高爽
  • 设计模式之代理模式(结构型)

    代理模式:代理模式就是引入一个代理对象,通过代理对象实现对原对象的引用。代理模式是一种对象结构型。

    SmileNicky
  • 静态代理和动态代理简介

    在某些情况下,一个客户不想或者不能直接引用一个对象,此时可以通过一个称之为“代理”的第三者来实现间接引用。代理对象可以在客户端和目标对象之间起到中介的作用,并且...

    SmileNicky
  • 动手实现MVC: 3. AOP实现准备篇动态代理

    背景 在实现AOP功能时,必然扰不开代理模式,所以在此之前,先准备下代理模式相关知识点 代理 关于代理,主要需要注意以下几个点 什么是代理模式 为什么要用代理 ...

    一灰灰blog
  • 【Java入门提高篇】Day11 Java代理——JDK动态代理

      今天来看看Java的另一种代理方式——JDK动态代理   我们之前所介绍的代理方式叫静态代理,也就是静态的生成代理对象,而动态代理则是在运行时创建代理对象。...

    弗兰克的猫
  • Java 静态代理、Java动态代理、CGLIB动态代理

    Java 的代理就是客户类不再直接和委托类打交道, 而是通过一个中间层来访问, 这个中间层就是代理。为啥要这样呢, 是因为使用代理有 2 个优势:

    java思维导图

扫码关注云+社区

领取腾讯云代金券