当前位置: 首页 > article >正文

Java学习笔记(九)

InvocationHandler

InvocationHandler 详细介绍

InvocationHandler 是 Java 反射机制中的一个接口,属于 java.lang.reflect 包。它的主要作用是为动态代理提供处理方法调用的能力。当使用 Java 动态代理时,可以通过实现 InvocationHandler 接口来定义在代理对象上调用方法时的行为。

核心方法
  • invoke(Object proxy, Method method, Object[] args):
    • proxy: 代表被代理的对象。
    • method: 被调用的方法。
    • args: 方法参数。

该方法会在每次调用代理对象的方法时被触发,你可以在这里添加额外的逻辑,比如日志、事务管理等。

AOP(面向切面编程)

AOP(Aspect-Oriented Programming)是一种编程范式,它允许你将关注点分离到不同的“切面”中。与传统 OOP 不同,AOP 可以让你将横切关注点(如日志、安全性、事务管理等)从业务逻辑中分离出来,从而提高代码的可维护性和可重用性。

AOP 和 InvocationHandler 的关系
  • 在 Java 中,Spring AOP 实际上是基于动态代理实现的,其中就使用了 InvocationHandler。当你创建一个带有切面的 Spring Bean 时,Spring 会生成一个代理类,这个类会实现目标接口,并在其内部使用 InvocationHandler 来拦截方法调用。

  • 因此,当你使用 Spring AOP 定义一个切面并应用于某个服务时,实际上是在背后利用了 InvocationHandler 来执行横切逻辑。

示例代码

以下是一个简单示例,包括自定义的 InvocationHandler 和如何通过 Spring AOP 使用它:

自定义 InvocationHandler 示例
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

// 定义接口
interface HelloService {
    void sayHello(String name);
}

// 实现接口
class HelloServiceImpl implements HelloService {
    @Override
    public void sayHello(String name) {
        System.out.println("Hello, " + name);
    }
}

// 自定义 InvocationHandler
class MyInvocationHandler implements InvocationHandler {
    private final 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: " + method.getName());
        
        // 调用目标方法
        Object result = method.invoke(target, args);
        
        // 后置增强:打印结束信息
        System.out.println("After method: " + method.getName());
        
        return result;
    }
}

public class Main {
    public static void main(String[] args) {
        HelloService helloService = new HelloServiceImpl();
        
        // 创建动态代理实例
        HelloService proxyInstance = (HelloService) Proxy.newProxyInstance(
                helloService.getClass().getClassLoader(),
                helloService.getClass().getInterfaces(),
                new MyInvocationHandler(helloService)
        );

        // 调用代理实例的方法
        proxyInstance.sayHello("World");
    }
}
输出结果
Before method: sayHello
Hello, World
After method: sayHello
使用 Spring AOP 示例

如果你想要通过 Spring AOP 来实现类似功能,可以按照下面步骤进行:

  1. 添加依赖(以 Maven 为例):
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
  1. 创建服务和切面:
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Service;

@Service
public class HelloServiceImpl implements HelloService {
    
    @Override
    public void sayHello(String name) {
        System.out.println("Hello, " + name);
    }
}

@Aspect
@Component
class LoggingAspect {

    @Before("execution(* com.example.HelloService.*(..))")
    public void logBefore() {
        System.out.println("Before executing the method");
    }
}
  1. 启动 Spring Boot 应用程序,并调用服务:
@SpringBootApplication
public class Application {

   public static void main(String[] args) {
       ApplicationContext context = SpringApplication.run(Application.class, args);
       HelloService helloService = context.getBean(HelloService.class);
       helloService.sayHello("World");
   }
}
总结
  • InvocationHandler 用于创建动态代理并处理方法调用。
  • AOP 是一种编程范式,通过切面将横切关注点从业务逻辑中分离出来。
  • 在 Spring 中,AOP 是基于动态代理实现的,因此可以看作是对 InvocationHandler 的高级封装。

MethodInterceptor 和 InvocationHandler 的关系

MethodInterceptor和InvocationHandler都是用于实现动态代理的工具,但它们在实现方式、应用场景以及效率上有所不同。以下是对两者关系的详细分析:

一、定义与实现方式
  1. InvocationHandler
  • InvocationHandler是Java动态代理的一种方式,定义在java.lang.reflect包中。
  • 通过实现InvocationHandler接口,开发者可以定义在代理对象上调用方法时要执行的逻辑。
  • InvocationHandler接口包含一个invoke()方法,该方法在代理对象的方法被调用时被触发。
  1. MethodInterceptor
  • MethodInterceptor是CGLIB库(Code Generation Library)提供的一种动态代理方式。
  • CGLIB是一个用于生成Java字节码的代码生成库,它允许在运行时对类进行代理,而不仅仅是对接口。
  • MethodInterceptor接口定义了一个intercept()方法,该方法在代理对象的方法被调用时被触发。
二、应用场景
  1. InvocationHandler
    主要用于对接口进行代理。
    由于Java的动态代理机制是基于接口的,因此InvocationHandler适用于那些需要代理的类实现了特定接口的场景。
  2. MethodInterceptor
    可以对类进行代理,而无需实现特定接口。
    由于CGLIB通过继承目标类来生成代理,因此MethodInterceptor适用于那些无法或不想实现接口的类。
三、效率与性能
  1. InvocationHandler
    由于Java的动态代理机制相对简单且直接基于接口,因此InvocationHandler通常具有较高的效率。
  2. MethodInterceptor
    由于CGLIB需要生成不同类型的字节码,并且需要生成一些运行时对象,因此MethodInterceptor的效率相对较低。
    但是,这种性能差异在大多数情况下可能并不显著,具体取决于应用程序的复杂性和性能要求。
四、总结
  1. InvocationHandler和MethodInterceptor都是实现动态代理的有效工具,但它们在实现方式、应用场景以及效率上有所不同。
  2. 如果只需要对接口进行代理,并且对效率有较高的要求,那么可以选择使用InvocationHandler。
  3. 如果需要对类进行代理,或者需要更多的控制被拦截的方法,那么可以选择使用MethodInterceptor。

综上所述,MethodInterceptor和InvocationHandler各有优劣,开发者应根据具体需求和场景选择合适的动态代理方式。

find 命令

find 命令是 Unix/Linux 系统中用于查找文件和目录的强大工具。它可以在指定的目录及其子目录中搜索符合条件的文件,并对这些文件执行操作。

基本语法
find [path] [expression]
  • path: 要搜索的路径,可以是一个或多个目录。如果不指定,默认是在当前目录。
  • expression: 用于定义查找条件,如名称、类型、大小等。
常用选项和表达式
  1. 基本查找

    • 查找特定名称的文件:

      find /path/to/search -name "filename"
      
    • 查找特定扩展名的文件:

      find /path/to/search -name "*.txt"
      
  2. 忽略大小写

    使用 -iname 选项可以忽略大小写:

    find /path/to/search -iname "*.txt"
    
  3. 按类型查找

    可以使用 -type 选项来限制查找结果:

    • 查找普通文件:

      find /path/to/search -type f
      
    • 查找目录:

      find /path/to/search -type d
      
    • 查找符号链接:

      find /path/to/search -type l
      
  4. 按时间查找

    使用 -mtime, -atime, 和 -ctime 来根据时间过滤:

    • 查找最近修改过的文件(例如:7天内):

      find /path/to/search -mtime -7 
      
    • 查找超过30天未被访问过的文件:

      find /path/to/search -atime +30 
      
  5. 按大小查找

    使用 -size 选项来根据文件大小进行筛选:

    • 找到大于100MB的文件:
      find /path/to/search -size +100M 
      
  6. 组合条件

    可以使用逻辑运算符组合多个条件:

    • -and: 与(默认)
    • -or: 或
    • !: 非

    示例:找到所有 .txt 文件并且大小大于1MB:

    find /path/to/search -name "*.txt" ! -size +1M 
    
  7. 执行命令

通过 -exec 选项可以对找到的每个文件执行命令:

find /path/to/search -name "*.tmp" -exec rm {} \;

这里 {} 是占位符,代表当前找到的每个文件,\; 表示命令结束。

  1. 打印结果

使用以下选项来控制输出格式:

  • 默认情况下,结果会逐行显示。

  • 如果需要以更易读的方式显示,可以加上 -print

find /path/to/search -name "*.log" -print 
  1. 限制深度

使用 -maxdepth-mindepth 限制搜索深度:

find /path/to/search -maxdepth 2 

这将只搜索到指定深度为2层级。

示例
  1. /home/user/ 下查找所有 .jpg 文件并删除它们:
find /home/user/ -name "*.jpg" -exec rm {} \;
  1. 找出 /var/log/ 中最后修改时间在10天前的日志文件:
find /var/log/ -mtime +10 
  1. 查找到大于500KB且以 .pdf 结尾的所有文档,并列出详细信息:
find . \( -name "*.pdf" \)  \( ! –size –500k \) –ls 
总结

find 命令非常灵活和强大,能够满足多种需求。通过合理地组合各种参数和表达式,可以高效地管理和处理大量数据。在实际使用中,根据具体需求调整路径和条件,以达到最佳效果。

mysql 创建用户方式

在 MySQL 中,创建用户是数据库管理的重要任务之一。MySQL 提供了多种方式来创建用户,包括使用 SQL 语句、图形界面工具(如 MySQL Workbench)等。下面将详细介绍通过 SQL 语句创建用户的步骤,并给出示例。

创建用户的基本步骤
  1. 连接到 MySQL 数据库:使用具有足够权限的账户(如 root 用户)登录到 MySQL。
  2. 执行 CREATE USER 语句:使用 SQL 命令创建新用户。
  3. 授予权限:为新用户分配所需的权限,以便他们可以执行特定操作。
创建用户的 SQL 语法
CREATE USER 'username'@'host' IDENTIFIED BY 'password';
  • username: 要创建的用户名。
  • host: 用户可以从哪个主机连接到数据库。常见值有:
    • 'localhost':仅允许本地连接。
    • '%':允许任何主机连接。
  • password: 用户密码。
示例
第一步:连接到 MySQL

首先,打开命令行并输入以下命令以登录到 MySQL:

mysql -u root -p

系统会提示你输入 root 用户的密码。

第二步:创建一个新用户

假设我们要创建一个名为 newuser 的新用户,该用户可以从任何主机访问,并且其密码为 password123

CREATE USER 'newuser'@'%' IDENTIFIED BY 'password123';
第三步:授予权限

接下来,我们需要为该用户授予必要的权限。例如,如果我们希望 newuser 可以对数据库进行所有操作,可以使用以下命令:

GRANT ALL PRIVILEGES ON *.* TO 'newuser'@'%';

这条命令表示给予 newuser 对所有数据库和表格的所有权限。如果只想授权某个特定数据库,例如名为 mydatabase 的数据库,可以这样做:

GRANT ALL PRIVILEGES ON mydatabase.* TO 'newuser'@'%';
第四步:刷新权限

为了确保新的权限生效,可以运行以下命令:

FLUSH PRIVILEGES;
完整示例代码

结合上述步骤,完整示例如下:

-- 登录到 MySQL (在命令行中)
mysql -u root -p;

-- 创建新用户
CREATE USER 'newuser'@'%' IDENTIFIED BY 'password123';

-- 授予所有权限(或指定数据库)
GRANT ALL PRIVILEGES ON *.* TO 'newuser'@'%';

-- 刷新权限
FLUSH PRIVILEGES;
注意事项
  1. 安全性: 使用强密码以保护你的数据库安全。
  2. 最小权限原则: 尽量不要给予过多不必要的权限,只授予必需的最低限度权利,以减少潜在风险。
  3. 主机限制: 如果你只希望特定 IP 或域名能够访问该账户,请替换 % 为具体地址,如 '192.168.1.%''example.com'

http://www.kler.cn/a/371428.html

相关文章:

  • 有趣智力题(非编程题)
  • VMware虚拟机启动报错“此主机支持 Intel VT-x,但 Intel VT-x 处于禁用状态”
  • 融合ASPICE与敏捷开发:探索汽车软件开发的最佳实践
  • Pytorch学习--神经网络--非线性激活
  • 111.SAP ABAP - Function ALV - 列、行、单元格颜色 - 记录
  • 使用docker-compose部署一个springboot项目(包含Postgres\redis\Mongo\Nginx等环境)
  • 云原生后端:现代应用架构的核心力量
  • JavaWeb——Web入门(2/9)-SpringBootWeb:快速入门(入门程序需求、开发步骤、项目相关文件说明、小结)
  • 【Linux网络编程】 --- Linux权限理解
  • ICM20948 DMP代码详解(106)
  • 四、Hadoop 命令高级用法深度剖析
  • 前端之html(二)加入css开篇(一)
  • LeetCode72:编辑距离
  • javaScript中复制一个数组的浅拷贝和深拷贝方法
  • Flutter Web部署到子路径的打包指令
  • 单细胞数据分析(四):细胞亚型注释
  • uniapp写抖音小程序阻止右滑返回上一个页面
  • Vue3使用AntV | X6绘制流程图:开箱即用
  • MPSK(BPSK/QPSK/8PSK)调制解调的Matlab仿真全套
  • TensorFlow面试整理-分布式
  • C语言——linux编程(上)
  • Fsm1
  • 枫清科技仲光庆:AI+行业新范式,双轮驱动助力数智化升级
  • 沪深A股上市公司数据报告分析
  • [蓝桥杯 2018 省 B] 乘积最大-题解
  • 配置mysql 主主模式 GTID