如何動(dòng)態(tài)修改JavaBean中注解的參數(shù)值
我這里有一個(gè)需求需要修改Person類中的一個(gè)屬性上的注解的值進(jìn)行修改,例如:
public class Person {
private int age;
@ApiParam(access="lala")
private String name;
//get set 方法忽略
}
將@ApiParam(access=“l(fā)ala”) 修改為@ApiParam(access=“fafa”),經(jīng)過分析是可以實(shí)現(xiàn)的,需要用到動(dòng)態(tài)代理進(jìn)行操作。
具體源碼如下所示:
@Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiParam {
String access() default "";
}
反射+動(dòng)態(tài)代理代碼如下:
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 是一個(gè)自定義的注解
ApiParam apiParam = (ApiParam) value.getAnnotation(ApiParam.class);
java.lang.reflect.InvocationHandler invocationHandler = Proxy.getInvocationHandler(apiParam);
Field memberValues = invocationHandler.getClass().getDeclaredField("memberValues");
//通過反射獲取memberValues 這個(gè)屬性是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());
//動(dòng)態(tài)代理的方式不會(huì)改變?cè)萩lass文件的內(nèi)容
}
}
補(bǔ)充:Java自定義注解并實(shí)現(xiàn)注解的偽動(dòng)態(tài)參數(shù)傳遞
自定義注解,實(shí)現(xiàn)記錄接口的調(diào)用日志,此注解可以實(shí)現(xiàn)傳遞偽動(dòng)態(tài)參數(shù)。
一、需要引入的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);
// 獲取注解中的參數(shù)
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);
// 將注解中測(cè)參數(shù)值保存到數(shù)據(jù)庫,實(shí)現(xiàn)記錄接口調(diào)用日志的功能(以下內(nèi)容省略...)
}
/**
* 獲取注解中傳遞的動(dòng)態(tài)參數(shù)的參數(shù)值
*
* @param joinPoint
* @param name
* @return
*/
public String getAnnotationValue(JoinPoint joinPoint, String name) {
String paramName = name;
// 獲取方法中所有的參數(shù)
Map<String, Object> params = getParams(joinPoint);
// 參數(shù)是否是動(dòng)態(tài)的:#{paramName}
if (paramName.matches("^#\\{\\D*\\}")) {
// 獲取參數(shù)名
paramName = paramName.replace("#{", "").replace("}", "");
// 是否是復(fù)雜的參數(shù)類型:對(duì)象.參數(shù)名
if (paramName.contains(".")) {
String[] split = paramName.split("\\.");
// 獲取方法中對(duì)象的內(nèi)容
Object object = getValue(params, split[0]);
// 轉(zhuǎn)換為JsonObject
JSONObject jsonObject = JSONObject.fromObject(object);
// 獲取值
Object o = jsonObject.get(split[1]);
return String.valueOf(o);
}
// 簡單的動(dòng)態(tài)參數(shù)直接返回
return String.valueOf(getValue(params, paramName));
}
// 非動(dòng)態(tài)參數(shù)直接返回
return name;
}
/**
* 根據(jù)參數(shù)名返回對(duì)應(yīng)的值
*
* @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;
}
/**
* 獲取方法的參數(shù)名和值
*
* @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;
}
}
四:測(cè)試前的準(zhǔn)備內(nèi)容:
// 實(shí)體類
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層內(nèi)容
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 = "測(cè)試注解傳遞復(fù)雜動(dòng)態(tài)參數(shù)")
public void saveUser(User user,String id){
System.out.println("測(cè)試注解...");
}
@ApiOperationLog(resourceId = "#{id}",operationType = "UPDATE",description = "測(cè)試注解傳遞簡單動(dòng)態(tài)參數(shù)")
public void updateUser(User user,String id){
System.out.println("測(cè)試注解...");
}
}
五、測(cè)試類:
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");
}
}
測(cè)試結(jié)果:
測(cè)試注解... resourceId:1 operationType:SAVE description:測(cè)試注解傳遞復(fù)雜動(dòng)態(tài)參數(shù) 測(cè)試注解... resourceId:666 operationType:UPDATE description:測(cè)試注解傳遞簡單動(dòng)態(tài)參數(shù)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。
相關(guān)文章
Mac M1 Java 開發(fā)環(huán)境配置詳解
這篇文章主要介紹了Mac M1 Java 開發(fā)環(huán)境配置詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03
tk.mybatis如何擴(kuò)展自己的通用mapper
這篇文章主要介紹了tk.mybatis如何擴(kuò)展自己的通用mapper操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06
Java中@Pattern注解常用的校驗(yàn)正則表達(dá)式學(xué)習(xí)筆記
對(duì)于正則這個(gè)東西,對(duì)我來說一直是很懵逼的,每次用每次查,然后還是記不住,下面這篇文章主要給大家介紹了關(guān)于Java中@Pattern注解常用的校驗(yàn)正則表達(dá)式學(xué)習(xí)筆記的相關(guān)資料,需要的朋友可以參考下2022-07-07
Jpa?Specification如何實(shí)現(xiàn)and和or同時(shí)使用查詢
這篇文章主要介紹了Jpa?Specification如何實(shí)現(xiàn)and和or同時(shí)使用查詢,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11
關(guān)于Assert.assertEquals報(bào)錯(cuò)的問題及解決
這篇文章主要介紹了關(guān)于Assert.assertEquals報(bào)錯(cuò)的問題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-05-05
Java實(shí)現(xiàn)文件點(diǎn)擊沒反應(yīng)的方法
jsp頁面鏈接,點(diǎn)擊訪問action用IO流去下載服務(wù)器上的文件,問題是任憑怎么點(diǎn)擊都沒反應(yīng),日志也不報(bào)錯(cuò)。這篇文章給大家介紹Java實(shí)現(xiàn)文件點(diǎn)擊沒反應(yīng)的方法,需要的朋友參考下吧2018-07-07
Java使用@EnableEurekaServer實(shí)現(xiàn)自動(dòng)裝配詳解
這篇文章主要介紹了Java使用@EnableEurekaServer實(shí)現(xiàn)自動(dòng)裝配過程,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2022-10-10
Springboot Logback日志多文件輸出方式(按日期和大小分割)
這篇文章主要介紹了Springboot Logback日志多文件輸出方式(按日期和大小分割),具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-05-05

