如何动态修改JavaBean中注解的参数值

 更新时间:2021年02月19日 10:33:26   作者:消魂钉  
这篇文章主要介绍了如何动态修改JavaBean中注解的参数值操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

我这里有一个需求需要修改Person类中的一个属性上的注解的值进行修改,例如:

public class Person {
 private int age;
 @ApiParam(access="lala")
 private String name;
 //get set 方法忽略 
}

将@ApiParam(access=“lala”) 修改为@ApiParam(access=“fafa”),经过分析是可以实现的,需要用到动态代理进行操作。

具体源码如下所示:

@Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiParam {
 String access() default "";
}

反射+动态代理代码如下:

public class TestClazz {
 public static void main(String[] args) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { 
 Person person = new Person();
 Field value = person.getClass().getDeclaredField("name");
 value.setAccessible(true);
 //APIParam 是一个自定义的注解
 ApiParam apiParam = (ApiParam) value.getAnnotation(ApiParam.class);
 java.lang.reflect.InvocationHandler invocationHandler = Proxy.getInvocationHandler(apiParam);
 Field memberValues = invocationHandler.getClass().getDeclaredField("memberValues");
 //通过反射获取memberValues 这个属性是Map类型 存放着所有的属性。
  memberValues.setAccessible(true);
  Map<String, Object> values = (Map<String, Object>) memberValues.get(invocationHandler);
  String val = (String) values.get("access");
 System.out.println("------改之前:"+val);
 values.put("access", "fafa");//修改属性
 System.out.println("-----------------");
 //Field value1 = person.getClass().getDeclaredField("name");
 value.setAccessible(true);
 ApiParam apiParam1 = (ApiParam) value.getAnnotation(ApiParam.class);
 System.out.println("------改之后:"+apiParam1.access());
 //动态代理的方式不会改变原先class文件的内容
 }
}

补充:Java自定义注解并实现注解的伪动态参数传递

自定义注解,实现记录接口的调用日志,此注解可以实现传递伪动态参数。

一、需要引入的jar包:

<dependencies>
 <dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-web</artifactId>
 </dependency>
 <dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-test</artifactId>
 </dependency>
<!-- test -->
 <dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-test</artifactId>
 </dependency>
 <dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-aop</artifactId>
 </dependency>
<!-- json -->
 <dependency>
 <groupId>commons-lang</groupId>
 <artifactId>commons-lang</artifactId>
 <version>2.4</version>
 </dependency>
 <dependency>
 <groupId>org.apache.commons</groupId>
 <artifactId>commons-lang3</artifactId>
 </dependency>
 <dependency>
 <groupId>commons-beanutils</groupId>
 <artifactId>commons-beanutils</artifactId>
 <version>1.8.0</version>
 </dependency>
 <dependency>
 <groupId>commons-collections</groupId>
 <artifactId>commons-collections</artifactId>
 <version>3.2.1</version>
 </dependency>
 <dependency>
 <groupId>commons-logging</groupId>
 <artifactId>commons-logging</artifactId>
 <version>1.1.1</version>
 </dependency>
 <dependency>
 <groupId>net.sf.json-lib</groupId>
 <artifactId>json-lib</artifactId>
 <version>2.4</version>
 </dependency>
 </dependencies>

二、自定义注解:

package com.example.demo.annotation; 
import java.lang.annotation.*; 
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ApiOperationLog {
 String resourceId() default "";
 String operationType();
 String description() default "";
}

三、定义切面:

package com.example.demo.aspect; 
import com.example.demo.annotation.ApiOperationLog;
import net.sf.json.JSONObject;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component; 
import java.util.HashMap;
import java.util.Map;
 
@Aspect
@Component
public class ApiOperationAspect { 
 @Pointcut("@annotation ( com.example.demo.annotation.ApiOperationLog)")
 public void apiLog() {
 }
 
 @AfterReturning(pointcut = "apiLog()")
 public void recordLog(JoinPoint joinPoint) {
  MethodSignature signature = (MethodSignature) joinPoint.getSignature();
  // 获取方法上的指定注解
  ApiOperationLog annotation = signature.getMethod().getAnnotation(ApiOperationLog.class);
  // 获取注解中的参数
  String resourceId = getAnnotationValue(joinPoint, annotation.resourceId());
  String operationType = getAnnotationValue(joinPoint, annotation.operationType());
  String description = getAnnotationValue(joinPoint, annotation.description());
  System.out.println("resourceId:" + resourceId);
  System.out.println("operationType:" + operationType);
  System.out.println("description:" + description);
  // 将注解中测参数值保存到数据库,实现记录接口调用日志的功能(以下内容省略...) 
 }
 
 /**
  * 获取注解中传递的动态参数的参数值
  *
  * @param joinPoint
  * @param name
  * @return
  */
 public String getAnnotationValue(JoinPoint joinPoint, String name) {
  String paramName = name;
  // 获取方法中所有的参数
  Map<String, Object> params = getParams(joinPoint);
  // 参数是否是动态的:#{paramName}
  if (paramName.matches("^#\\{\\D*\\}")) {
   // 获取参数名
   paramName = paramName.replace("#{", "").replace("}", "");
   // 是否是复杂的参数类型:对象.参数名
   if (paramName.contains(".")) {
    String[] split = paramName.split("\\.");
    // 获取方法中对象的内容
    Object object = getValue(params, split[0]);
    // 转换为JsonObject
    JSONObject jsonObject = JSONObject.fromObject(object);
    // 获取值
    Object o = jsonObject.get(split[1]);
    return String.valueOf(o);
   }
   // 简单的动态参数直接返回
   return String.valueOf(getValue(params, paramName));
  }
  // 非动态参数直接返回
  return name;
 }
 
 /**
  * 根据参数名返回对应的值
  *
  * @param map
  * @param paramName
  * @return
  */
 public Object getValue(Map<String, Object> map, String paramName) {
  for (Map.Entry<String, Object> entry : map.entrySet()) {
   if (entry.getKey().equals(paramName)) {
    return entry.getValue();
   }
  }
  return null;
 }
 
 /**
  * 获取方法的参数名和值
  *
  * @param joinPoint
  * @return
  */
 public Map<String, Object> getParams(JoinPoint joinPoint) {
  Map<String, Object> params = new HashMap<>(8);
  Object[] args = joinPoint.getArgs();
  MethodSignature signature = (MethodSignature) joinPoint.getSignature();
  String[] names = signature.getParameterNames();
  for (int i = 0; i < args.length; i++) {
   params.put(names[i], args[i]);
  }
  return params;
 } 
}

四:测试前的准备内容:

// 实体类
package com.example.demo.model; 
public class User {
 
 private Long id;
 private String name;
 private int age;
 
 public Long getId() {
  return id;
 }
 
 public void setId(Long id) {
  this.id = id;
 }
 
 public String getName() {
  return name;
 }
 
 public void setName(String name) {
  this.name = name;
 }
 
 public int getAge() {
  return age;
 }
 
 public void setAge(int age) {
  this.age = age;
 }
 
 @Override
 public String toString() {
  return "User{" +
    "id=" + id +
    ", name='" + name + '\'' +
    ", age=" + age +
    '}';
 }
} 
 
// controller层内容
package com.example.demo.controller; 
import com.example.demo.annotation.ApiOperationLog;
import com.example.demo.model.User;
import org.springframework.web.bind.annotation.RestController; 
@RestController
public class LoginController {
 
 @ApiOperationLog(resourceId = "#{user.id}",operationType = "SAVE",description = "测试注解传递复杂动态参数")
 public void saveUser(User user,String id){
  System.out.println("测试注解...");
 }
 
 @ApiOperationLog(resourceId = "#{id}",operationType = "UPDATE",description = "测试注解传递简单动态参数")
 public void updateUser(User user,String id){
  System.out.println("测试注解...");
 }
 
}

五、测试类:

package com.example.demo.aspect; 
import com.example.demo.DemoApplication;
import com.example.demo.controller.LoginController;
import com.example.demo.model.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = DemoApplication.class)
public class ControllerTest {
 
 @Autowired
 private LoginController loginController;
 
 @Test
 public void test(){
  User user = new User();
  user.setId(1L);
  user.setName("test");
  user.setAge(20);
  loginController.saveUser(user,"123");
  loginController.updateUser(user,"666");
 }
}

测试结果:

测试注解...
resourceId:1
operationType:SAVE
description:测试注解传递复杂动态参数
测试注解...
resourceId:666
operationType:UPDATE
description:测试注解传递简单动态参数

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。如有错误或未考虑完全的地方,望不吝赐教。

相关文章

  • java实习--每天打卡十道面试题!

    java实习--每天打卡十道面试题!

    临近秋招,备战暑期实习,祝大家每天进步亿点点!本篇文章准备了十道java的常用面试题,希望能够给大家提供帮助,最后祝大家面试成功,进入自己心仪的大厂
    2021-06-06
  • Java Ribbon与openfeign区别和用法讲解

    Java Ribbon与openfeign区别和用法讲解

    Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具,主要功能是提供客户端的软件负载均衡算法和服务调用。openfeign对Feign进行了增强,使其支持Spring MVC注解,另外还整合了Ribbon和Nacos,从而使得Feign的使用更加方便
    2022-08-08
  • springboot+spring data jpa实现新增及批量新增方式

    springboot+spring data jpa实现新增及批量新增方式

    这篇文章主要介绍了springboot+spring data jpa实现新增及批量新增方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-11-11
  • Java实现读取SFTP服务器指定目录文件的方法

    Java实现读取SFTP服务器指定目录文件的方法

    SFTP是一种在安全通道上传输文件的协议,它是基于SSH(Secure Shell)协议的扩展,用于在客户端和服务器之间进行加密的文件传输,这篇文章主要介绍了Java实现读取SFTP服务器指定目录文件,感兴趣的朋友跟随小编一起看看吧
    2023-08-08
  • Java 实现RSA非对称加密算法

    Java 实现RSA非对称加密算法

    RSA解决了对称加密的一个不足,比如AES算法加密和解密时使用的是同一个秘钥,因此这个秘钥不能公开,因此对于需要公开秘钥的场合,我们需要在加密和解密过程中使用不同的秘钥,加密使用的公钥可以公开,解密使用的私钥要保密,这就是非对称加密的好处。 
    2021-06-06
  • Java socket通信模拟QQ实现多人聊天室

    Java socket通信模拟QQ实现多人聊天室

    Socket在Java实战网络通信编程应用中有非常重要的作用,你想要跟别人联系都得通过socket占据端口来实现,掌握Socket技术不仅在聊天应用程序中需要用到(比如QQ什么的都都是用socket来写的),而且对于学习 Asp.net 也非常有帮助
    2022-07-07
  • 浅谈Android开发中项目的文件结构及规范化部署建议

    浅谈Android开发中项目的文件结构及规范化部署建议

    这篇文章主要介绍了Android开发中项目的文件结构及规范化部署建议,组织好代码文件的结构有利于维护团队合作的效率,需要的朋友可以参考下
    2016-03-03
  • java 示例讲解循环语句的使用

    java 示例讲解循环语句的使用

    顺序结构的程序语句只能被执行一次。如果您想要同样的操作执行多次,就需要使用循环结构,循环结构就是在循环条件满足的情况下,反复执行特定代码
    2022-04-04
  • Spring在多线程环境下如何确保事务一致性问题详解

    Spring在多线程环境下如何确保事务一致性问题详解

    这篇文章主要介绍了Spring在多线程环境下如何确保事务一致性问题详解,说到异步执行,很多小伙伴首先想到Spring中提供的@Async注解,但是Spring提供的异步执行任务能力并不足以解决我们当前的需求,需要的朋友可以参考下
    2023-11-11
  • logback输出日志屏蔽quartz的debug等级日志方式

    logback输出日志屏蔽quartz的debug等级日志方式

    这篇文章主要介绍了logback输出日志屏蔽quartz的debug等级日志方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-08-08

最新评论