好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

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

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

查看更多关于如何动态修改JavaBean中注解的参数值的详细内容...

  阅读:21次