首页 > 编程语言 >java几种代理模式的实现方式

java几种代理模式的实现方式

时间:2024-04-01 16:11:52浏览次数:19  
标签:System insert java 对象 代理 几种 println public

1. 代理模式

代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。简单的说就是,我们在访问实际对象时,是通过代理对象来访问的,代理模式就是在访问实际对象时引入一定程度的间接性,因为这种间接性,可以附加多种用途。

2. 静态代理

简单来说代理模式就是将被代理类包装起来然后重新实现相同的方法,并且调用原来方法的同时可以在方法前后添加一个新的处理。而这种包装可以使用继承或者组合来使用。当我们调用的时候需要使用的是代理类的对象来调用而不是原来的被代理对象。

静态代理有两种实现方式:

1、基于继承的方式实现

2、基于接口方式实现

基于继承实现静态代理

通过继承被代理对象,重写被代理方法,可以对其进行代理。
优点:被代理类无需实现接口
缺点:只能代理这个类,要想代理其他类,要想代理其他类需要写新的代理方法。
cglib动态代理就是采用这种方式对类进行代理。不过类是由cglib帮我们在内存中动态生成的。

/**
 * 被代理对象
 */
class UserDao{
    public int insert(){
        System.out.println("执行insert......");
        return 1;
    }
}

/**
 * 代理对象
 */
class UserDaoProxy extends UserDao{

    @Override
    public int insert() {
        System.out.println("代理执行方法前......");
        int result = super.insert();
        System.out.println("代理执行方法后......");
        return result;
    }
}

public class StaticProxyWithExtendsDemo {
    public static void main(String[] args) {
        UserDao userDao = new UserDaoProxy();
        userDao.insert();
    }
}

基于接口方式实现

  • 被代理类与代理类一定要实现同一接口。
  • 代理类需要将该接口作为属性,实例化时需要传入该接口的对象。
  • 优点:可以代理所有实现接口的类。
  • 缺点:被代理的类必须实现接口。
  • JDK动态代理就是采用的这种方式实现的。同样的代理类是由JDK自动帮我们在内存生成的。
interface IUserDao{
    void insert();
}

/**
 * 被代理对象
 */
class UserDaoImpl implements IUserDao{
    @Override
    public void insert() {
        System.out.println("这里执行了insert方法......");
    }
}

/**
 * 代理对象
 */
class UserDaoImplProxy implements IUserDao{
    private IUserDao userDao;
    public UserDaoImplProxy(IUserDao userDao){
        this.userDao = userDao;
    }

    @Override
    public void insert() {
        System.out.println("代理执行方法前.....");
        userDao.insert();
        System.out.println("代理执行方法后.....");
    }
}

public class StaticProxyWithInterfaceDemo {
    public static void main(String[] args) {
        //需要被代理的对象
        IUserDao userDao = new UserDaoImpl();
        //获取代理对象
        IUserDao userDaoProxy = new UserDaoImplProxy(userDao);
        //代理对象执行方法
        userDaoProxy.insert();
    }
}

3.动态代理

动态代理其实本质还是 将被代理类包装一层,生成一个具有新的相同功能的代理类。

但是与静态代理不同的是,这个代理类我们自己定义的。而动态代理这个代理类是根据我们的提示动态生成的。

相比于静态代理,动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类中的方法。

实现动态代理有几种方案

  • JDK动态代理
  • CGLIB动态代理

3.1 JDK动态代理

通过java提供的Proxy类帮我们创建代理对象。
优点:可以生成所有实现接口的代理对象
缺点:JDK反射生成代理必须面向接口, 这是由Proxy的内部实现决定的。生成代理的方法中必须指定实现类的接口,它根据这个接口来实现代理类生成的所实现的接口。

interface IStudentDao{
    void insert();
}

//被代理对象
class StudentDaoImpl implements IStudentDao{
    @Override
    public void insert() {
        System.out.println("执行了insert方法......");
    }
}

class ProxyInvoke implements InvocationHandler{
    //需要被代理的对象
    Object target;
    public ProxyInvoke(Object target){
        this.target = target;
    }
    /**
     * nvoke方法的三个参数
     *     Object proxy:这个就是代理对象
     *     Method method:执行的方法的反射对象
     *     Object[] args:执行方法的参数
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("代理执行方法前......");
        method.invoke(target,args);
        System.out.println("代理执行方法后......");
        return null;
    }
}
public class DynamicProxyWithJDKDemo {
    public static void main(String[] args) {
        //需要被代理的对象
        IStudentDao studentDao = new StudentDaoImpl();
        //通过JDC的Proxy.newProxyInstance进行生成代理对象
        // 参数一: 被代理类对象
        // 参数二:接口类对象  被代理对象所实现的接口
        // 参数三:调用处理器。 被调用对象的那个方法被调用后该如何处理
        IStudentDao studentDaoProxy = (IStudentDao) Proxy.newProxyInstance(studentDao.getClass().getClassLoader(),studentDao.getClass().getInterfaces(),new ProxyInvoke(studentDao));
        studentDaoProxy.insert();
    }
}

如果业务逻辑不复杂,也可以进行简写:

public class DynamicProxyWithJDKDemo {
    public static void main(String[] args) {
        //需要被代理的对象
        IStudentDao studentDao = new StudentDaoImpl();
        IStudentDao studentDaoProxy = (IStudentDao)Proxy.newProxyInstance(studentDao.getClass().getClassLoader(), studentDao.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("代理执行方法前......");
                Object invoke = method.invoke(studentDao, args);
                System.out.println("代理执行方法后......");
                return invoke;
            }
        });
        studentDaoProxy.insert();
    }
}

interface IStudentDao{
    void insert();
}

class StudentDaoImpl implements IStudentDao{
    @Override
    public void insert() {
        System.out.println("执行了insert方法......");
    }
}

3.2 CGLib动态代理

CGLib(Code Generate Library) 与JDK动态代理不同的是,cglib生成代理是被代理对象的子类。因此它拥有继承方法实现静态代理的优点:不需要被代理对象实现某个接口。
缺点:不能给final类生成代理,因为final类无法拥有子类。

使用cglib生成代理类也很简单,只要指定父类和回调方法即可
首先需要引入依赖

<dependency>
     <groupId>cglib</groupId>
     <artifactId>cglib</artifactId>
     <version>3.2.12</version>
 </dependency>
public class DynamicProxyWithCgLibDemo {
    public static void main(String[] args) {
        TeacherDao teacherDao = new TeacherDao();
        TeacherDao teacherProxy = (TeacherDao) Enhancer.create(teacherDao.getClass(), new MethodInterceptor() {
            @Override
            public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
                System.out.println("执行方法之前");
                proxy.invokeSuper(obj,args);
                System.out.println("执行方法之后");
                return null;
            }
        });
        teacherProxy.insert();
    }
}

class TeacherDao{
    public void insert(){
        System.out.println("执行了insert方法");
    }
}

标签:System,insert,java,对象,代理,几种,println,public
From: https://www.cnblogs.com/codeli/p/18108706

相关文章

  • JavaScript高级 —— 学习(四)(完结)
    目录一、深浅拷贝(一)浅拷贝1.浅拷贝的简单使用拷贝对象:拷贝数组:使用两种浅拷贝方法 2.浅拷贝的问题(二)深拷贝1.通过递归实现深拷贝递归函数:递归实现过程:其他问题:2.利用lodash实现深拷贝3.利用JSON实现深拷贝二、异常处理(一)抛出异常throw(二)捕获异常tryca......
  • JavaScript事件流
    JavaScript的事件流主要包括三个阶段:捕获阶段、目标阶段和冒泡阶段。当一个事件发生时,如点击一个按钮,这个事件会从最外层的祖先元素(通常是window对象)开始向下传递,这是捕获阶段。当事件到达触发事件的目标元素时,进入目标阶段。然后,事件会从目标元素开始,向上冒泡到最外层的祖先元......
  • 执行计划不走索引的几种情况总结
    优化器不想用索引,主要原因是优化器认为走索引还不如走顺序扫描代价低,因为索引扫描对应的是离散IO,我们可以通过调整random_page_cost告诉优化器随机IO代价值,非特殊情况不建议修改此值。1.表太小场景经常有开发问,为什么有索引而不走索引呢?因为优化器认为走索引方式太慢了!test=#c......
  • java大整数类
    importjava.util.ArrayList;publicclassBigIntimplementsComparable<BigInt>{privatestaticfinalcharMINUS_CHAR='-';privatestaticfinalcharPLUS_CHAR='+';//Savesthedigitsofthenumber-lastelemen......
  • 代码随想录算法训练营第二十五天(回溯2)|216. 组合总和 III、17. 电话号码的字母组合(JA
    文章目录216.组合总和III解题思路源码17.电话号码的字母组合解题思路源码216.组合总和III找出所有相加之和为n的k个数的组合,且满足下列条件:只使用数字1到9每个数字最多使用一次返回所有可能的有效组合的列表。该列表不能包含相同的组合两次,组合可......
  • 代码随想录算法训练营第二十七天(回溯3)|39. 组合总和、40. 组合总和 II、131. 分割回文
    文章目录39.组合总和解题思路源码40.组合总和II解题思路源码131.分割回文串解题思路源码39.组合总和给你一个无重复元素的整数数组candidates和一个目标整数target,找出candidates中可以使数字和为目标数target的所有不同组合,并以列表形式返回......
  • JimuReport 积木报表 v1.7.4 正式版本发布,免费的 JAVA 报表工具
    项目介绍一款免费的数据可视化报表,含报表和大屏设计,像搭建积木一样在线设计报表!功能涵盖,数据报表、打印设计、图表报表、大屏设计等!Web版报表设计器,类似于excel操作风格,通过拖拽完成报表设计。秉承“简单、易用、专业”的产品理念,极大的降低报表开发难度、缩短开......
  • Java 实现OCR扫描/识别图片文字
    图片内容一般无法编辑,如果想要读取图片中的文本,我们需要用到OCR工具。本文将介绍如何在Java中实现OCR识别读取图片中的文字。所需工具:IDEASpire.OCRforJava-JavaOCR组件,支持识别多种语言、字体,可读取JPG、PNG、GIF、BMP和TIFF等常用图片中的文本信息。    ......
  • Java 8 新特性:Lambda 表达式、方法引用和 Stream 流
    函数式接口具有单个抽象方法的接口被称为“函数式接口”,函数式接口的实例被称为“函数对象”,表示函数和要采取的动作。六大基础函数式接口:函数式接口名称用途方法Consumer<T>消费型接口操作类型T的对象voidaccept(Tt)Supplier<T>供给型接口返回类型为T......
  • Java:异常处理
    在Java中,异常是程序运行时发生的不正常情况,它们打断了正常的指令流。异常处理是Java语言的一个重要特性,它可以帮助程序员捕获并处理运行时可能出现的错误,从而提高程序的健壮性。以下是Java中异常相关的详细知识:异常类的层次结构Java的异常类都继承自java.lang.Throwable类......