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

@DeclareParents

@DeclareParents 注解

@DeclareParents 是 Spring AOP 中用于 引入(Introduction) 的一个注解,它允许通过 AOP 动态地为目标类添加新的接口实现。这种功能也被称为 类型引入,是 Spring AOP 中的一种特殊功能。


1. @DeclareParents 的作用

  1. 动态扩展目标类的功能

    • 通过引入新的接口及其实现,目标类可以动态获得接口的能力,而无需显式继承或实现该接口。
  2. 不修改目标类代码

    • 目标类不需要修改代码即可获得新的行为,符合 AOP 的解耦思想。
  3. 运行时增强

    • 引入的接口和功能是在运行时动态添加的,不会改变目标类的实际类型。

2. @DeclareParents 的使用方式

基本语法
@DeclareParents(value = "目标类的类型表达式", defaultImpl = 接口实现类.class)
public 接口 被引入的接口;
  • value:指定需要增强的目标类,可以是类或接口的表达式(支持通配符)。
  • defaultImpl:指定被引入接口的默认实现类。
  • 接口:指被引入到目标类的接口。

3. 使用示例

场景描述

假设我们有一个 PersonService 类,但我们希望动态为它添加一个新功能接口(例如 HasAge),而不修改它的代码。

代码实现

1. 定义目标类

package com.example.service;

public class PersonService {
    public void sayHello() {
        System.out.println("Hello, I am a person!");
    }
}

2. 定义被引入的接口

package com.example.introduction;

public interface HasAge {
    void setAge(int age);
    int getAge();
}

3. 定义接口的默认实现类

package com.example.introduction;

public class HasAgeImpl implements HasAge {
    private int age;

    @Override
    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public int getAge() {
        return this.age;
    }
}

4. 定义切面类

package com.example.aspect;

import com.example.introduction.HasAge;
import com.example.introduction.HasAgeImpl;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.DeclareParents;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class IntroductionAspect {

    // 动态为 com.example.service.PersonService 引入 HasAge 接口
    @DeclareParents(
        value = "com.example.service.PersonService", // 目标类
        defaultImpl = HasAgeImpl.class              // 默认实现类
    )
    public static HasAge hasAge;
}

5. 启用 AOP 并测试

package com.example;

import com.example.introduction.HasAge;
import com.example.service.PersonService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.stereotype.Component;

@Component
public class MainApp {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

        // 获取目标类的 Spring Bean
        PersonService personService = context.getBean(PersonService.class);

        // 调用目标类原本的方法
        personService.sayHello();

        // 动态添加的接口功能
        if (personService instanceof HasAge) {
            HasAge hasAge = (HasAge) personService;
            hasAge.setAge(25);
            System.out.println("Age: " + hasAge.getAge());
        } else {
            System.out.println("This object does not have the HasAge interface.");
        }
    }
}

6. 配置类

package com.example;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@ComponentScan("com.example")
@EnableAspectJAutoProxy // 启用 AOP
public class AppConfig {
}
运行结果
Hello, I am a person!
Age: 25

4. 注意事项

  1. @DeclareParents 的作用范围

    • @DeclareParents 只能动态为 Spring 容器中的目标类添加接口及其实现,而不会修改类的实际字节码或类型。
  2. 目标类必须是 Spring 管理的 Bean

    • 如果目标类没有被 Spring 容器管理,@DeclareParents 不会生效。
  3. 被引入的接口实现类必须是无参构造的

    • defaultImpl 中指定的类必须有一个无参构造函数,因为 Spring 会通过反射来创建它的实例。
  4. 只能引入接口

    • @DeclareParents 只能为目标类引入接口,不能直接引入普通类。
  5. 目标类的动态行为不会改变其实际类型

    • 目标类的原始类型不会发生变化,但 Spring 会通过动态代理使其实现被引入的接口。

5. 高级用法

5.1 为多个目标类引入接口

通过通配符,可以为一组类动态引入接口。例如:

@DeclareParents(
    value = "com.example.service.*+", // 匹配 com.example.service 包中所有的类
    defaultImpl = HasAgeImpl.class
)
public static HasAge hasAge;
5.2 条件判断(检查接口是否被引入)

在代码中可以通过 instanceof 判断目标对象是否实现了某个接口:

if (targetObject instanceof HasAge) {
    System.out.println("This object has the HasAge interface!");
}

6. 与 Spring AOP 的其他功能对比

功能描述
通知 (Advice)拦截目标类的方法,增强已有行为。
引入 (Introduction)动态为目标类添加接口及其实现,扩展目标类的功能。
切入点 (Pointcut)定义哪些方法或连接点需要被拦截或增强。

7. 总结

  • @DeclareParents 是 Spring AOP 中用于实现 类型引入 的注解。
  • 它可以动态为目标类添加接口及其实现,扩展目标类的功能,而无需修改目标类代码。
  • 使用场景:
    • 动态扩展类的功能。
    • 为现有代码添加通用行为(例如日志、权限检查、属性管理等)。
  • 要正确使用 @DeclareParents,需要合理定义接口、实现类和目标类,并确保它们都被 Spring 管理。

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

相关文章:

  • LeetCode Java面试刷题笔记汇总
  • 使用Pygame制作“打砖块”游戏
  • FastAPI之参数传递和参数校验
  • 使用SpringBoot发送邮件|解决了部署时连接超时的bug|网易163|2025
  • 算法日记11:SC63(离散化)
  • mysql 学习8 函数,字符串函数,数值函数,日期函数,流程函数
  • 如何借助DeepSeek、ChatGPT等AI模型构建自己的量化交易策略?
  • maven详细讲解
  • 【Leetcode刷题记录】90. 子集 II
  • .netframework升级为.net8以后元组数据返回格式变成了 [{}]
  • Ubuntu 下 nginx-1.24.0 源码分析 - ngx_vslprintf 函数
  • 面向对象编程的三大特性
  • LeetCode 1726. Tuple with Same Product
  • vue2-插槽slot
  • 13.PPT:诺贝尔奖【28】
  • Kappa数据架构学习小结
  • 惠普HP工作站如何关闭关闭RAID?
  • DeepSeek 部署过程中的问题
  • 2025年家用音响市场分析:潜力无限,音质为王的新纪元
  • PyTorch 预分配显存是什么,为什么会有PyTorch 预分配显存
  • 【C语言系列】深入理解指针(5)
  • RabbitMQ深度探索:五种消息模式
  • CentOS 7.3编译Rsyslog 8.1903.0
  • 机器学习9-卷积和卷积核2
  • Android_P_Audio_系统(1) — Auido 系统简介
  • 【FPGA】 MIPS 12条整数指令 【3】