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

Java学习——day24(反射进阶:注解与动态代理)

文章目录

  • 1. 反射与注解
  • 2. 动态代理
  • 3. 实践:编写动态代理示例
  • 4. 注解定义与使用
  • 5. 动态代理
  • 6. 小结与思考

1. 反射与注解

  • 注解:注解是 Java 提供的用于在代码中添加元数据的机制。它不会影响程序的执行,但可以在运行时通过反射获取和处理。
  • 反射读取注解:
    • 通过 Class、Method、Field 等反射 API 获取注解信息。
    • 注解可以用于类、方法、字段等。

2. 动态代理

  • 动态代理的概念:动态代理是 Java 提供的一种机制,可以在运行时创建接口的代理实例,并且可以在方法调用前后插入额外的操作。
  • 使用 Proxy 类:java.lang.reflect.Proxy 类提供了创建代理对象的静态方法。
  • 代理接口:通过 InvocationHandler 接口来定义代理对象的行为。

3. 实践:编写动态代理示例

  • 创建一个接口,使用动态代理为其生成代理对象。
  • 在代理方法中加入日志打印,打印每个方法的调用时间。

4. 注解定义与使用

注解的定义通常采用 @interface 关键字,例如:

// 定义一个自定义注解
import java.lang.annotation.*;

@Target(ElementType.METHOD) // 这个注解应用在方法上
@Retention(RetentionPolicy.RUNTIME) // 运行时可以反射获取
public @interface Log {
    String value() default "日志记录";
}

如何通过反射读取注解:
假设有如下类及方法上使用了注解:

import java.lang.annotation.*;

public class Example {

    // 应用自定义注解
    @Log(value = "执行sayHello方法")
    public void sayHello() {
        System.out.println("Hello, World!");
    }

    public static void main(String[] args) {
        try {
            // 获取 sayHello 方法的 Class 对象
            Method method = Example.class.getMethod("sayHello");

            // 判断该方法是否有 Log 注解
            if (method.isAnnotationPresent(Log.class)) {
                // 获取注解的值
                Log log = method.getAnnotation(Log.class);
                System.out.println("注解内容: " + log.value());
            }

            // 调用方法
            method.invoke(new Example());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

输出结果:

注解内容: 执行sayHello方法
Hello, World!

解释:

  • @Log 注解定义了一个 value 属性,在 sayHello() 方法上使用。
  • 通过反射获取方法 sayHello,使用 isAnnotationPresent 判断是否应用了注解,然后获取注解并打印 value 属性。

5. 动态代理

动态代理的原理

  • 动态代理是一种在运行时创建代理对象的技术。通过 java.lang.reflect.Proxy 类和 InvocationHandler 接口,Java 实现了动态代理机制。
  • 通过动态代理可以增强原对象的功能,比如记录日志、权限控制等。

创建动态代理的基本步骤
1.定义接口:代理类需要实现接口。
2.实现 InvocationHandler:InvocationHandler 用于处理代理对象的方法调用。
3.使用 Proxy.newProxyInstance():创建代理对象。

示例:为某个接口创建代理对象,并在方法调用前后打印日志
1. 定义接口

public interface Person {
    void sayHello();
    void work();
}

2. 实现接口

public class PersonImpl implements Person {
    @Override
    public void sayHello() {
        System.out.println("Hello from Person!");
    }

    @Override
    public void work() {
        System.out.println("Person is working.");
    }
}

3. 创建 InvocationHandler 实现类

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

public class LoggingHandler implements InvocationHandler {
    private Object target;

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 在方法执行前打印日志
        System.out.println("Method " + method.getName() + " is about to be called.");

        // 执行目标方法
        Object result = method.invoke(target, args);

        // 在方法执行后打印日志
        System.out.println("Method " + method.getName() + " was called.");

        return result;
    }
}

4. 使用 Proxy 创建代理对象

import java.lang.reflect.Proxy;

public class DynamicProxyExample {
    public static void main(String[] args) {
        Person person = new PersonImpl(); // 创建目标对象
        
        // 创建代理对象
        Person proxyPerson = (Person) Proxy.newProxyInstance(
            Person.class.getClassLoader(),
            new Class<?>[]{Person.class},
            new LoggingHandler(person)
        );

        // 使用代理对象调用方法
        proxyPerson.sayHello();
        proxyPerson.work();
    }
}

输出结果:

Method sayHello is about to be called.
Hello from Person!
Method sayHello was called.
Method work is about to be called.
Person is working.
Method work was called.

解释:

  • 通过 Proxy.newProxyInstance() 创建了一个 Person 接口的代理对象。代理对象会调用 LoggingHandler 的 invoke 方法。
  • LoggingHandler 通过 method.invoke(target, args) 调用实际的目标方法,并在方法调用前后打印日志。

6. 小结与思考

1.反射与注解:

  • 注解是一个非常强大的元数据机制,可以在运行时动态地获取类和方法的相关信息。常见应用包括框架开发、AOP(面向切面编程)等。
    2.动态代理:
  • 动态代理是面向切面编程中的一个核心技术,它允许我们在运行时动态地为接口生成代理,并对方法执行前后进行增强(如日志、权限控制等)。
  • 动态代理广泛应用于 Java 框架,如 Spring 的 AOP(面向切面编程)。

相关文章:

  • 海外网红营销新玩法:虚拟红人引爆2025跨境电商市场
  • LeetCode算法题(Go语言实现)_35
  • Java面向对象高级(继承、单例、抽象、接口)
  • MySQL学习笔记九
  • ETPNav:基于演进拓扑规划的连续环境视觉语言导航模型
  • VUE中的路由处理
  • 2025我们关注DeepSeek什么?
  • Ollama部署离线大模型
  • 前端跨页面通信完全指南
  • 利用Python requests库爬虫程序示例
  • Spring IOC 容器加载过程
  • C++实现文件断点续传:原理剖析与实战指南
  • Tips:用proxy解决前后端分离项目中的跨域问题
  • 研发效率破局之道阅读总结(1)研发效能
  • Windows 图形显示驱动开发-WDDM 2.0功能_IoMmu 模型
  • 开源推荐#2:Social Auto Upload — 自动化上传视频到社交媒体
  • 已知Word内容格式固定,通过宏实现Word转Excel
  • 【区块链安全 | 第三十七篇】合约审计之获取私有数据(一)
  • 理解 DuckDB 的逻辑计划(Logical Plan)、优化器(Optimizer)和物理执行计划模块的工作流程
  • [Godot] C#简单实现人物的控制和动画
  • 极限拉扯上任巴西,安切洛蒂开启夏窗主帅大挪移?
  • 新剧|《藏海传》定档,《折腰》《人生若如初见》今日开播
  • 工人日报:“鼠标手”被纳入职业病,劳动保障网越织越密
  • 茅台1935今年动销达到预期,暂无赴港上市计划!茅台业绩会回应多个热点
  • “拼好假”的年轻人,今年有哪些旅游新玩法?
  • 解放军仪仗分队参加白俄罗斯纪念苏联伟大卫国战争胜利80周年阅兵活动