Springboot-JPA之AOP保存历史记录

摘要

  • 业务中有这么个需求,就是需要记录每条记录的历史,并要记录该记录变更的时间和操作人,即每条记录的新增、修改和删除都要记录

业务分析

  • 1.业务系统架构基于springboot,并采用springboot-jpa的方式处理数据

  • 2.业务系统中部分表设计之初并没有变更时间和操作人字段

  • 3.业务系统已经运行一段时间,很多功能已经开发完成,不适合采用侵入代码的形式进行修改

  • 4.系统并发量不大

解决方案

  • 基于对业务系统的分析,决定采用AOP的方式在每次记录变更的同时保存记录流水

  • 因为采用springboot-jpa的方式处理数据,所以可以将切入点设置在类似CrudRepository的修改记录的方法上

具体实现

  • DataHistoryAspect.java

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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
package com.hanqf.support;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hanqf.utils.CP_ClassUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
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.beans.factory.annotation.Autowired;

import javax.persistence.Id;
import javax.persistence.Table;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.StreamSupport;

/**
* <h1>历史数据保存拦截器</h1>
* Created by hanqf on 2022/9/20 16:11.
* <p>
* 说明:
* 1.以关系型数据库为例
* 2.所有Entity都要有唯一主键@Id
*/

@Aspect
@Slf4j
public class DataHistoryAspect {

/**
* 不需要保存历史数据的表
*/
private static final String[] IGNORE_TABLES = {"tbl_cp_logger"};

@Autowired
private ObjectMapper objectMapper;

/**
* 新增和修改
* CrudRepository 针对关系型数据库(mysql,oracle等),Mongo,ES等等
* JpaRepository 只针对关系型数据库(mysql,oracle等)
*/
/**
* CrudRepository
* <S extends T> S save(S entity);
*/
@Pointcut("execution(* com.hanqf.function..dao.*.save(..))")
public void savePointCut() {
}

/**
* JpaRepository
* <S extends T> S saveAndFlush(S entity);
*/
@Pointcut("execution(* com.hanqf.function..dao.*.saveAndFlush(..))")
public void saveAndFlushPointCut() {
}

/**
* JpaRepository
* <S extends T> List<S> saveAll(Iterable<S> entities);
*/
@Pointcut("execution(* com.hanqf.function..dao.*.saveAll(Iterable))")
public void saveAllPointCut() {
}

/**
* JpaRepository
* <S extends T> List<S> saveAllAndFlush(Iterable<S> entities);
*/
@Pointcut("execution(* com.hanqf.function..dao.*.saveAllAndFlush(Iterable))")
public void saveAllAndFlushPointCut() {
}

/**
* 删除
* CrudRepository 针对关系型数据库(mysql,oracle等),Mongo,ES等等
* JpaRepository 只针对关系型数据库(mysql,oracle等)
*/
/**
* CrudRepository
* void deleteById(ID id);
*/
@Pointcut("execution(* com.hanqf.function..dao.*.deleteById(..))")
public void deleteByIdPointCut() {
}

/**
* CrudRepository
* void deleteAllById(Iterable<? extends ID> ids);
*/
@Pointcut("execution(* com.hanqf.function..dao.*.deleteAllById(Iterable))")
public void deleteAllByIdPointCut() {
}

/**
* CrudRepository
* void deleteAll(Iterable<? extends T> entities);
*/
@Pointcut("execution(* com.hanqf.function..dao.*.deleteAll(Iterable))")
public void deleteAllIterablePointCut() {
}

/**
* CrudRepository
* void delete();
*/
@Pointcut("execution(* com.hanqf.function..dao.*.delete(..))")
public void deletePointCut() {
}

/**
* CrudRepository
* void deleteAll();
*/
@Pointcut("execution(* com.hanqf.function..dao.*.deleteAll())")
public void deleteAllPointCut() {
}

/**
* JpaRepository
* void deleteAllInBatch();
*/
@Pointcut("execution(* com.hanqf.function..dao.*.deleteAllInBatch())")
public void deleteAllInBatchPointCut() {
}

/**
* JpaRepository
* void deleteAllInBatch(Iterable<T> entities);
*/
@Pointcut("execution(* com.hanqf.function..dao.*.deleteAllInBatch(Iterable))")
public void deleteAllInBatchIterablePointCut() {
}

/**
* JpaRepository
* void deleteAllInBatch(Iterable<T> entities);
*/
@Pointcut("execution(* com.hanqf.function..dao.*.deleteAllByIdInBatch(Iterable))")
public void deleteAllByIdInBatchPointCut() {
}


@AfterReturning(value = "savePointCut() || saveAndFlushPointCut()", returning = "result")
public void saveAfterReturning(JoinPoint joinPoint, Object result) {
log.info("DataHistoryAspect afterReturning....");
try {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
final String methodName = method.getName();
Object model = result;
Class<?> modelClass = model.getClass();

//必须被@Table注解的类
final Table table = modelClass.getAnnotation(Table.class);

if (table != null && !ArrayUtils.contains(IGNORE_TABLES, table.name())) {
String dataId = String.valueOf(CP_ClassUtil.getFieldValue(model, CP_ClassUtil.getField(modelClass, Id.class)));
makeHistory(methodName, objectMapper.writeValueAsString(model), table.name(), dataId);
}

} catch (Exception e) {
e.printStackTrace();
}
}

@AfterReturning(value = "saveAllPointCut() || saveAllAndFlushPointCut()", returning = "result")
public void saveAllAfterReturning(JoinPoint joinPoint, List result) {
log.info("DataHistoryAspect saveAllAfterReturning....");
try {
final Class targetInterface = CP_ClassUtil.getProxyTargetInterface(joinPoint.getTarget(), 0);
final Class<?> modelClass = CP_ClassUtil.getTIClass(targetInterface, 0, 0);

MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
final String methodName = method.getName();

//必须被@Table注解的类
final Table table = modelClass.getAnnotation(Table.class);
if (table != null && !ArrayUtils.contains(IGNORE_TABLES, table.name())) {
result.stream().forEach(entity -> {
String dataId = String.valueOf(CP_ClassUtil.getFieldValue(entity, CP_ClassUtil.getField(modelClass, Id.class)));
try {
makeHistory(methodName, objectMapper.writeValueAsString(entity), table.name(), dataId);
} catch (JsonProcessingException e) {
throw new RuntimeException();
}
});
}
} catch (Exception e) {
e.printStackTrace();
}
}

@AfterReturning("(deleteAllIterablePointCut() || deleteAllInBatchIterablePointCut()) && args(entities)")
public void deleteAllIterablePointCut(JoinPoint joinPoint, Iterable entities) {
log.info("DataHistoryAspect deleteByIdAfterReturning....");
try {
final Class targetInterface = CP_ClassUtil.getProxyTargetInterface(joinPoint.getTarget(), 0);
final Class<?> modelClass = CP_ClassUtil.getTIClass(targetInterface, 0, 0);
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
final String methodName = method.getName();
if (modelClass != null) {
//必须被@Table注解的类
final Table table = modelClass.getAnnotation(Table.class);
if (table != null && !ArrayUtils.contains(IGNORE_TABLES, table.name())) {
StreamSupport.stream(entities.spliterator(), true)
.forEach(entity -> {
try {
String dataId = String.valueOf(CP_ClassUtil.getFieldValue(entity, CP_ClassUtil.getField(entity.getClass(), Id.class)));
makeHistory(methodName, objectMapper.writeValueAsString(entity), table.name(), dataId);
} catch (JsonProcessingException e) {
throw new RuntimeException();
}
});
}
}
} catch (Exception e) {
e.printStackTrace();
}
}

@AfterReturning("(deleteAllByIdPointCut() || deleteAllByIdInBatchPointCut()) && args(ids)")
public void deleteAllByIdPointCutAfterReturning(JoinPoint joinPoint, Iterable ids) {
log.info("DataHistoryAspect deleteAllByIdPointCutAfterReturning....");
try {
final Class targetInterface = CP_ClassUtil.getProxyTargetInterface(joinPoint.getTarget(), 0);
final Class<?> modelClass = CP_ClassUtil.getTIClass(targetInterface, 0, 0);

MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
final String methodName = method.getName();

if (modelClass != null) {
//必须被@Table注解的类
final Table table = modelClass.getAnnotation(Table.class);
if (table != null && !ArrayUtils.contains(IGNORE_TABLES, table.name())) {
StreamSupport.stream(ids.spliterator(), true)
.forEach(id -> makeHistory(methodName, String.valueOf(id), table.name(), String.valueOf(id)));
}
}
} catch (Exception e) {
e.printStackTrace();
}
}

@AfterReturning("deleteByIdPointCut() && args(id)")
public void deleteByIdAfterReturning(JoinPoint joinPoint, Object id) {
log.info("DataHistoryAspect deleteByIdAfterReturning....");
try {
final Class targetInterface = CP_ClassUtil.getProxyTargetInterface(joinPoint.getTarget(), 0);
final Class<?> modelClass = CP_ClassUtil.getTIClass(targetInterface, 0, 0);

MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
final String methodName = method.getName();

if (modelClass != null) {
//必须被@Table注解的类
final Table table = modelClass.getAnnotation(Table.class);
if (table != null && !ArrayUtils.contains(IGNORE_TABLES, table.name())) {
makeHistory(methodName, String.valueOf(id), table.name(), String.valueOf(id));
}
}
} catch (Exception e) {
e.printStackTrace();
}
}

@AfterReturning("deletePointCut() && args(entity)")
public void deleteAfterReturning(JoinPoint joinPoint, Object entity) {
log.info("DataHistoryAspect deleteAfterReturning....");
try {
final Class targetInterface = CP_ClassUtil.getProxyTargetInterface(joinPoint.getTarget(), 0);
final Class<?> modelClass = CP_ClassUtil.getTIClass(targetInterface, 0, 0);

MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
final String methodName = method.getName();

if (modelClass != null) {
//必须被@Table注解的类
final Table table = modelClass.getAnnotation(Table.class);
if (table != null && !ArrayUtils.contains(IGNORE_TABLES, table.name())) {
String dataId = String.valueOf(CP_ClassUtil.getFieldValue(entity, CP_ClassUtil.getField(modelClass, Id.class)));
makeHistory(methodName, objectMapper.writeValueAsString(entity), table.name(), dataId);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}

@AfterReturning("deleteAllPointCut() || deleteAllInBatchPointCut()")
public void deleteAllAfterReturning(JoinPoint joinPoint) {
log.info("DataHistoryAspect deleteAllAfterReturning....");
try {
final Class targetInterface = CP_ClassUtil.getProxyTargetInterface(joinPoint.getTarget(), 0);
final Class<?> modelClass = CP_ClassUtil.getTIClass(targetInterface, 0, 0);

MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
final String methodName = method.getName();

//必须被@Table注解的类
final Table table = modelClass.getAnnotation(Table.class);
if (table != null && !ArrayUtils.contains(IGNORE_TABLES, table.name())) {
makeHistory(methodName, "deleteAll", table.name(), null);
}
} catch (Exception e) {
e.printStackTrace();
}
}


/**
* 保存数据
* @param methodName 执行的方法名称
* @param data 操作的数据
* @param tableName 操作的表名称
* @param dataId 记录Id
*/
private void makeHistory(String methodName, String data, String tableName, String dataId) {
//TODO
//可以保存到文件,数据库或者ES
//此处可以保存操作人和操作时间
//一般来说获取操作人信息都会被封装为静态方法,比如基于SpringSecurity获取登录人信息,
//或者从request中获取操作人时也会通过前置拦截器将其封装到ThreadLocal<LoginUser>中,
//如果要在此处获取request对象,可以使用如下方法
//RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
//ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes)requestAttributes;
//HttpServletRequest request = servletRequestAttributes.getRequest();
}
}
  • 工具类CP_ClassUtil.java

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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
package com.hanqf.utils;

import org.springframework.aop.framework.AdvisedSupport;
import org.springframework.aop.framework.AopProxy;
import org.springframework.aop.support.AopUtils;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

/**
* <h1>类工具</h1>
* Created by hanqf on 2022/9/21 10:55.
*/


public class CP_ClassUtil {

/**
* 验证class是否存在
*/
public static boolean classIsAvailable(String className) {
Assert.notNull(className, "className must not be null");
boolean result;
try {
result = null != Class.forName(className);
} catch (Throwable t) {
result = false;
}
return result;
}

/**
* 判断类中是否包含指定的方法
*/
public static boolean hasMethod(Class clazz, String methodName, Class... argsType) {
Assert.notNull(clazz, "Class must not be null");
Assert.notNull(methodName, "methodName must not be null");
Method method = ReflectionUtils.findMethod(clazz, methodName, argsType);
if (null != method) {
return true;
}
return false;
}

/**
* 获取指定类的方法
*/
public static Method getMethod(Class clazz, String methodName, Class... argsType) {
Assert.notNull(clazz, "Class must not be null");
Assert.notNull(methodName, "methodName must not be null");
Method method = ReflectionUtils.findMethod(clazz, methodName, argsType);
if (null != method) {
return method;
}
return null;
}

/**
* 获取指定类的指定方法的返回类型
*/
public static Class getMethodReturnType(Class clazz, String methodName, Class... argsType) {
Assert.notNull(clazz, "Class must not be null");
Assert.notNull(methodName, "methodName must not be null");
Method method = ReflectionUtils.findMethod(clazz, methodName, argsType);
if (null != method) {
return method.getReturnType();
}
return null;
}

/**
* 判断类中是否包含指定的字段
*/
public static boolean hasField(Class clazz, String fieldName) {
Assert.notNull(clazz, "Class must not be null");
Assert.notNull(fieldName, "fieldName must not be null");
Field field = ReflectionUtils.findField(clazz, fieldName);
if (field != null) {
return true;
}
return false;
}

/**
* 获取类中指定的字段
*/
public static Field getField(Class clazz, String fieldName) {
Assert.notNull(clazz, "Class must not be null");
Assert.notNull(fieldName, "fieldName must not be null");
Field field = ReflectionUtils.findField(clazz, fieldName);
if (field != null) {
field.setAccessible(true);
return field;
}
return null;
}

/**
* 获取声明了某个注解的字段,这里只返回获取到的第一个字段
*/
public static Field getField(Class clazz, Class annotationClass) {
Assert.notNull(clazz, "Class must not be null");
Assert.notNull(annotationClass, "annotationClass must not be null");
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (field.getAnnotation(annotationClass) != null) {
field.setAccessible(true);
return field;
}
}
return null;
}

/**
* 获取声明了指定注解的全部字段
*/
public static Field[] getFields(Class clazz, Class annotationClass) {
Assert.notNull(clazz, "Class must not be null");
Assert.notNull(annotationClass, "annotationClass must not be null");
List<Field> annotationList = new ArrayList<>();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (field.getAnnotation(annotationClass) != null) {
field.setAccessible(true);
annotationList.add(field);
}
}
return annotationList.toArray(new Field[annotationList.size()]);
}

/**
* 获取字段的返回值
*/
public static Object getFieldValue(Class clazz, String fieldName) {
return getFieldValue(clazz, getField(clazz, fieldName));
}

public static Object getFieldValue(Object entity, Field field) {
Assert.notNull(entity, "entity must not be null");
Assert.notNull(field, "field must not be null");
try {
return field.get(entity);
} catch (IllegalAccessException e) {
return null;
}

}


/**
* <h2>获得定义当前`类`的类型时在其父类上的声明的泛型真实类型</h2>
* 示例:
* public class BookInfoGrap extends MustLoginGrap<BookInfoParam, BookInfoResult>
* 这里当前Class就是 BookInfoGrap.class
* 其父类上声明的泛型真实类型就是 0:BookInfoParam 1:BookInfoResult
*
* @param clazz 当前`类`的类型
* @param num 第一个泛型类型,从0开始算,如BookInfoParam就是第0个
* @return java.lang.Class 泛型真实类型
* @author hanqf
*/
public static Class getTClass(Class clazz, int num) {
Class tClass = null;
Type genericSuperclass = clazz.getGenericSuperclass();
if (!"java.lang.reflect.Proxy".equals(genericSuperclass.getTypeName())) {
//获取第二个泛型类型,这里是按实际需要,只需获取第二个泛型类型,这里就是获取<T extends BaseResult>的实际类型
Type actualTypeArgument = ((ParameterizedType) genericSuperclass).getActualTypeArguments()[num];
//判断T是否依旧包含泛型,如果包含泛型,则只取出外层类型
//这里因为为每个BaseResult都创建的实现类,而且其实现类都是不包含泛型的,所以不会执行这个逻辑
if (actualTypeArgument instanceof ParameterizedType) {
tClass = (Class) ((ParameterizedType) actualTypeArgument).getRawType();
} else {//直接返回BaseResult的实现类类型,
tClass = (Class) actualTypeArgument;
}
}
return tClass;
}

/**
* <h2>获得定义当前`类`或`接口`时在其父接口上的声明的泛型真实类型</h2>
* 示例:
* public interface BookInfoJpaRepository extends BaseJpaRepository<BookInfo, Long>
* 这里当前Interface就是 BookInfoJpaRepository.class
* 其父类上声明的泛型真实类型就是 0:BookInfo 1:Long
*
* @param clazz 当前`类`或`接口`的类型
* @param interfaceNum 要获取第几个接口,从0开始计算,如BaseJpaRepository就是第0个
* @param num 接口中第几个泛型类型,从0开始算,如BookInfo就是第0个
* @return java.lang.Class 泛型真实类型
* @author hanqf
*/
public static Class getTIClass(Class clazz, int interfaceNum, int num) {
Class tClass = null;
final Type[] genericInterfaces = clazz.getGenericInterfaces();
Type genericSuperclass = genericInterfaces[interfaceNum];
if (!"java.lang.reflect.Proxy".equals(genericSuperclass.getTypeName())) {
//获取第二个泛型类型,这里是按实际需要,只需获取第二个泛型类型,这里就是获取<T extends BaseResult>的实际类型
Type actualTypeArgument = ((ParameterizedType) genericSuperclass).getActualTypeArguments()[num];
//判断T是否依旧包含泛型,如果包含泛型,则只取出外层类型
//这里因为为每个BaseResult都创建的实现类,而且其实现类都是不包含泛型的,所以不会执行这个逻辑
if (actualTypeArgument instanceof ParameterizedType) {
tClass = (Class) ((ParameterizedType) actualTypeArgument).getRawType();
} else {//直接返回BaseResult的实现类类型,
tClass = (Class) actualTypeArgument;
}
}
return tClass;
}


/**
* 获取当前代理对象的真实目标对象,即实现类
*
* @param proxy 代理对象
* @return 目标对象
* @throws Exception
*/
public static Object getProxyTarget(Object proxy) throws Exception {
if (!AopUtils.isAopProxy(proxy)) {
return proxy;
}
//判断是jdk还是cglib代理
if (AopUtils.isJdkDynamicProxy(proxy)) {
proxy = getJdkDynamicProxyTargetObject(proxy);
} else {
proxy = getCglibProxyTargetObject(proxy);
}
return getProxyTarget(proxy);
}


/**
* 获取Cglib代理对象的真实目标对象,即实现类
*
* @param proxy 代理对象
* @return 目标对象
* @throws Exception
*/
private static Object getCglibProxyTargetObject(Object proxy) throws Exception {
Field h = proxy.getClass().getDeclaredField("CGLIB$CALLBACK_0");
h.setAccessible(true);
Object dynamicAdvisedInterceptor = h.get(proxy);
Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField("advised");
advised.setAccessible(true);
Object target = ((AdvisedSupport) advised.get(dynamicAdvisedInterceptor)).getTargetSource().getTarget();
return target;
}

/**
* 获取JdkDynamic代理对象的真实目标对象,即实现类
*
* @param proxy 代理对象
* @return 目标对象
* @throws Exception
*/
private static Object getJdkDynamicProxyTargetObject(Object proxy) throws Exception {
Field h = proxy.getClass().getSuperclass().getDeclaredField("h");
h.setAccessible(true);
AopProxy aopProxy = (AopProxy) h.get(proxy);
Field advised = aopProxy.getClass().getDeclaredField("advised");
advised.setAccessible(true);
Object target = ((AdvisedSupport) advised.get(aopProxy)).getTargetSource().getTarget();
return target;
}


/**
* <h2>获取当前代理对象的真实目标接口类型,即接口</h2>
*
* @param proxy proxy 代理对象
* @param num 第几个接口,从0开始计算
* @return java.lang.Class 接口类型
* @author hanqf
*/
public static Class getProxyTargetInterface(Object proxy, int num) throws Exception {
if (!AopUtils.isAopProxy(proxy)) {
return null;
}
//判断是jdk还是cglib代理
if (AopUtils.isJdkDynamicProxy(proxy)) {
return getJdkDynamicProxyTargetInterface(proxy, num);
} else {
return getCglibProxyTargetInterface(proxy, num);
}

}

/**
* 获取CGLIB动态代理对象的目标接口
*
* @param proxy 代理对象
* @param num 第几个接口
* @return 目标接口类型
*/
private static Class getCglibProxyTargetInterface(Object proxy, int num) throws Exception {
Field h = proxy.getClass().getDeclaredField("CGLIB$CALLBACK_0");
h.setAccessible(true);
Object dynamicAdvisedInterceptor = h.get(proxy);
Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField("advised");
advised.setAccessible(true);
final Class<?>[] proxiedInterfaces = ((AdvisedSupport) advised.get(dynamicAdvisedInterceptor)).getProxiedInterfaces();
return proxiedInterfaces[num];
}

/**
* 获取Jdk动态代理对象的目标接口
*
* @param proxy 代理对象
* @param num 第几个接口
* @return 目标接口类型
*/
private static Class getJdkDynamicProxyTargetInterface(Object proxy, int num) throws Exception {
Field h = proxy.getClass().getSuperclass().getDeclaredField("h");
h.setAccessible(true);
AopProxy aopProxy = (AopProxy) h.get(proxy);
Field advised = aopProxy.getClass().getDeclaredField("advised");
advised.setAccessible(true);
final Class<?>[] proxiedInterfaces = ((AdvisedSupport) advised.get(aopProxy)).getProxiedInterfaces();
return proxiedInterfaces[num];
}
}

后记