带你深入了解java-代理机制

带你深入了解 Java 代理机制

代理机制是 Java 语言的一个重要特性,它允许我们在运行时生成一个替代某个对象的对象,从而能够控制访问、修改被代理对象的属性或方法。在本文中,我们将深入讲解 Java 的代理机制,包括代理类型、创建方式、使用场景等。

代理类型

Java 语言中有两种代理类型:静态代理和动态代理。

静态代理

静态代理是指在编译时确定代理类和被代理类的关系,代理类和被代理类实现共同的接口,代理类中调用被代理类中的方法。在使用静态代理时,需要手动编写代理类,这种方式比较麻烦且容易出现重复代码。

动态代理

动态代理是指在运行时根据需要动态生成代理类,不需要手动编写代理类。Java 中动态代理主要使用了两个类:InvocationHandlerProxy。其中,InvocationHandler是一个接口,它只有一个invoke方法,在代理对象调用方法时,会先调用invoke方法,再执行相应的方法。Proxy类是动态代理的核心类,可以通过它的静态方法newProxyInstance创建一个动态代理对象。

创建动态代理

创建动态代理的步骤主要包括以下几个步骤:

  1. 实现InvocationHandler接口,重写invoke方法;
  2. 创建被代理类的实例对象和InvocationHandler对象;
  3. 使用Proxy类的newProxyInstance方法创建代理类;
  4. 通过代理类调用被代理类的方法。

以下是一个示例代码:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

interface Hello {
    void sayHello();
}

class HelloImpl implements Hello {
    @Override
    public void sayHello() {
        System.out.println("Hello World!");
    }
}

class MyInvocationHandler implements InvocationHandler {
    private Object target;

    public MyInvocationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before method invoke!");
        Object result = method.invoke(target, args);
        System.out.println("After method invoke!");
        return result;
    }
}

public class Main {
    public static void main(String[] args) {
        Hello hello = new HelloImpl();
        MyInvocationHandler handler = new MyInvocationHandler(hello);
        Hello proxy = (Hello) Proxy.newProxyInstance(
                hello.getClass().getClassLoader(),
                hello.getClass().getInterfaces(),
                handler);
        proxy.sayHello();
    }
}

以上代码中,我们定义了一个Hello接口和它的实现类HelloImpl,然后实现了一个MyInvocationHandler类,并实现了其中的invoke方法,在代理类调用方法前后打印日志。最后,通过Proxy类的newProxyInstance方法创建代理类,并调用其中的sayHello方法。

使用代理机制的场景

代理机制可以用于以下场景:

  • AOP(面向切面编程):通过代理对方法进行增强,如日志记录、权限控制等;
  • 数据库连接池:通过代理实现数据库连接的多线程复用;
  • 远程调用:通过代理实现远程调用,如 RMI(远程方法调用)等。

示例说明

示例 1:AOP

在日常开发中,我们经常需要在方法调用前后打印日志,可以通过代理实现这一功能。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

interface UserService {
    void login();
}

class UserServiceImpl implements UserService {
    @Override
    public void login() {
        System.out.println("User Login");
    }
}

class LogHandler implements InvocationHandler {
    private Object target;

    public LogHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before method invoke!");
        Object result = method.invoke(target, args);
        System.out.println("After method invoke!");
        return result;
    }
}

public class Main {
    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        LogHandler handler = new LogHandler(userService);
        UserService proxy = (UserService) Proxy.newProxyInstance(
                userService.getClass().getClassLoader(),
                userService.getClass().getInterfaces(),
                handler);
        proxy.login();
    }
}

以上代码中,我们通过创建一个LogHandler类实现在调用login方法前后打印日志的功能。最后通过代理类proxy调用login方法。

示例 2:数据库连接池

在多线程环境下,为了避免频繁创建和销毁数据库连接,可以通过代理实现数据库连接的多线程复用。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

interface DataSource {
    Connection getConnection();
}

class DataSourceImpl implements DataSource {
    private String url;
    private String username;
    private String password;

    public DataSourceImpl(String url, String username, String password) {
        this.url = url;
        this.username = username;
        this.password = password;
    }

    @Override
    public Connection getConnection() {
        Connection conn = null;
        try {
            Class.forName("com.mysql.jdbc.Driver");
            conn = DriverManager.getConnection(url, username, password);
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }
        return conn;
    }
}

class ConnectionHandler implements InvocationHandler {
    private DataSource dataSource;

    public ConnectionHandler(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if ("getConnection".equals(method.getName())) {
            Connection conn = (Connection) method.invoke(dataSource, args);
            return new ConnectionProxy(conn);
        }
        return null;
    }
}

class ConnectionProxy implements InvocationHandler {
    private Connection conn;

    public ConnectionProxy(Connection conn) {
        this.conn = conn;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if ("close".equals(method.getName())) {
            System.out.println("Connection return to pool!");
            return null;
        }
        return method.invoke(conn, args);
    }
}

public class Main {
    public static void main(String[] args) {
        DataSource dataSource = new DataSourceImpl("jdbc:mysql://localhost:3306/test", "root", "password");
        ConnectionHandler handler = new ConnectionHandler(dataSource);
        DataSource proxy = (DataSource) Proxy.newProxyInstance(
                dataSource.getClass().getClassLoader(),
                dataSource.getClass().getInterfaces(),
                handler);
        Connection conn = proxy.getConnection();
        conn.prepareStatement("SELECT * FROM user WHERE id = 1");
        conn.close();
    }
}

以上代码中,我们通过创建一个ConnectionProxy类实现对获取数据库连接的代理,通过代理类ConnectionProxy实现对连接的控制。最后通过代理类proxy获取数据库连接并进行操作。

结论

通过本文,我们了解了 Java 的代理机制及其应用场景,学会了使用动态代理实现对方法的增强和数据库连接的控制。在实际开发中,代理机制是一个非常有用的工具,能够提高代码的可维护性和可扩展性。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:带你深入了解java-代理机制 - Python技术站

(0)
上一篇 2023年6月26日
下一篇 2023年6月26日

相关文章

  • SpringBoot项目集成Flyway进行数据库版本控制的详细教程

    SpringBoot项目集成Flyway进行数据库版本控制的详细教程 Flyway是一个开源的数据库版本控制工具,它可以帮助我们管理数据库的变更和迁移。在Spring Boot项目中,我们可以很方便地集成Flyway来实现数据库版本控制。下面是一个详细的攻略,包含了集成Flyway的步骤和两个示例说明。 步骤一:添加Flyway依赖 首先,在你的Spring…

    other 2023年8月3日
    00
  • Win10 Build 10532运行上手高清截图 改进右键菜单

    这是一篇关于如何在Win10 Build 10532上使用高清截图和改进右键菜单的完整攻略。通过本文,您将了解到具体的步骤,并通过两条具体的示例说明实际操作。 高清截图 步骤一:打开Snipping 定位工具 首先,从开始菜单中找到”Snipping 工具”并打开。您也可以使用Win+Shift+s快捷键打开截图工具。 步骤二:选择截图区域 鼠标会变成十字架…

    other 2023年6月27日
    00
  • Oracle REGEXP_LIKE模糊查询用法例子

    Oracle REGEXP_LIKE模糊查询用法例子攻略 简介 Oracle数据库提供了REGEXP_LIKE函数,用于进行正则表达式的模糊查询。该函数可以帮助我们在数据库中进行更加灵活和精确的数据搜索。本攻略将详细介绍REGEXP_LIKE函数的用法,并提供两个示例说明。 语法 REGEXP_LIKE函数的基本语法如下: REGEXP_LIKE(colum…

    other 2023年8月19日
    00
  • windows7系统下如何查看IP地址?win7查看IP地址的2个方法

    在Windows 7系统下,你可以使用以下两种方法来查看IP地址: 方法一:使用命令提示符 打开开始菜单,点击“运行”(或者按下Win + R键),输入“cmd”并按下回车键,打开命令提示符窗口。 在命令提示符窗口中,输入以下命令并按下回车键:ipconfig 这将显示与你的计算机相关的网络配置信息。 在命令提示符窗口中,查找以太网适配器或无线局域网适配器的…

    other 2023年7月30日
    00
  • Win10 Java jdk14.0.2安装及环境变量配置详细教程

    Win10 Java jdk14.0.2安装及环境变量配置详细教程 安装JDK 下载JDK 前往官网(https://www.oracle.com/java/technologies/javase-jdk14-downloads.html)下载JDK 14.0.2版本,并根据操作系统选择相应的安装包。 安装JDK 将下载的JDK安装包双击打开,跟随向导完成安…

    other 2023年6月27日
    00
  • php从完整文件路径中分离文件目录和文件名的方法

    分离文件目录和文件名通常是在处理文件操作时经常会用到的操作。在PHP中,我们可以使用函数pathinfo()和dirname()来实现分离文件目录和文件名。下面是详细的攻略: 使用pathinfo() pathinfo() 函数返回文件路径的信息,包括文件目录、文件名、文件扩展名等信息。我们可以利用它来获取文件名称、文件目录和文件扩展名信息。 下面是一个示例…

    other 2023年6月26日
    00
  • android系统id介绍

    Android系统id介绍 在Android系统中,每个Android设备都有一个唯一的标示符,即设备ID。这个ID在应用程序开发中也被称为Android ID,设备ID,系统ID等等,是一个可以用于标识Android设备的字符串。 获取Android ID 获取Android ID非常容易,只需要使用以下代码即可: String android_id = …

    其他 2023年3月28日
    00
  • 解决svn每次操作都需要重输入用户名密码问题

    解决 SVN 每次操作都需要重新输入用户名密码问题 如果你经常使用 SVN 进行代码的版本控制,你可能会遇到每次对版本库进行操作都需要重新输入用户名密码的问题。这个问题可能会让你感到很困扰,因为每次都需要输入用户名和密码会导致你的工作效率降低。 这个问题的主要原因是 SVN 默认不会缓存用户的用户名和密码,每次使用 SVN 都需要重新输入。但是,SVN 提供…

    其他 2023年3月29日
    00
合作推广
合作推广
分享本页
返回顶部