我这里有一个需求需要修改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