我这里有一个需求需要修改Person类中的一个属性上的注解的值进行修改,例如:
1
2
3
4
5
6
|
public class Person {
private int age;
@ApiParam (access= "lala" )
private String name;
//get set 方法忽略
}
|
将@ApiParam(access=“lala”) 修改为@ApiParam(access=“fafa”),经过分析是可以实现的,需要用到动态代理进行操作。
具体源码如下所示:
1
2
3
4
5
|
@Target ({ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD})
@Retention (RetentionPolicy.RUNTIME)
public @interface ApiParam {
String access() default "" ;
}
|
反射+动态代理代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
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包:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
< 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 >
|
二、自定义注解:
1
2
3
4
5
6
7
8
9
10
|
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 "" ;
}
|
三、定义切面:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
|
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;
}
}
|
四:测试前的准备内容:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
// 实体类
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( "测试注解..." );
}
}
|
五、测试类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
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" );
}
}
|
测试结果:
1
2
3
4
5
6
7
8
|
测试注解...
resourceId: 1
operationType:SAVE
description:测试注解传递复杂动态参数
测试注解...
resourceId: 666
operationType:UPDATE
description:测试注解传递简单动态参数
|
以上为个人经验,希望能给大家一个参考,也希望大家多多支持服务器之家。如有错误或未考虑完全的地方,望不吝赐教。
原文链接:https://blog.csdn.net/ltllml44/article/details/84305262