-
2021-03-04 09:44:35
本文整理匯總了Java中org.aspectj.lang.reflect.MethodSignature.getMethod方法的典型用法代碼示例。如果您正苦於以下問題:Java MethodSignature.getMethod方法的具體用法?Java MethodSignature.getMethod怎麽用?Java MethodSignature.getMethod使用的例子?那麽恭喜您, 這裏精選的方法代碼示例或許可以為您提供幫助。您也可以進一步了解該方法所在類org.aspectj.lang.reflect.MethodSignature的用法示例。
在下文中一共展示了MethodSignature.getMethod方法的20個代碼示例,這些例子默認根據受歡迎程度排序。您可以為喜歡或者感覺有用的代碼點讚,您的評價將有助於我們的係統推薦出更棒的Java代碼示例。
示例1: invoke
點讚 5
import org.aspectj.lang.reflect.MethodSignature; //導入方法依賴的package包/類
@Override
public Object invoke(String transactionGroupId, ProceedingJoinPoint point) throws Throwable {
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
Class> clazz = point.getTarget().getClass();
Object[] args = point.getArgs();
Method thisMethod = clazz.getMethod(method.getName(), method.getParameterTypes());
final String compensationId = CompensationLocal.getInstance().getCompensationId();
final TxTransaction txTransaction = method.getAnnotation(TxTransaction.class);
final int waitMaxTime = txTransaction.waitMaxTime();
final PropagationEnum propagation = txTransaction.propagation();
TransactionInvocation invocation = new TransactionInvocation(clazz, thisMethod.getName(), args, method.getParameterTypes());
TxTransactionInfo info = new TxTransactionInfo(invocation,transactionGroupId,compensationId,waitMaxTime,propagation);
final Class c = txTransactionFactoryService.factoryOf(info);
final TxTransactionHandler txTransactionHandler =
(TxTransactionHandler) SpringBeanUtils.getInstance().getBean(c);
return txTransactionHandler.handler(point, info);
}
開發者ID:yu199195,項目名稱:happylifeplat-transaction,代碼行數:24,
示例2: before
點讚 3
import org.aspectj.lang.reflect.MethodSignature; //導入方法依賴的package包/類
@Around("execution(org.springframework.web.servlet.ModelAndView org.gra4j.dataMigration.controller..*.*(..)) "
+ " and @annotation(org.springframework.web.bind.annotation.RequestMapping)")
public Object before(ProceedingJoinPoint pjp) throws Throwable {
// 從切點上獲取目標方法
MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
Method method = methodSignature.getMethod();
// 若目標方法忽略了安全性檢查,則直接調用目標方法
if (method.isAnnotationPresent(UnCheck.class))
return pjp.proceed();
if (StringUtils.isEmpty(tokenName))
tokenName = DEFAULT_TOKEN_NAME;
HttpServletRequest request = WebContext.getRequest();
HttpServletResponse response = WebContext.getResponse();
String token = tokenManager.createToken(
((SecurityContextImpl) request.getSession()
.getAttribute("SPRING_SECURITY_CONTEXT"))
.getAuthentication()
.getName());
response.addHeader(tokenName,token);
return pjp.proceed();
}
開發者ID:finefuture,項目名稱:data-migration,代碼行數:25,
示例3: execute
點讚 3
import org.aspectj.lang.reflect.MethodSignature; //導入方法依賴的package包/類
/**
* 接收到客戶端請求時執行
*
* @param pjp
* @return
* @throws Throwable
*/
@Around("controllerAspect()")
public Object execute(ProceedingJoinPoint pjp) throws Throwable {
// 從切點上獲取目標方法
MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
Method method = methodSignature.getMethod();
/**
* 驗證Token
*/
if (method.isAnnotationPresent(Token.class)) {
// 從 request header 中獲取當前 token
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String token = request.getHeader(DEFAULT_TOKEN_NAME);
if (StringUtils.isEmpty(token)) {
throw new TokenException("客戶端X-Token參數不能為空,且從Header中傳入,如果沒有登錄,請先登錄獲取Token");
}
// 檢查 token 有效性
if (!tokenManager.checkToken(token)) {
String message = String.format("Token [%s] 非法", token);
throw new TokenException(message);
}
}
// 調用目標方法
return pjp.proceed();
}
開發者ID:melonlee,項目名稱:LazyREST,代碼行數:33,
示例4: isLocalProceeder
點讚 3
import org.aspectj.lang.reflect.MethodSignature; //導入方法依賴的package包/類
/**
* @param method
* @return
true
if the given method has the same signature as* the currently aspectJ extension-overridden method
*/
static boolean isLocalProceeder(Method method)
{
if (!ajLocalProceedingJoinPoints.get().isEmpty())
{
ProceedingContext proceedingCotext = ajLocalProceedingJoinPoints.get().peek();
MethodSignature ms = (MethodSignature) proceedingCotext.proceedingJoinPoint.getSignature();
Method jpMethod = ms.getMethod();
return jpMethod.getName().endsWith(method.getName()) && Arrays.equals(jpMethod.getParameterTypes(),
method.getParameterTypes());
}
else
{
return false;
}
}
開發者ID:Alfresco,項目名稱:alfresco-repository,代碼行數:21,
示例5: interceptor
點讚 3
import org.aspectj.lang.reflect.MethodSignature; //導入方法依賴的package包/類
@Around("aspect()&&@annotation(anno)")
public Object interceptor(ProceedingJoinPoint invocation, CacheClear anno)
throws Throwable {
MethodSignature signature = (MethodSignature) invocation.getSignature();
Method method = signature.getMethod();
Class>[] parameterTypes = method.getParameterTypes();
Object[] arguments = invocation.getArgs();
String key = "";
if (StringUtils.isNotBlank(anno.key())) {
key = getKey(anno, anno.key(), CacheScope.application,
parameterTypes, arguments);
cacheAPI.remove(key);
} else if (StringUtils.isNotBlank(anno.pre())) {
key = getKey(anno, anno.pre(), CacheScope.application,
parameterTypes, arguments);
cacheAPI.removeByPre(key);
} else if (anno.keys().length > 1) {
for (String tmp : anno.keys()) {
tmp = getKey(anno, tmp, CacheScope.application, parameterTypes,
arguments);
cacheAPI.removeByPre(tmp);
}
}
return invocation.proceed();
}
開發者ID:wxiaoqi,項目名稱:ace-cache,代碼行數:26,
示例6: beforeTrans
點讚 2
import org.aspectj.lang.reflect.MethodSignature; //導入方法依賴的package包/類
public void beforeTrans(JoinPoint point) {
Signature signature = point.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
// 獲取目標類
Class> target = point.getTarget().getClass();
Method targetMethod = null;
try {
targetMethod = target.getMethod(method.getName(), method.getParameterTypes());
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
// 根據目標類方法中的注解,選擇數據源
if (targetMethod != null) {
Transactional transactional = targetMethod.getAnnotation(Transactional.class);
if (transactional != null) {
SpecifyDS specifyDSCls = target.getAnnotation(SpecifyDS.class);
SpecifyDS specifyDS = targetMethod.getAnnotation(SpecifyDS.class);
if (specifyDS != null) {
DataSourceHolder.setDataSource(specifyDS.value());
} else if (specifyDSCls != null) {
DataSourceHolder.setDataSource(specifyDSCls.value());
} else {
DataSourceHolder.setDataSource(defaultTransDb);
}
}
}
}
開發者ID:xiachuanshou,項目名稱:shop-manager,代碼行數:29,
示例7: invoke
點讚 2
import org.aspectj.lang.reflect.MethodSignature; //導入方法依賴的package包/類
public Object invoke(ProceedingJoinPoint pjp) throws Throwable {
boolean profilerSwitch = ProfilerSwitch.getInstance().isOpenProfilerTree();
if (!profilerSwitch) {
return pjp.proceed();
}
MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
String clazzName = pjp.getTarget().toString();
Method method = methodSignature.getMethod();
String methodName = this.getClassAndMethodName(clazzName, method);
if (null == methodName) {
return pjp.proceed();
}
try {
if (Profiler.getEntry() == null) {
Profiler.start(methodName);
} else {
Profiler.enter(methodName);
}
return pjp.proceed();
} catch (Throwable e) {
warnLog.warn("profiler " + methodName + " error");
throw e;
} finally {
Profiler.release();
//當root entry為狀態為release的時候,打印信息,並做reset操作
Profiler.Entry rootEntry = Profiler.getEntry();
if (rootEntry != null) {
if (rootEntry.isReleased()) {
long duration = rootEntry.getDuration();
if (duration > ProfilerSwitch.getInstance().getInvokeTimeout()) {
profilerLogger.info("\n" + Profiler.dump() + "\n");
metricsLogger.info("\n" + Profiler.metrics() + "\n");
}
Profiler.reset();
}
}
}
}
開發者ID:minotaursu,項目名稱:profilerAop,代碼行數:39,
示例8: begin
點讚 2
import org.aspectj.lang.reflect.MethodSignature; //導入方法依賴的package包/類
public MythTransaction begin(ProceedingJoinPoint point) {
LogUtil.debug(LOGGER, () -> "開始執行Myth分布式事務!start");
MythTransaction mythTransaction = getCurrentTransaction();
if (Objects.isNull(mythTransaction)) {
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
Class> clazz = point.getTarget().getClass();
mythTransaction = new MythTransaction();
mythTransaction.setStatus(MythStatusEnum.BEGIN.getCode());
mythTransaction.setRole(MythRoleEnum.START.getCode());
mythTransaction.setTargetClass(clazz.getName());
mythTransaction.setTargetMethod(method.getName());
}
//保存當前事務信息
coordinatorCommand.execute(new CoordinatorAction(CoordinatorActionEnum.SAVE, mythTransaction));
//當前事務保存到ThreadLocal
CURRENT.set(mythTransaction);
//設置tcc事務上下文,這個類會傳遞給遠端
MythTransactionContext context = new MythTransactionContext();
//設置事務id
context.setTransId(mythTransaction.getTransId());
//設置為發起者角色
context.setRole(MythRoleEnum.START.getCode());
TransactionContextLocal.getInstance().set(context);
return mythTransaction;
}
開發者ID:yu199195,項目名稱:myth,代碼行數:37,
示例9: retry
點讚 2
import org.aspectj.lang.reflect.MethodSignature; //導入方法依賴的package包/類
@Around("@annotation(com.wise.core.aop.annotation.RetriableTransaction)")
public Object retry(ProceedingJoinPoint pjp) throws Throwable {
MethodSignature signature = (MethodSignature) pjp.getSignature();
Method method = signature.getMethod();
RetriableTransaction annotation = method.getAnnotation(RetriableTransaction.class);
int maxAttempts = annotation.maxRetries();
int attemptCount = 0;
List> exceptions = Arrays.asList(annotation.retryFor());
Throwable failure = null;
TransactionStatus currentTransactionStatus = null;
String businessName = pjp.getTarget().toString();
businessName = businessName.substring(0, businessName.lastIndexOf("@")) + "." + method.getName();
do {
attemptCount++;
try {
DefaultTransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
transactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
currentTransactionStatus = transactionManager.getTransaction(transactionDefinition);
Object returnValue = pjp.proceed();
transactionManager.commit(currentTransactionStatus);
return returnValue;
} catch (Throwable t) {
if (!exceptions.contains(t.getClass())) {
throw t;
}
if (currentTransactionStatus != null && !currentTransactionStatus.isCompleted()) {
transactionManager.rollback(currentTransactionStatus);
failure = t;
}
LOGGER.debug("事務重試:["+businessName+":"+attemptCount+"/"+maxAttempts+"]");
}
} while (attemptCount < maxAttempts);
LOGGER.debug("事務重試:["+businessName+":已達最大重試次數]");
throw failure;
}
示例10: getControllerMethodDescriptionInfo
點讚 2
import org.aspectj.lang.reflect.MethodSignature; //導入方法依賴的package包/類
/**
* 獲取注解中對方法的描述信息 用於Controller層注解
*
* @param joinPoint 切點
* @return discription
*/
public static String getControllerMethodDescriptionInfo(JoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
SystemControllerLog controllerLog = method
.getAnnotation(SystemControllerLog.class);
String discription = controllerLog.description();
return discription;
}
開發者ID:ranji1221,項目名稱:lemcloud,代碼行數:15,
示例11: saveSysLog
點讚 2
import org.aspectj.lang.reflect.MethodSignature; //導入方法依賴的package包/類
@Before("logPointCut()")
public void saveSysLog(JoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
SysLogEntity sysLog = new SysLogEntity();
SysLog syslog = method.getAnnotation(SysLog.class);
if(syslog != null){
//注解上的描述
sysLog.setOperation(syslog.value());
}
//請求的方法名
String className = joinPoint.getTarget().getClass().getName();
String methodName = signature.getName();
sysLog.setMethod(className + "." + methodName + "()");
//請求的參數
Object[] args = joinPoint.getArgs();
String params = new Gson().toJson(args[0]);
sysLog.setParams(params);
//獲取request
HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
//設置IP地址
sysLog.setIp(IPUtils.getIpAddr(request));
//用戶名
String username = ((SysUserEntity) SecurityUtils.getSubject().getPrincipal()).getUsername();
sysLog.setUsername(username);
sysLog.setCreateDate(new Date());
//保存係統日誌
sysLogService.save(sysLog);
}
開發者ID:zhaoqicheng,項目名稱:renren-fast,代碼行數:36,
示例12: prefsMethod
點讚 2
import org.aspectj.lang.reflect.MethodSignature; //導入方法依賴的package包/類
private Object prefsMethod(final ProceedingJoinPoint joinPoint) throws Throwable {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
Prefs prefs = method.getAnnotation(Prefs.class);
Object result = null;
if (prefs!=null) {
String key = prefs.key();
result = joinPoint.proceed();
String type = ((MethodSignature) joinPoint.getSignature()).getReturnType().toString();
if (!"void".equalsIgnoreCase(type)) {
String className = ((MethodSignature) joinPoint.getSignature()).getReturnType().getCanonicalName();
AppPrefs appPrefs = AppPrefs.get(Utils.getContext());
if ("int".equals(className) || "java.lang.Integer".equals(className)) {
appPrefs.putInt(key, (Integer) result);
} else if ("boolean".equals(className) || "java.lang.Boolean".equals(className)) {
appPrefs.putBoolean(key,(Boolean) result);
} else if ("float".equals(className) || "java.lang.Float".equals(className)) {
appPrefs.putFloat(key,(Float) result);
} else if ("long".equals(className) || "java.lang.Long".equals(className)) {
appPrefs.putLong(key,(Long) result);
} else if ("java.lang.String".equals(className)) {
appPrefs.putString(key,(String) result);
} else {
appPrefs.putObject(key,result);
}
}
} else {
// 不影響原來的流程
result = joinPoint.proceed();
}
return result;
}
開發者ID:fengzhizi715,項目名稱:SAF-AOP,代碼行數:38,
示例13: getAnnotation
點讚 2
import org.aspectj.lang.reflect.MethodSignature; //導入方法依賴的package包/類
private LimitIPRequestAnnotation getAnnotation(JoinPoint joinPoint) {
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
if (method != null) {
return method.getAnnotation(LimitIPRequestAnnotation.class);
}
return null;
}
開發者ID:numsg,項目名稱:spring-boot-seed,代碼行數:11,
示例14: doBeforeController
點讚 2
import org.aspectj.lang.reflect.MethodSignature; //導入方法依賴的package包/類
/**
* 前置通知
*/
@Before("log()")
public void doBeforeController(JoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
Action action = method.getAnnotation(Action.class);
System.out.println("action名稱 " + action.value()); // ⑤
}
開發者ID:longjiazuo,項目名稱:springBoot-project,代碼行數:11,
示例15: before
點讚 2
import org.aspectj.lang.reflect.MethodSignature; //導入方法依賴的package包/類
@Around("controllerMethodPointcut()")
public Object before(ProceedingJoinPoint pjp) {
long beginTime = System.currentTimeMillis();
MethodSignature signature = (MethodSignature) pjp.getSignature();
Method method = signature.getMethod(); //獲取被攔截的方法
String methodName = method.getName(); //獲取被攔截的方法名
logger.info("請求開始,方法:{}", methodName);
Object result = null;
Object[] args = pjp.getArgs();
for(Object arg : args){
logger.info(arg.toString());
}
try {
result = pjp.proceed();
} catch (Throwable e) {
logger.info("exception: ", e);
}
long costMs = System.currentTimeMillis() - beginTime;
logger.info("{}請求結束,耗時:{}ms", methodName, costMs);
return result;
}
開發者ID:hutou-workhouse,項目名稱:miscroServiceHello,代碼行數:28,
示例16: doAround
點讚 2
import org.aspectj.lang.reflect.MethodSignature; //導入方法依賴的package包/類
@Around("execution(* *..controller..*.*(..))")
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
// 獲取request
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
HttpServletRequest request = servletRequestAttributes.getRequest();
UpmsLog upmsLog = new UpmsLog();
// 從注解中獲取操作名稱、獲取響應結果
Object result = pjp.proceed();
Signature signature = pjp.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
if (method.isAnnotationPresent(ApiOperation.class)) {
ApiOperation log = method.getAnnotation(ApiOperation.class);
upmsLog.setDescription(log.value());
}
if (method.isAnnotationPresent(RequiresPermissions.class)) {
RequiresPermissions requiresPermissions = method.getAnnotation(RequiresPermissions.class);
String[] permissions = requiresPermissions.value();
if (permissions.length > 0) {
upmsLog.setPermissions(permissions[0]);
}
}
endTime = System.currentTimeMillis();
LOGGER.debug("doAround>>>result={},耗時:{}", result, endTime - startTime);
upmsLog.setBasePath(RequestUtil.getBasePath(request));
upmsLog.setIp(RequestUtil.getIpAddr(request));
upmsLog.setMethod(request.getMethod());
if ("GET".equalsIgnoreCase(request.getMethod())) {
upmsLog.setParameter(request.getQueryString());
} else {
upmsLog.setParameter(ObjectUtils.toString(request.getParameterMap()));
}
upmsLog.setResult(JSON.toJSONString(result));
upmsLog.setSpendTime((int) (endTime - startTime));
upmsLog.setStartTime(startTime);
upmsLog.setUri(request.getRequestURI());
upmsLog.setUrl(ObjectUtils.toString(request.getRequestURL()));
upmsLog.setUserAgent(request.getHeader("User-Agent"));
upmsLog.setUsername(ObjectUtils.toString(request.getUserPrincipal()));
upmsApiService.insertUpmsLogSelective(upmsLog);
return result;
}
開發者ID:ChangyiHuang,項目名稱:shuzheng,代碼行數:46,
示例17: getMethodByClassAndName
點讚 2
import org.aspectj.lang.reflect.MethodSignature; //導入方法依賴的package包/類
/**
* 根據類和方法名得到方法
*/
private Method getMethodByClassAndName(ProceedingJoinPoint joinPoint) {
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
return methodSignature.getMethod();
}
開發者ID:wxz1211,項目名稱:dooo,代碼行數:9,
示例18: doAround
點讚 2
import org.aspectj.lang.reflect.MethodSignature; //導入方法依賴的package包/類
@Around("execution(* *..controller..*.*(..))")
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
// 獲取request
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
HttpServletRequest request = servletRequestAttributes.getRequest();
SysLog log=new SysLog();
// 從注解中獲取操作名稱、獲取響應結果
Object result = pjp.proceed();
Signature signature = pjp.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
log.setTitle("未知");
if (method.isAnnotationPresent(ApiOperation.class)) {
ApiOperation logA = method.getAnnotation(ApiOperation.class);
log.setTitle(logA.value());
}
//if (method.isAnnotationPresent(RequiresPermissions.class)) {
//RequiresPermissions requiresPermissions = method.getAnnotation(RequiresPermissions.class);
//String[] permissions = requiresPermissions.value();
//if (permissions.length > 0) {
//upmsLog.setPermissions(permissions[0]);
//}
//}
LogUtils.saveLog(request,log);
endTime = System.currentTimeMillis();
_log.debug("doAround>>>result={},耗時:{}", result, endTime - startTime);
//upmsLog.setBasePath(RequestUtil.getBasePath(request));
//upmsLog.setIp(RequestUtil.getIpAddr(request));
//upmsLog.setMethod(request.getMethod());
//if (request.getMethod().equalsIgnoreCase("GET")) {
//upmsLog.setParameter(request.getQueryString());
//} else {
//upmsLog.setParameter(ObjectUtils.toString(request.getParameterMap()));
//}
//upmsLog.setLogId(StringUtil.guid());
//upmsLog.setResult(ObjectUtils.toString(result));
//upmsLog.setSpendTime((int) (endTime - startTime));
//upmsLog.setStartTime(startTime);
//upmsLog.setUri(request.getRequestURI());
//upmsLog.setUrl(ObjectUtils.toString(request.getRequestURL()));
//upmsLog.setUserAgent(request.getHeader("User-Agent"));
//upmsLog.setUsername(ObjectUtils.toString(request.getUserPrincipal()));
//upmsApiService.insertUpmsLogSelective(upmsLog);
return result;
}
開發者ID:egojit8,項目名稱:easyweb,代碼行數:50,
示例19: getMethod
點讚 2
import org.aspectj.lang.reflect.MethodSignature; //導入方法依賴的package包/類
private static Method getMethod(ProceedingJoinPoint pjp, Object object) {
MethodSignature signature = (MethodSignature) pjp.getSignature();
Method method = signature.getMethod();
return ReflectionUtils
.findMethod(object.getClass(), method.getName(), method.getParameterTypes());
}
開發者ID:opentracing-contrib,項目名稱:java-spring-cloud,代碼行數:7,
示例20: registerParticipant
點讚 1
import org.aspectj.lang.reflect.MethodSignature; //導入方法依賴的package包/類
/**
* 獲取調用接口的協調方法並封裝
*
* @param point 切點
*/
private void registerParticipant(ProceedingJoinPoint point, String transId) throws NoSuchMethodException {
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
Class> clazz = point.getTarget().getClass();
Object[] args = point.getArgs();
final Tcc tcc = method.getAnnotation(Tcc.class);
//獲取協調方法
String confirmMethodName = tcc.confirmMethod();
String cancelMethodName = tcc.cancelMethod();
//設置模式
final TccPatternEnum pattern = tcc.pattern();
tccTransactionManager.getCurrentTransaction().setPattern(pattern.getCode());
TccInvocation confirmInvocation = null;
if (StringUtils.isNoneBlank(confirmMethodName)) {
confirmInvocation = new TccInvocation(clazz,
confirmMethodName, method.getParameterTypes(), args);
}
TccInvocation cancelInvocation = null;
if (StringUtils.isNoneBlank(cancelMethodName)) {
cancelInvocation = new TccInvocation(clazz,
cancelMethodName,
method.getParameterTypes(), args);
}
//封裝調用點
final Participant participant = new Participant(
transId,
confirmInvocation,
cancelInvocation);
tccTransactionManager.enlistParticipant(participant);
}
開發者ID:yu199195,項目名稱:happylifeplat-tcc,代碼行數:51,
注:本文中的org.aspectj.lang.reflect.MethodSignature.getMethod方法示例整理自Github/MSDocs等源碼及文檔管理平台,相關代碼片段篩選自各路編程大神貢獻的開源項目,源碼版權歸原作者所有,傳播和使用請參考對應項目的License;未經允許,請勿轉載。
更多相关内容 -
Spring 5 MethodParameter 源码注释
2020-09-05 15:12:55* Helper class that encapsulates the specification of a method parameter, i.e. a {@link Method} * or {@link Constructor} plus a parameter index and a nested type index for a declared generic * type.../** * Helper class that encapsulates the specification of a method parameter, i.e. a {@link Method} * or {@link Constructor} plus a parameter index and a nested type index for a declared generic * type. Useful as a specification object to pass along. * <p> * 封装方法参数说明的帮助类,即一个{@link Method} 或者{@link Constructor}以及已声明的泛型类型 * 的参数索引和嵌套类型索引。用作传递的规范对象 * </p> * <p>As of 4.2, there is a {@link org.springframework.core.annotation.SynthesizingMethodParameter} * subclass available which synthesizes annotations with attribute aliases. That subclass is used * for web and message endpoint processing, in particular. * <p> * 从4.2起,有一个{@link org.springframework.core.annotation.SynthesizingMethodParameter}子类, * 可以使用属性别名来合成注解。该子类尤其是用于web和消息终结点处理。 * </p> * @author Juergen Hoeller * @author Rob Harrop * @author Andy Clement * @author Sam Brannen * @author Sebastien Deleuze * @author Phillip Webb * @since 2.0 * @see org.springframework.core.annotation.SynthesizingMethodParameter */ public class MethodParameter { /** * 空注解数组 */ private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0]; /** * 当前Method或构造函数对象 * <p>Executable类是Method和Constructor的父类,一个抽象类,直接继承AccessibleObject类,并实现Membet与GenericDeclaration接口, * 主要作用是实现类型变量的相关操作以及展示方法的信息。</p> * */ private final Executable executable; /** * 通过检查后的参数索引 */ private final int parameterIndex; /** * 当前方法/构造函数 {@link #parameterIndex} 位置的参数 */ @Nullable private volatile Parameter parameter; /** * 目标类型的嵌套等级(通常为1;比如,在列表的列表的情况下,则1表示嵌套列表,而2表示嵌套列表的元素) */ private int nestingLevel; /** Map from Integer level to Integer type index.<p>从整数嵌套等级到整数类型索引的映射</p> */ @Nullable Map<Integer, Integer> typeIndexesPerLevel; /** * The containing class. Could also be supplied by overriding {@link #getContainingClass()} * <p>包含的类。也可以通过覆盖{@link #getContainingClass()}来提供</p> * */ @Nullable private volatile Class<?> containingClass; /** * 当前参数类型 */ @Nullable private volatile Class<?> parameterType; /** * 当前泛型参数类型 */ @Nullable private volatile Type genericParameterType; /** * 当前参数的注解 */ @Nullable private volatile Annotation[] parameterAnnotations; /** * 用于发现方法和构造函数的参数名的发现器 */ @Nullable private volatile ParameterNameDiscoverer parameterNameDiscoverer; /** * 当前参数名 */ @Nullable private volatile String parameterName; /** * 内嵌的方法参数 */ @Nullable private volatile MethodParameter nestedMethodParameter; /** * Create a new {@code MethodParameter} for the given method, with nesting level 1. * <p>使用嵌套级别1为给定方法创建一个新的{@code MethodParameter}</p> * @param method the Method to specify a parameter for * -- 指定参数的方法 * @param parameterIndex the index of the parameter: -1 for the method * return type; 0 for the first method parameter; 1 for the second method * parameter, etc. * -- 参数的索引位置:-1表示方法的返回类型;0表示第一个方法参数; * 1表示第二个方法参数,以此类推 */ public MethodParameter(Method method, int parameterIndex) { this(method, parameterIndex, 1); } /** * Create a new {@code MethodParameter} for the given method. * <p>使用嵌套级别1为给定方法创建一个新的{@code MethodParameter}</p> * @param method the Method to specify a parameter for -- 指定参数的方法 * @param parameterIndex the index of the parameter: -1 for the method * return type; 0 for the first method parameter; 1 for the second method * parameter, etc. * -- 参数的索引位置:-1表示方法的返回类型;0表示第一个方法参数; * 1表示第二个方法参数,以此类推 * @param nestingLevel the nesting level of the target type * (typically 1; e.g. in case of a List of Lists, 1 would indicate the * nested List, whereas 2 would indicate the element of the nested List) * -- 目标类型的嵌套等级(通常为1;比如,在列表的列表的情况下, * 则1表示嵌套列表,而2表示嵌套列表的元素) */ public MethodParameter(Method method, int parameterIndex, int nestingLevel) { //如果方法为null,抛出异常 Assert.notNull(method, "Method must not be null"); this.executable = method; //将通过检查后的parameterIndex赋值给parameterIndex this.parameterIndex = validateIndex(method, parameterIndex); this.nestingLevel = nestingLevel; } /** * Create a new MethodParameter for the given constructor, with nesting level 1. * <p>使用嵌套级别1为给定构造函数创建一个新的{@code MethodParameter}</p> * @param constructor the Constructor to specify a parameter for -- 指定参数的构造函数 * @param parameterIndex the index of the parameter -- 参数索引 */ public MethodParameter(Constructor<?> constructor, int parameterIndex) { this(constructor, parameterIndex, 1); } /** * Create a new MethodParameter for the given constructor. * <p>使用嵌套级别1为给定构造函数创建一个新的{@code MethodParameter}</p> * @param constructor the Constructor to specify a parameter for -- 指定参数的构造函数 * @param parameterIndex the index of the parameter -- 参数索引 * @param nestingLevel the nesting level of the target type * (typically 1; e.g. in case of a List of Lists, 1 would indicate the * nested List, whereas 2 would indicate the element of the nested List) * -- 目标类型的嵌套等级(通常为1;比如,在列表的列表的情况下, * 则1表示嵌套列表,而2表示嵌套列表的元素) */ public MethodParameter(Constructor<?> constructor, int parameterIndex, int nestingLevel) { //如果方法为null,抛出异常 Assert.notNull(constructor, "Constructor must not be null"); this.executable = constructor; //将通过检查后的parameterIndex赋值给parameterIndex this.parameterIndex = validateIndex(constructor, parameterIndex); this.nestingLevel = nestingLevel; } /** * Internal constructor used to create a {@link MethodParameter} with a * containing class already set. * <p>内部构造函数,用于创建带有已设置的类的{@link MethodParameter}</p> * @param executable the Executable to specify a parameter for * -- 可执行程序以指定参数 * @param parameterIndex the index of the parameter -- 参数索引 * @param containingClass the containing class -- 包含类 * @since 5.2 */ MethodParameter(Executable executable, int parameterIndex, @Nullable Class<?> containingClass) { //如果方法为null,抛出异常 Assert.notNull(executable, "Executable must not be null"); this.executable = executable; //将通过检查后的parameterIndex赋值给parameterIndex this.parameterIndex = validateIndex(executable, parameterIndex); this.nestingLevel = 1; this.containingClass = containingClass; } /** * Copy constructor, resulting in an independent MethodParameter object * based on the same metadata and cache state that the original object was in. * <p> * 赋值构造函数,根据与原始对象相同的元数据和缓存状态,生成一个独立 * 的MethodParameter对象 * </p> * @param original the original MethodParameter object to copy from * -- 要复制的原始MethodParameter对象 */ public MethodParameter(MethodParameter original) { //如果original为null,抛出异常 Assert.notNull(original, "Original must not be null"); this.executable = original.executable; this.parameterIndex = original.parameterIndex; this.parameter = original.parameter; this.nestingLevel = original.nestingLevel; this.typeIndexesPerLevel = original.typeIndexesPerLevel; this.containingClass = original.containingClass; this.parameterType = original.parameterType; this.genericParameterType = original.genericParameterType; this.parameterAnnotations = original.parameterAnnotations; this.parameterNameDiscoverer = original.parameterNameDiscoverer; this.parameterName = original.parameterName; } /** * Return the wrapped Method, if any. * <p>返回包装的方法,如果有</p> * <p>Note: Either Method or Constructor is available. * <p>注意:方法或构造函数均可用</p> * @return the Method, or {@code null} if none -- 方法对象,如果没有就返回null */ @Nullable public Method getMethod() { //如果executable是Method的子类或者本身就强转executable类型为Method再返回出去,否则返回null return (this.executable instanceof Method ? (Method) this.executable : null); } /** * Return the wrapped Constructor, if any. * <p>返回包装的构造函数,如果有</p> * <p>Note: Either Method or Constructor is available. * <p>注意:方法或构造函数均可用</p> * @return the Constructor, or {@code null} if none -- 构造函数对象,如果没有就返回null */ @Nullable public Constructor<?> getConstructor() { //如果executable是Constructor的子类或者本身就强转executable类型为Method再返回出去,否则返回null return (this.executable instanceof Constructor ? (Constructor<?>) this.executable : null); } /** * Return the class that declares the underlying Method or Constructor. * <p>返回声明底层方法或者构造函数的类</p> */ public Class<?> getDeclaringClass() { //获取声明该executable的类型并返回 return this.executable.getDeclaringClass(); } /** * Return the wrapped member. * <p>返回包装的成员</p> * @return the Method or Constructor as Member -- 方法或构造函数作为成员 */ public Member getMember() { return this.executable; } /** * Return the wrapped annotated element. * <p>返回包装的注解元素</p> * <p>Note: This method exposes the annotations declared on the method/constructor * itself (i.e. at the method/constructor level, not at the parameter level). * <p>注意:此方法公开在方法/构造函数本身上声明的注解(即,在方法/构造函数级别, * 而不是参数级别)</p> * @return the Method or Constructor as AnnotatedElement * -- 方法或构造函数作为成员 */ public AnnotatedElement getAnnotatedElement() { return this.executable; } /** * Return the wrapped executable. * <p>返回包装的可执行程序</p> * @return the Method or Constructor as Executable -- 方法或构造函数作为可执行程序 * @since 5.0 */ public Executable getExecutable() { return this.executable; } /** * Return the {@link Parameter} descriptor for method/constructor parameter. * <p>返回方法或构造函数参数的{@link Parameter}描述符</p> * @since 5.0 */ public Parameter getParameter() { //如果参数索引小于0 if (this.parameterIndex < 0) { //抛出异常,说明无法检索方法返回类型的参数描述符 throw new IllegalStateException("Cannot retrieve Parameter descriptor for method return type"); } Parameter parameter = this.parameter; //如果当前参数为null if (parameter == null) { //获取可执行程序的的第parameterIndex个参数 parameter = getExecutable().getParameters()[this.parameterIndex]; //设置当前参数 this.parameter = parameter; } //返回反射 return parameter; } /** * Return the index of the method/constructor parameter. * <p>返回方法/构造函数参数的索引</p> * @return the parameter index (-1 in case of the return type) * -- 参数索引(如果是返回类型,则为-1) */ public int getParameterIndex() { return this.parameterIndex; } /** * Increase this parameter's nesting level. * <p>增加参数的嵌套等级</p> * @see #getNestingLevel() * @deprecated since 5.2 in favor of {@link #nested(Integer)} -- 从5.2开始支持{@link #nested(Integer)} */ @Deprecated public void increaseNestingLevel() { this.nestingLevel++; } /** * Decrease this parameter's nesting level. * <p>降低此参数的嵌套等级</p> * @see #getNestingLevel() * @deprecated since 5.2 in favor of retaining the original MethodParameter and * using {@link #nested(Integer)} if nesting is required * -- 从5.2开始,建议保留MethodParameter,如果需要嵌套,则使用{@link #nested(Integer)} */ @Deprecated public void decreaseNestingLevel() { //移除从整数嵌套等级到整数类型索引的映射关系 getTypeIndexesPerLevel().remove(this.nestingLevel); //嵌套等级-1 this.nestingLevel--; } /** * Return the nesting level of the target type * (typically 1; e.g. in case of a List of Lists, 1 would indicate the * nested List, whereas 2 would indicate the element of the nested List). * <p>返回目标类型的嵌套等级(通常为1;比如,在列表的列表的情况下, * 则1表示嵌套列表,而2表示嵌套列表的元素))</p> */ public int getNestingLevel() { return this.nestingLevel; } /** * Return a variant of this {@code MethodParameter} with the type * for the current level set to the specified value. * <p> * 返回此{@code MethodParameter}的变体,类型为当前级别设置的指定值 * </p> * @param typeIndex the new type index -- 新的类型索引 * @since 5.2 */ public MethodParameter withTypeIndex(int typeIndex) { return nested(this.nestingLevel, typeIndex); } /** * Set the type index for the current nesting level. * <p>设置当前嵌套等级的类型索引</p> * @param typeIndex the corresponding type index * (or {@code null} for the default type index) * -- 对应的类型索引(或默认类型索引为{@code null}) * @see #getNestingLevel() * @deprecated since 5.2 in favor of {@link #withTypeIndex} -- 从5.2开始支持{@link #withTypeIndex(int)} */ @Deprecated public void setTypeIndexForCurrentLevel(int typeIndex) { //将嵌套等级和类型索引添加到typeIndexPerLevel中 getTypeIndexesPerLevel().put(this.nestingLevel, typeIndex); } /** * Return the type index for the current nesting level. * <p>返回当前嵌套等级的类型索引</p> * @return the corresponding type index, or {@code null} * if none specified (indicating the default type index) * -- 对应的类型索引(或默认类型索引为{@code null}) * @see #getNestingLevel() */ @Nullable public Integer getTypeIndexForCurrentLevel() { //从typeIndexPerLevel中获取当前nestingLevel对应的类型索引 return getTypeIndexForLevel(this.nestingLevel); } /** * Return the type index for the specified nesting level. * <p>返回指定嵌套等级的类型索引</p> * @param nestingLevel the nesting level to check -- 要检查的嵌套等级 * @return the corresponding type index, or {@code null} * if none specified (indicating the default type index) * -- 对应的类型索引(或默认类型索引为{@code null}) */ @Nullable public Integer getTypeIndexForLevel(int nestingLevel) { //从typeIndexPerLevel中获取传入的nestingLevel对应的类型索引 return getTypeIndexesPerLevel().get(nestingLevel); } /** * Obtain the (lazily constructed) type-indexes-per-level Map. * <p>获取(延迟构造的) 从整数嵌套等级到整数类型索引的映射</p> */ private Map<Integer, Integer> getTypeIndexesPerLevel() { //如果tyepIndexsPerLevel为null if (this.typeIndexesPerLevel == null) { //初始化typeIndexesPerLevel,容量为4 this.typeIndexesPerLevel = new HashMap<>(4); } //从整数嵌套等级到整数类型索引的映射 return this.typeIndexesPerLevel; } /** * Return a variant of this {@code MethodParameter} which points to the * same parameter but one nesting level deeper. * <p>返回此{@code MethodParameter}的变体,它指向同一个参数,但嵌套层次更深</p> * @since 4.3 */ public MethodParameter nested() { return nested(null); } /** * Return a variant of this {@code MethodParameter} which points to the * same parameter but one nesting level deeper. * <p>返回此{@code MethodParameter}的变体,它指向同一个参数,但嵌套层次更深</p> * @param typeIndex the type index for the new nesting level * --新嵌套等级的类型索引 * @since 5.2 */ public MethodParameter nested(@Nullable Integer typeIndex) { //获取当前嵌套MethodParameter MethodParameter nestedParam = this.nestedMethodParameter; //如果nestedParam不为null 且 类型索引为null if (nestedParam != null && typeIndex == null) { //返回嵌套的MethodParameter return nestedParam; } //获取嵌套等级多1级的MethodParameter nestedParam = nested(this.nestingLevel + 1, typeIndex); //如果类型索引为null if (typeIndex == null) { //设置当前嵌套MethodParametr this.nestedMethodParameter = nestedParam; } //返回嵌套等级多1级嵌套的MethodParameter return nestedParam; } /** * <p>返回此{@code MethodParameter}的变体,它指向给定嵌套等级,以及给定的类型索引</p> * @param nestingLevel 嵌套等级 * @param typeIndex 类型索引 * @return 返回此{@code MethodParameter}的变体,它指向给定嵌套等级,以及给定的类型索引 */ private MethodParameter nested(int nestingLevel, @Nullable Integer typeIndex) { //克隆当前类对象得到一份副本进行操作 MethodParameter copy = clone(); //设置嵌套等级为nestinglevel copy.nestingLevel = nestingLevel; //如果 从整数嵌套等级到整数类型索引的映射 不为null if (this.typeIndexesPerLevel != null) { //设置一个从整数嵌套等级到整数类型索引的映射 copy.typeIndexesPerLevel = new HashMap<>(this.typeIndexesPerLevel); } //如果类型索引不为null if (typeIndex != null) { //将嵌套等级和类型索引添加的哦typeIndexPerLevel中 copy.getTypeIndexesPerLevel().put(copy.nestingLevel, typeIndex); } //设置副本的当前参数类型为null copy.parameterType = null; //设置副本的通用参数类型为null copy.genericParameterType = null; //返回修整好的副本 return copy; } /** * Return whether this method indicates a parameter which is not required: * either in the form of Java 8's {@link java.util.Optional}, any variant * of a parameter-level {@code Nullable} annotation (such as from JSR-305 * or the FindBugs set of annotations), or a language-level nullable type * declaration in Kotlin. * <p> * 返回此方法是否表明不需要参数:以Java8的{@link java.util.Optional}形式, * 参数级{@code Nullable}注解的任何变体(例如来自JSR-305或FindBugs注释集), * 或者Kotlin中的语言集可为null的类型声明。 * </p> * @since 4.3 */ public boolean isOptional() { //如果当前参数索引的参数类型为Optional类 或者 此方法的参数注解是否带有Nullable注解的任何变体 // 或者 (存在Kotlin反射 且 当前包含类是Kotlin类型(上面带有Kotlin元数据) 且 ) return (getParameterType() == Optional.class || hasNullableAnnotation() || (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(getContainingClass()) && KotlinDelegate.isOptional(this))); } /** * Check whether this method parameter is annotated with any variant of a * {@code Nullable} annotation, e.g. {@code javax.annotation.Nullable} or * {@code edu.umd.cs.findbugs.annotations.Nullable}. * <p> * 检查此方法的参数注解是否带有{@code Nullable}注解的任何变体,比如: * {@code javax.annotation.Nullable} 或者 {@code edu.umd.cs.findbugs.annotations.Nullable}. * </p> */ private boolean hasNullableAnnotation() { //遍历返回与指定(当前)method/constructor参数关联的注解数组 for (Annotation ann : getParameterAnnotations()) { //如果ann的简单注解类型名为'Nullable' if ("Nullable".equals(ann.annotationType().getSimpleName())) { //返回true,表示此方法的参数注解带有{@code Nullable}注解的任何变体 return true; } } //执行到这里,表示在当前参数的注解数组没有找到带有{@code Nullable}注解的任何变体 return false; } /** * Return a variant of this {@code MethodParameter} which points to * the same parameter but one nesting level deeper in case of a * {@link java.util.Optional} declaration. * <p>返回{@code MethodParameter}的变体,该变体执行同一个参数但是在 * 声明{@link java.util.Optional}的情况下,嵌套级别更深</p> * @since 4.3 * @see #isOptional() * @see #nested() */ public MethodParameter nestedIfOptional() { //获取当前的参数类型如果是Optional类食,返回同一个参数但是嵌套级别更深的{@code MethodParameter}变体 return (getParameterType() == Optional.class ? nested() : this); } /** * Return a variant of this {@code MethodParameter} which refers to the * given containing class. * <p>返回{@code MethodParameter}的变体,该变体指向给定的包含类</p> * @param containingClass a specific containing class (potentially a * subclass of the declaring class, e.g. substituting a type variable) * -- 指定的包含类(可能是声明类的子类,比如替换类型变量) * @since 5.2 * @see #getParameterType() */ public MethodParameter withContainingClass(@Nullable Class<?> containingClass) { //克隆当前类对象得到一份副本进行操作 MethodParameter result = clone(); //设置副本的包含类 result.containingClass = containingClass; //设置副本的当前参数类型 result.parameterType = null; //返回副本 return result; } /** * Set a containing class to resolve the parameter type against. * <p>设置一个包含类来解析参数类型</p> */ @Deprecated void setContainingClass(Class<?> containingClass) { //设置当前包含类 this.containingClass = containingClass; //将当前参数类型置为null this.parameterType = null; } /** * Return the containing class for this method parameter. * <p>返回方法参数的包含类</p> * @return a specific containing class (potentially a subclass of the * declaring class), or otherwise simply the declaring class itself * -- 指定的包含类(可能是声明类的子类),否则只是声明类本身 * @see #getDeclaringClass() */ public Class<?> getContainingClass() { //获取当前包含类 Class<?> containingClass = this.containingClass; //如果containingClass不为null,返回containingClass;否则返回声明该方法的类 return (containingClass != null ? containingClass : getDeclaringClass()); } /** * Set a resolved (generic) parameter type. * <p>设置解析的(通用)参数类型</p> */ @Deprecated void setParameterType(@Nullable Class<?> parameterType) { this.parameterType = parameterType; } /** * Return the type of the method/constructor parameter. * <p>返回方法或构造函数的当前参数索引参数类型</p> * @return the parameter type (never {@code null}) -- 参数类型(不能为{@code null}) */ public Class<?> getParameterType() { //获取当前参数类型 Class<?> paramType = this.parameterType; //如果paramType不为null if (paramType != null) { //返回当前参数类型 return paramType; } //在嵌套级别1为本类对象返回一个ResolvableType对象,将此ResolvableType对象的type属性解析为Class, // 如果无法解析,则返回nul paramType = ResolvableType.forMethodParameter(this, null, 1).resolve(); //如果paramType为null if (paramType == null) { //计算参数类型,如果当前参数索引小于0,返回method的返回类型; // 否则返回executable的参数类型 数组中当前参数索引的参数类型 paramType = computeParameterType(); } //设置当前参数类型,缓存起来,避免下次调用该方法时需要再次解析 this.parameterType = paramType; return paramType; } /** * Return the generic type of the method/constructor parameter. * <p>返回Method或Contructor的当前参数索引的泛型参数类型</p> * @return the parameter type (never {@code null}) * -- 参数类型(不可以为{@code null}) * @since 3.0 */ public Type getGenericParameterType() { //获取当前泛型参数类型 Type paramType = this.genericParameterType; //如果paramType为null if (paramType == null) { //如果当前参数索引小于0 if (this.parameterIndex < 0) { //获取当前Method对象 Method method = getMethod(); //如果method不为null, 则(如果存在Kotlin反射且声明当前Method对象的类为Kotlin类型, // 则得到返回方法的泛型返回类型,通过Kotlin反射支持暂停功能;否则得到一个Type对象,该对象表示此Method // 对象表示的方法的正式返回类型);否则为void类型 paramType = (method != null ? (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(getContainingClass()) ? KotlinDelegate.getGenericReturnType(method) : method.getGenericReturnType()) : void.class); } else { //Method.getGenericParameterTypes()方法返回一个Type对象的数组,它以声明顺序表示此 // Method对象表示的方法的形式参数类型。如果底层方法没有参数,则返回长度为0的数组 Type[] genericParameterTypes = this.executable.getGenericParameterTypes(); //获取当前参数索引 int index = this.parameterIndex; //如果executable是Constructor的实例 且 声明executable的类是内部类 且 // genericParameterTypes的长度 等于 executable的参数数量-1 if (this.executable instanceof Constructor && ClassUtils.isInnerClass(this.executable.getDeclaringClass()) && genericParameterTypes.length == this.executable.getParameterCount() - 1) { // Bug in javac: type array excludes enclosing instance parameter // for inner classes with at least one generic constructor parameter, // so access it with the actual parameter index lowered by 1 // JDK<9中的javac bug:注解数组不包含内部类的实例参数,所以以实际参数索引降低1的 // 的方式进行访问 index = this.parameterIndex - 1; } //如果index属于[0,genericParameterTypes长度)范围内,获取第index个genericParameterTypes元素对象 // 赋值给paramType;否则计算参数类型,如果当前参数索引小于0,返回method的返回类型;否则返回executable的参数类型 // 数组中当前参数索引的参数类型 paramType = (index >= 0 && index < genericParameterTypes.length ? genericParameterTypes[index] : computeParameterType()); } //设置当前泛型参数类型,缓存起来,避免下次调用该方法时需要再次解析 this.genericParameterType = paramType; } return paramType; } /** * 计算参数类型,如果当前参数索引小于0,返回method的返回类型;否则返回executable的参数类型 * 数组中当前参数索引的参数类型 */ private Class<?> computeParameterType() { //如果当前参数索引小于0 if (this.parameterIndex < 0) { //获取当前Method对象 Method method = getMethod(); //如果method为null if (method == null) { //返回void return void.class; } //如果存在Kotlin反射 且 方法参数的包含类为Kotlin类型(上面带有Kotlin元数据) if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(getContainingClass())) { //返回method的返回类型,通过Kotlin反射支持暂停功能 return KotlinDelegate.getReturnType(method); } //返回method的返回类型 return method.getReturnType(); } //返回executable的参数类型数组中当前参数索引的参数类型 return this.executable.getParameterTypes()[this.parameterIndex]; } /** * Return the nested type of the method/constructor parameter. * <p>返回method/constructor参数嵌套类型</p> * @return the parameter type (never {@code null}) -- 参数类型(不可以为{@code null}) * @since 3.1 * @see #getNestingLevel() */ public Class<?> getNestedParameterType() { //嵌套级别大于1 if (this.nestingLevel > 1) { //返回Method或Contructor的泛型参数类型 Type type = getGenericParameterType(); //从2开始遍历传进来的嵌套等级,因为1表示其本身,所以从2开始 for (int i = 2; i <= this.nestingLevel; i++) { //如果type是ParameterizedType对象 if (type instanceof ParameterizedType) { //ParameterizedType.getActualTypeArgments:获取泛型中的实际类型,可能会存在多个泛型, // 例如Map<K,V>,所以会返回Type[]数组; Type[] args = ((ParameterizedType) type).getActualTypeArguments(); //返回i的类型索引 Integer index = getTypeIndexForLevel(i); //如果index不为null,获取第index个args元素;否则取最后一个元素 type = args[index != null ? index : args.length - 1]; } // TODO: Object.class if unresolvable 如果Object不可解析 } //如果type是Class实例 if (type instanceof Class) { //强转type为Class对象 return (Class<?>) type; } //如果type是ParameterizedType实例 else if (type instanceof ParameterizedType) { //ParameterizeType.getRowType:返回最外层<>前面那个类型,即Map<K ,V>的Map。 Type arg = ((ParameterizedType) type).getRawType(); //如果arg是Class的子类 if (arg instanceof Class) { //强转成arg的为Class对象 return (Class<?>) arg; } } //所有条件不满足,直接返回Object.class,因为java的所有类需要继承Object return Object.class; } else { //返回方法或构造函数的当前参数索引参数类型 return getParameterType(); } } /** * Return the nested generic type of the method/constructor parameter. * <p>返回method/constructor参数的嵌套泛型类型</p> * @return the parameter type (never {@code null}) -- 参数类型(不可以为{@code null}) * @since 4.2 * @see #getNestingLevel() */ public Type getNestedGenericParameterType() { //如果当前嵌套等级大于1 if (this.nestingLevel > 1) { //返回Method或Contructor的当前参数索引的泛型参数类型 Type type = getGenericParameterType(); //从2开始遍历传进来的嵌套等级,因为1表示其本身,所以从2开始 for (int i = 2; i <= this.nestingLevel; i++) { //如果type是ParameterizedType实例 if (type instanceof ParameterizedType) { //ParameterizedType.getActualTypeArgments:获取泛型中的实际类型,可能会存在多个泛型, // 例如Map<K,V>,所以会返回Type[]数组; Type[] args = ((ParameterizedType) type).getActualTypeArguments(); //返回i的类型索引 Integer index = getTypeIndexForLevel(i); //如果index不为null,获取第index个args元素;否则取最后一个元素 type = args[index != null ? index : args.length - 1]; } } //返回当前参数索引的泛型参数类型的嵌套泛型类型 return type; } else { //返回Method或Contructor的当前参数索引的泛型参数类型 return getGenericParameterType(); } } /** * Return the annotations associated with the target method/constructor itself. * <p>返回与目标method或constructor本身关联的经过后处理的注解</p> */ public Annotation[] getMethodAnnotations() { //getAnnotatedElement:返回包装的注解元素, //AnnotatiedElement.getAnnotations:获取method或constructor的注解数组 //将获取到注解数组返回给调用方之前对他进行后处理的模板方法,默认实例简单照原样返回给定的注解数组 return adaptAnnotationArray(getAnnotatedElement().getAnnotations()); } /** * Return the method/constructor annotation of the given type, if available. * <p>返回给定类型的method/constructor注解,(如果有)</p> * @param annotationType the annotation type to look for -- 要查找的注解类型 * @return the annotation object, or {@code null} if not found * 注解对象,如果没有找到返回{@code null} */ @Nullable public <A extends Annotation> A getMethodAnnotation(Class<A> annotationType) { //获取包装的注解元素,从其中获取annotationType对应的注解对象 A annotation = getAnnotatedElement().getAnnotation(annotationType); //如果annotation不为null, return (annotation != null ? adaptAnnotation(annotation) : null); } /** * Return whether the method/constructor is annotated with the given type. * <p>返回method/constructor是否使用给定类型进行注释</p> * @param annotationType the annotation type to look for -- 要查找的注解 * @since 4.3 * @see #getMethodAnnotation(Class) */ public <A extends Annotation> boolean hasMethodAnnotation(Class<A> annotationType) { //获取包装的注解元素,从中查找annotationType类型的注解对象,并返回出去 return getAnnotatedElement().isAnnotationPresent(annotationType); } /** * Return the annotations associated with the specific method/constructor parameter. * <p>返回与指定(当前)method/constructor参数关联的注解数组</p> */ public Annotation[] getParameterAnnotations() { //获取当前参数注解数组 Annotation[] paramAnns = this.parameterAnnotations; //如果paramAnns为null if (paramAnns == null) { //从方法或构造函数中获取参数注解 Annotation[][] annotationArray = this.executable.getParameterAnnotations(); //获取当前参数索引 int index = this.parameterIndex; //如果executable是构造函数 且 声明executable的类不是内部类 // 且 参数注解数组长度等于executable的参数数量-1 if (this.executable instanceof Constructor && ClassUtils.isInnerClass(this.executable.getDeclaringClass()) && annotationArray.length == this.executable.getParameterCount() - 1) { // Bug in javac in JDK <9: annotation array excludes enclosing instance parameter // for inner classes, so access it with the actual parameter index lowered by 1 // JDK<9中的javac bug:注解数组不包含内部类的实例参数,所以以实际参数索引降低1的 //的方式进行访问 index = this.parameterIndex - 1; } //如果index属于[0,annotationArry长度)范围内,就将annotationArray[index]的注解数组 //交给adaptAnnationArray方法进行处理后返回,adaptAnnationArray方法是给模板方法, //可用于供给子类重写,本类的adpatAnnationArray方法实现是个空方法,直接返回annotationArray[index] //不作任何处理;否则返回空注解数组 paramAnns = (index >= 0 && index < annotationArray.length ? adaptAnnotationArray(annotationArray[index]) : EMPTY_ANNOTATION_ARRAY); //设置当前参数的注解数组 this.parameterAnnotations = paramAnns; } //返回当前参数的注解数组 return paramAnns; } /** * Return {@code true} if the parameter has at least one annotation, * {@code false} if it has none. * <p>如果参数至少有一个注解,返回ture;如果没有,返回false</p> * @see #getParameterAnnotations() */ public boolean hasParameterAnnotations() { //遍历返回与指定(当前)method/constructor参数关联的注解数组,如果长度不为0,表示至少 // 有一个参数,返回ture;否则返回false return (getParameterAnnotations().length != 0); } /** * Return the parameter annotation of the given type, if available. * <p>返回给定类型的参数注解,如果可用</p> * @param annotationType the annotation type to look for -- 要查找的注解类型 * @return the annotation object, or {@code null} if not found * --注解对象,如果没有找到{@code null} */ @SuppressWarnings("unchecked") @Nullable public <A extends Annotation> A getParameterAnnotation(Class<A> annotationType) { //遍历返回与指定(当前)method/constructor参数关联的注解数组 Annotation[] anns = getParameterAnnotations(); //遍历注解数组 for (Annotation ann : anns) { //如果annotationType的ann的实例 if (annotationType.isInstance(ann)) { //返回ann,并强转成传进来的注解类型 return (A) ann; } } //返回null,表示没有找到 return null; } /** * Return whether the parameter is declared with the given annotation type. * <p>返回参数是否具有给定的注解类型声明</p> * @param annotationType the annotation type to look for -- 要查找的注解类型 * @see #getParameterAnnotation(Class) */ public <A extends Annotation> boolean hasParameterAnnotation(Class<A> annotationType) { //获取annotationType的参数注解,如果不为null,表示具有给定的 // 注解类型声明,返回true;否则为false return (getParameterAnnotation(annotationType) != null); } /** * Initialize parameter name discovery for this method parameter. * <p>初始化此方法参数的参数名称发现器</p> * <p>This method does not actually try to retrieve the parameter name at * this point; it just allows discovery to happen when the application calls * <p>此时,该方法实际上并不会尝试检索参数名称;它只允许在应用程序调用时进行发现</p> * {@link #getParameterName()} (if ever). */ public void initParameterNameDiscovery(@Nullable ParameterNameDiscoverer parameterNameDiscoverer) { this.parameterNameDiscoverer = parameterNameDiscoverer; } /** * Return the name of the method/constructor parameter. * <p>返回method/constructor参数的名称</p> * @return the parameter name (may be {@code null} if no * parameter name metadata is contained in the class file or no * {@link #initParameterNameDiscovery ParameterNameDiscoverer} * has been set to begin with) * -- 参数名(如果在类文件中不包含任何参数名称元数据,或者没有将 * {@link #initParameterNameDiscovery ParameterNameDiscoverer}设置为开头, * 则为{@code null}) */ @Nullable public String getParameterName() { //如果当前参数索引小于0 if (this.parameterIndex < 0) { //返回null return null; } //获取当前参数名发现器 ParameterNameDiscoverer discoverer = this.parameterNameDiscoverer; //如果发现器不为null if (discoverer != null) { String[] parameterNames = null; //如果executable是Method的实例 if (this.executable instanceof Method) { //获取方法的参数名,如果不能确定就返回null,如果参数名称仅可用于给定方法的某些参数, // 而不适用于其他参数,则数组的各个条目 可能为null.但是,建议在可行 // 的地方使用存根参数名名代替。 parameterNames = discoverer.getParameterNames((Method) this.executable); } //如果executable是Constructor的实例 else if (this.executable instanceof Constructor) { //获取方法的参数名,如果不能确定就返回null,如果参数名称仅可用于给定方法的某些参数, // 而不适用于其他参数,则数组的各个条目 可能为null.但是,建议在可行 // 的地方使用存根参数名名代替。 parameterNames = discoverer.getParameterNames((Constructor<?>) this.executable); } //如果参数名数组不为null if (parameterNames != null) { //取出当前参数索引在parameterNames中对应的参数名作为当前参数名 this.parameterName = parameterNames[this.parameterIndex]; } //将参数名发现器设置为null,因为已经解析完并成功获取了参数名,参数名发现器就不再起作用, //将其置null,能让GC回收该对象 this.parameterNameDiscoverer = null; } //返回当前参数名 return this.parameterName; } /** * A template method to post-process a given annotation instance before * returning it to the caller. * <p>将给定的注解返回给调用方之前对他进行后处理的模板方法</p> * <p>The default implementation simply returns the given annotation as-is. * <p>默认实例简单照原样返回给定的注解</p> * @param annotation the annotation about to be returned -- 将要返回的注解 * @return the post-processed annotation (or simply the original one) * -- 处理后的注解数组(或者简单原注解数组) * @since 4.2 */ protected <A extends Annotation> A adaptAnnotation(A annotation) { return annotation; } /** * A template method to post-process a given annotation array before * returning it to the caller. * <p>将给定的注解数组返回给调用方之前对他进行后处理的模板方法</p> * <p>The default implementation simply returns the given annotation array as-is. * <p>默认实例简单照原样返回给定的注解数组</p> * @param annotations the annotation array about to be returned * -- 将要返回的注解数组 * @return the post-processed annotation array (or simply the original one) * -- 处理后的注解数组(或者简单原注解数组) * @since 4.2 */ protected Annotation[] adaptAnnotationArray(Annotation[] annotations) { //直接返回传进来的注解数组 return annotations; } @Override public boolean equals(@Nullable Object other) { //如果本类对象地址与other相等 if (this == other) { //返回true,表示相等 return true; } //如果other是MethodParameter的实例 if (!(other instanceof MethodParameter)) { //返回false,表示不相等 return false; } //强转other为MethodParameter对象 MethodParameter otherParam = (MethodParameter) other; //如果当前容器类与otherParam的容器类是同一个 且 当前整数嵌套等级到整数类型索引的映射 // 与otherParam的otherParam从整数嵌套等级到整数类型索引的映射 相等 且 当前嵌套等级与otherParam的嵌套等级相等 // 且 当前参数索引与otherParam的参数索引相等 且 当前Method或构造函数对象与otherParam的Method或构造函数对象相等 // 则返回true,表示相等 return (getContainingClass() == otherParam.getContainingClass() && ObjectUtils.nullSafeEquals(this.typeIndexesPerLevel, otherParam.typeIndexesPerLevel) && this.nestingLevel == otherParam.nestingLevel && this.parameterIndex == otherParam.parameterIndex && this.executable.equals(otherParam.executable)); } @Override public int hashCode() { //取当前Method或构造函数对象加上当前参数索引计算出本类对象的哈希值 return (31 * this.executable.hashCode() + this.parameterIndex); } @Override public String toString() { //获取当前Method对象 Method method = getMethod(); //如果method不为null,拼装方法名;否则为'constructor',再拼装当前参数索引 return (method != null ? "method '" + method.getName() + "'" : "constructor") + " parameter " + this.parameterIndex; } /** * 克隆本类对象 * @return 克隆出来的 {@code MethodParameter} */ @Override public MethodParameter clone() { //赋值构造函数,根据与原始对象相同的元数据和缓存状态,生成一个独立 的MethodParameter对象 return new MethodParameter(this); } /** * Create a new MethodParameter for the given method or constructor. * <p>为给定的method或者constructor创建一个新的MethodParameter对象</p> * <p>This is a convenience factory method for scenarios where a * Method or Constructor reference is treated in a generic fashion. * <p>这是一个方便的工厂方法,适用于以通用方式处理method或者Constructor引用情况</p> * @param methodOrConstructor the Method or Constructor to specify a parameter for * -- Method或者Constructor以指定参数 * @param parameterIndex the index of the parameter * -- 参数索引 * @return the corresponding MethodParameter instance * -- 对应的MethodParamter实例 * @deprecated as of 5.0, in favor of {@link #forExecutable} * -- 从5.0开始,推荐使用{@link #forExecutable} */ @Deprecated public static MethodParameter forMethodOrConstructor(Object methodOrConstructor, int parameterIndex) { //如果methodOrConstructor不是Executable的实例 if (!(methodOrConstructor instanceof Executable)) { //抛出非法异常,异常信息:给定的对象[methodOrConstructor]既不是Method又不是Constructor throw new IllegalArgumentException( "Given object [" + methodOrConstructor + "] is neither a Method nor a Constructor"); } //为methodOrConstructor创建一个新的MethodParameter对象 return forExecutable((Executable) methodOrConstructor, parameterIndex); } /** * Create a new MethodParameter for the given method or constructor. * <p>为给定的method或者constructor创建一个新的MethodParameter对象</p> * <p>This is a convenience factory method for scenarios where a * Method or Constructor reference is treated in a generic fashion. * <p>这是一个方便的工厂方法,适用于以通用方式处理method或者Constructor引用情况</p> * @param executable the Method or Constructor to specify a parameter for * -- Method或者Constructor以指定参数 * @param parameterIndex the index of the parameter -- 参数索引 * @return the corresponding MethodParameter instance * -- 对应的MethodParamter实例 * @since 5.0 */ public static MethodParameter forExecutable(Executable executable, int parameterIndex) { //如果executable是Method实例 if (executable instanceof Method) { //强转executable为Method对象,使用嵌套级别1为Method对象创建一个新的MethodParameter return new MethodParameter((Method) executable, parameterIndex); } //如果executable是Constructor实例 else if (executable instanceof Constructor) { //强转executable为Constructor对象,使用嵌套级别1为Constructor对象创建一个新的MethodParameter return new MethodParameter((Constructor<?>) executable, parameterIndex); } else { //抛出非法参数异常,异常信息:不是Method/Constructor:executable throw new IllegalArgumentException("Not a Method/Constructor: " + executable); } } /** * Create a new MethodParameter for the given parameter descriptor. * <p>为给定的参数描述符创建一个新的MethodParameter对象</p> * <p>This is a convenience factory method for scenarios where a * Java 8 {@link Parameter} descriptor is already available. * <p>对于Java8{@link Parameter}描述符已经可用的情况,这个一个编辑的工厂方法</p> * @param parameter the parameter descriptor -- 参数描述符 * @return the corresponding MethodParameter instance * -- 对于的MethodParameter实例 * @since 5.0 */ public static MethodParameter forParameter(Parameter parameter) { return forExecutable(parameter.getDeclaringExecutable(), findParameterIndex(parameter)); } /** * 找出参数索引 * @param parameter 参数对象 * @return */ protected static int findParameterIndex(Parameter parameter) { //获取parameter的声明方法 Executable executable = parameter.getDeclaringExecutable(); //获取方法的参数数组 Parameter[] allParams = executable.getParameters(); // Try first with identity checks for greater performance. //首先尝试进行身份检查以提高信工 //遍历方法的参数数组 for (int i = 0; i < allParams.length; i++) { //如果parameter与第i个allParams的Parameter对象相同 if (parameter == allParams[i]) { //返回i,表示该parameter对应的参数索引 return i; } } // Potentially try again with object equality checks in order to avoid race // conditions while invoking java.lang.reflect.Executable.getParameters(). // 可能在调用java.lang.reflect.Executable.getParameters().时再次尝试相等性检查, // 以避免出现竞态条件 //竞态:指多线程情况下计算的正确性依赖于相对时间顺序或线程的交错; //遍历方法的参数数组 for (int i = 0; i < allParams.length; i++) { //如果parameter与第i个allParams的Parameter对象相同 if (parameter.equals(allParams[i])) { //返回i,表示该parameter对应的参数索引 return i; } } //抛出非法参数异常,异常信息:给定参数[parameter]再声明的方法中不匹配任何参数 throw new IllegalArgumentException("Given parameter [" + parameter + "] does not match any parameter in the declaring executable"); } /** * 验证参数索引位置, * @param executable Method或者Contructor对象 * @param parameterIndex 参数索引 * @return 通过检查后的parameterIndex */ private static int validateIndex(Executable executable, int parameterIndex) { //获取方法的参数数量 int count = executable.getParameterCount(); //如果parameterIndex不在[-1,count)范围内,抛出IllegalArgumentException Assert.isTrue(parameterIndex >= -1 && parameterIndex < count, () -> "Parameter index needs to be between -1 and " + (count - 1)); //返回通过检查后的parameterIndex return parameterIndex; } /** * Inner class to avoid a hard dependency on Kotlin at runtime. * <p>内部类,以避免在运行时严重依赖Kotlin</p> */ private static class KotlinDelegate { /** * Check whether the specified {@link MethodParameter} represents a nullable Kotlin type * or an optional parameter (with a default value in the Kotlin declaration). * <p>检查给定的{@link MethodParameter}是否表示nullable Kotlin 类型 或者 optional 参数( * 在Kontlin声明中具有默认值)</p> */ public static boolean isOptional(MethodParameter param) { //获取param的Method对象 Method method = param.getMethod(); //获取param的Constructor对象 Constructor<?> ctor = param.getConstructor(); //获取param的当前参数索引 int index = param.getParameterIndex(); //如果method不为null 且 index 等于 -1 if (method != null && index == -1) { //获取与method相应的KFunction实例;如果此方法不能由Kotlin函数表示,则返回null KFunction<?> function = ReflectJvmMapping.getKotlinFunction(method); //如果function不为null 且 function的返回类型在源代码中标记为nullable ,则返回 // true return (function != null && function.getReturnType().isMarkedNullable()); } else { KFunction<?> function = null; //Predicate接口主要用来判断一个参数是否符合要求,类似于Junit的assert. Predicate<KParameter> predicate = null; //如果method不为null if (method != null) { //获取与method相应的KFunction实例;如果此方法不能由Kotlin函数表示,则返回null function = ReflectJvmMapping.getKotlinFunction(method); //KParameter.Kind.VALUE表示普通命名参数 //设置判断条件为:如果p的参数种类是普通命名参数 predicate = p -> KParameter.Kind.VALUE.equals(p.getKind()); } //如果ctor不为null else if (ctor != null) { //获取与method相应的KFunction实例;如果此方法不能由Kotlin函数表示,则返回null function = ReflectJvmMapping.getKotlinFunction(ctor); //KParameter.Kind.INSTANCE表示调用成员需的实例,或者内部类构造函数的外部类实例 //设置判断条件为:如果p的参数种类是普通命名参数 或者是调用成员需的实例,或者内部类构造函数的外部类实例 predicate = p -> KParameter.Kind.VALUE.equals(p.getKind()) || KParameter.Kind.INSTANCE.equals(p.getKind()); } //如果function不为null if (function != null) { //调用此可调用项所需要的参数,如果此可调用项需要this实例或者扩展接收者参数,则他们 // 以该顺序在列表中排在第一位 List<KParameter> parameters = function.getParameters(); //收集parameters中符合predicate条件的KParameter对象到List,然后获取第index个KParameter对象 KParameter parameter = parameters .stream() .filter(predicate) .collect(Collectors.toList()) .get(index); //如果参数类型在源码中标记为可空 且 参数类型是可选的,并且通过KCallable.calBy进行调用时可以省略 return (parameter.getType().isMarkedNullable() || parameter.isOptional()); } } return false; } /** * Return the generic return type of the method, with support of suspending * functions via Kotlin reflection. * <p>返回方法的泛型返回类型,通过Kotlin反射支持暂停功能</p> */ static private Type getGenericReturnType(Method method) { //获取与method相应的KFunction实例;如果此方法不能由Kotlin函数表示,则返回null KFunction<?> function = ReflectJvmMapping.getKotlinFunction(method); //如果function不为null且function是挂起 if (function != null && function.isSuspend()) { //获取与给定Kotlin类型相对应的Java Type实例。请注意,根据出现的位置,一种 // Kotlin类型可能对应于不同的JVM类型。例如,当Unit是参数的类型时,它对应于 // JVM类Unit;当它是函数的返回类型时,它对应于void return ReflectJvmMapping.getJavaType(function.getReturnType()); } //返回一个Type对象,该对象表示此Method对象表示的方法的正式返回类型。 return method.getGenericReturnType(); } /** * Return the return type of the method, with support of suspending * functions via Kotlin reflection. * <p>返回method的返回类型,通过Kotlin反射支持暂停功能</p> */ static private Class<?> getReturnType(Method method) { //获取与method相应的KFunction实例;如果此方法不能由Kotlin函数表示,则返回null KFunction<?> function = ReflectJvmMapping.getKotlinFunction(method); //如果function不为null且function是挂起 if (function != null && function.isSuspend()) { //获取与给定Kotlin类型相对应的Java Type实例。请注意,根据出现的位置,一种 // Kotlin类型可能对应于不同的JVM类型。例如,当Unit是参数的类型时,它对应于 // JVM类Unit;当它是函数的返回类型时,它对应于void Type paramType = ReflectJvmMapping.getJavaType(function.getReturnType()); //获取paramType的ResolvableType对象,将此类型解析为Class,如果无法解析该类型, // 则返回method的返回类型 如果直接解析失败,则此方法考虑和WildcardTypes的bounds, // 但是Object.class的bounds将被忽略 return ResolvableType.forType(paramType).resolve(method.getReturnType()); } //返回method的返回类型 return method.getReturnType(); } } }
-
java反射之Method的invoke方法实现
2018-07-29 00:31:48在框架中经常会会用到method.invoke()方法,用来执行某个的对象的目标方法。以前写代码用到反射时,总是获取先获取Method,然后传入对应的Class实例对象执行方法。然而前段时间研究invoke方法时,发现invoke方法居然...在框架中经常会会用到method.invoke()方法,用来执行某个的对象的目标方法。以前写代码用到反射时,总是获取先获取Method,然后传入对应的Class实例对象执行方法。然而前段时间研究invoke方法时,发现invoke方法居然包含多态的特性,这是以前没有考虑过的一个问题。那么Method.invoke()方法的执行过程是怎么实现的?它的多态又是如何实现的呢?
本文将从java和JVM的源码实现深入探讨invoke方法的实现过程。
首先给出invoke方法多态特性的演示代码:
public class MethodInvoke { public static void main(String[] args) throws Exception { Method animalMethod = Animal.class.getDeclaredMethod("print"); Method catMethod = Cat.class.getDeclaredMethod("print"); Animal animal = new Animal(); Cat cat = new Cat(); animalMethod.invoke(cat); animalMethod.invoke(animal); catMethod.invoke(cat); catMethod.invoke(animal); } } class Animal { public void print() { System.out.println("Animal.print()"); } } class Cat extends Animal { @Override public void print() { System.out.println("Cat.print()"); } }
代码中,Cat类覆盖了父类Animal的print()方法, 然后通过反射分别获取print()的Method对象。最后分别用Cat和Animal的实例对象去执行print()方法。其中animalMethod.invoke(animal)和catMethod.invoke(cat),示例对象的真实类型和Method的声明Classs是相同的,按照预期打印结果;animalMethod.invoke(cat)中,由于Cat是Animal的子类,按照多态的特性,子类调用父类的的方法,方法执行时会动态链接到子类的实现方法上。因此,这里会调用Cat.print()方法;而catMethod.invoke(animal)中,传入的参数类型Animal是父类,却期望调用子类Cat的方法,因此这一次会抛出异常。代码打印结果为:
Cat.print() Animal.print() Cat.print() Exception in thread "main" java.lang.IllegalArgumentException: object is not an instance of declaring class at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at com.wy.invoke.MethodInvoke.main(MethodInvoke.java:17)
接下来,我们来看看invoke()方法的实现过程。
public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { if (!override) { if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { Class<?> caller = Reflection.getCallerClass(1); checkAccess(caller, clazz, obj, modifiers); } } MethodAccessor ma = methodAccessor; // read volatile if (ma == null) { ma = acquireMethodAccessor(); } return ma.invoke(obj, args); }
invoke()方法中主要分为两部分:访问控制检查和调用MethodAccessor.invoke()实现方法执行。
首先看一下访问控制检查这一块的逻辑。第一眼看到这里的逻辑的时候,很容易搞不清楚是干嘛的。通俗来讲就是通过方法的修饰符(public/protected/private/package),来判断方法的调用者是否可以访问该方法。这是java的基础内容,不过用代码写出来,一下子不容易想到。访问控制检查分为3步:
- 检查override,如果override为true,跳过检查;否则继续;
- 快速检查,判断该方法的修饰符modifiers是否为public,如果是跳过检查;否则继续;
- 详细检查,通过方法的(protected/private/package)修饰符或方法的声明类(例如子类可以访问父类的protected方法)与调用者caller之间的关系,判断caller是否有权限访问该方法。
override属性是Method的父类AccessibleObject中声明的变量,使得程序可以控制是否跳过访问权限的检查。另外,Method的实例对象中,override属性的初始值设置为false。
public void setAccessible(boolean flag) throws SecurityException { SecurityManager sm = System.getSecurityManager(); if (sm != null) sm.checkPermission(ACCESS_PERMISSION); setAccessible0(this, flag); } private static void setAccessible0(AccessibleObject obj, boolean flag) throws SecurityException { if (obj instanceof Constructor && flag == true) { Constructor<?> c = (Constructor<?>)obj; if (c.getDeclaringClass() == Class.class) { throw new SecurityException("Can not make a java.lang.Class" + " constructor accessible"); } } obj.override = flag; }
多说一句,Field同样继承了AccessibleObject,且Field的override也是初始化为false的,也就是说并没有按照变量的修饰符去初始化不同的值。但是我们在调用Field.set(Object obj, Object value)时,如果该Field是private修饰的,会因没有访问权限而抛出异常,因此必须调用setAccessible(true)。此处非常容易理解为因为变量是public的,所以override就被初始化为true。
invoke()方法中,访问控制检查之后,就是通过MethodAccessor.invoke()调用方法。再来看一下代码:
MethodAccessor ma = methodAccessor; // read volatile if (ma == null) { ma = acquireMethodAccessor(); } return ma.invoke(obj, args);
这里的逻辑很简单,首先将变量methodAccessor赋值给ma,在方法栈中保存一个可以直接引用的本地变量,如果methodAccessor不存在,调用acquireMethodAccessor()方法创建一个。
private volatile MethodAccessor methodAccessor; private Method root; private MethodAccessor acquireMethodAccessor() { // First check to see if one has been created yet, and take it // if so MethodAccessor tmp = null; if (root != null) tmp = root.getMethodAccessor(); if (tmp != null) { methodAccessor = tmp; } else { // Otherwise fabricate one and propagate it up to the root tmp = reflectionFactory.newMethodAccessor(this); setMethodAccessor(tmp); } return tmp; } void setMethodAccessor(MethodAccessor accessor) { methodAccessor = accessor; // Propagate up if (root != null) { root.setMethodAccessor(accessor); } } Method copy() { Method res = new Method(clazz, name, parameterTypes, returnType, exceptionTypes, modifiers, slot, signature, annotations, parameterAnnotations, annotationDefault); res.root = this; res.methodAccessor = methodAccessor; return res; }
综合acquireMethodAccessor(),setMethodAccessor()以及copy()这三个方法,可以看到一个Method实例对象维护了一个root引用。当调用Method.copy()进行方法拷贝时,root指向了被拷贝的对象。那么当一个Method被多次拷贝后,调用一次setMethodAccessor()方法,就会将root引用所指向的Method的methodAccessor变量同样赋值。例如:D -> C -> B -> A,其中X-> Y表示X = Y.copy(), 当C对象调用setMethodAccessor()时,B和A都会传播赋值methodAccessor, 而D的methodAccessor还是null。紧接着,当D需要获取methodAccessor而调用acquireMethodAccessor()时,D获取root的methodAccessor, 那么D将和ABC持有相同的methodAccessor。
虽然Method中,通过维护root引用意图使相同的方法始终保持只有一个methodAccessor实例,但是上述方法仍然无法保证相同的方法只有一个methodAccessor实例。例如通过copy()使ABCD保持关系:D -> C -> B -> A, 当B对象调用setMethodAccessor()时,B和A都会赋值methodAccessor, 而C、D的methodAccessor还是null。这时D调用acquireMethodAccessor()时,D获取root也就是C的methodAccessor,发现为空,然后就新创建了一个。从而出现了相同的方法中出现了两个methodAccessor实例对象的现象。
在Class.getMethod()、Class.getDeclaredMethod()以及Class.getDeclaredMethod(String name, Class<?>... parameterTypes)方法中最终都会调用copy()方法来保障Method使用的安全性。 在比较极端加巧合的情况下,可能会引起类膨胀的问题,这就是接下来要讲到的MethodAccessor的实现机制。
在前面代码中,MethodAccessor的创建是通过反射工厂ReflectionFactory的newMethodAccessor(Method)方法来创建的。
public MethodAccessor newMethodAccessor(Method method) { checkInitted(); if (noInflation) { return new MethodAccessorGenerator(). generateMethod(method.getDeclaringClass(), method.getName(), method.getParameterTypes(), method.getReturnType(), method.getExceptionTypes(), method.getModifiers()); } else { NativeMethodAccessorImpl acc = new NativeMethodAccessorImpl(method); DelegatingMethodAccessorImpl res = new DelegatingMethodAccessorImpl(acc); acc.setParent(res); return res; } }
其中, checkInitted()方法检查从配置项中读取配置并设置noInflation、inflationThreshold的值:
private static void checkInitted() { if (initted) return; AccessController.doPrivileged( new PrivilegedAction<Void>() { public Void run() { if (System.out == null) { // java.lang.System not yet fully initialized return null; } String val = System.getProperty("sun.reflect.noInflation"); if (val != null && val.equals("true")) { noInflation = true; } val = System.getProperty("sun.reflect.inflationThreshold"); if (val != null) { try { inflationThreshold = Integer.parseInt(val); } catch (NumberFormatException e) { throw (RuntimeException) new RuntimeException("Unable to parse property sun.reflect.inflationThreshold"). initCause(e); } } initted = true; return null; } }); }
可以通过启动参数-Dsun.reflect.noInflation=false -Dsun.reflect.inflationThreshold=15来设置:
结合字面意思及下面代码理解,这两个配置sun.reflect.noInflation是控制是否立即进行类膨胀,sun.reflect.inflationThreshold是设置类膨胀阈值。
创建MethodAccessor有两种选择,一种是当sun.reflect.noInflation配置项为true时,ReflectionFactory利用MethodAccessor的字节码生成类 MethodAccessorGenerator直接创建一个代理类,通过间接调用原方法完成invoke()任务,具体实现稍后给出。MethodAccessor的另一种实现方式是,创建DelegatingMethodAccessorImpl 委托类,并将执行invoke()方法的具体内容交由NativeMethodAccessorImpl实现,而NativeMethodAccessorImpl最终调用native方法完成invoke()任务。以下是NativeMethodAccessorImpl的invoke()方法实现。
public Object invoke(Object obj, Object[] args) throws IllegalArgumentException, InvocationTargetException { if (++numInvocations > ReflectionFactory.inflationThreshold()) { MethodAccessorImpl acc = (MethodAccessorImpl) new MethodAccessorGenerator(). generateMethod(method.getDeclaringClass(), method.getName(), method.getParameterTypes(), method.getReturnType(), method.getExceptionTypes(), method.getModifiers()); parent.setDelegate(acc); } return invoke0(method, obj, args); } private static native Object invoke0(Method m, Object obj, Object[] args);
可以看到,当numInvocations数量大于配置项sun.reflect.inflationThreshold即类膨胀阈值时, 使用MethodAccessorGenerator创建一个代理类对象,并且将被委托的NativeMethodAccessorImpl的parent,也就是委托类DelegatingMethodAccessorImpl的委托类设置为这个生成的代理对象。这么说可能有点绕,下面用一幅图表示这个过程。
总体来说,当调用invoke()时,按照默认配置,Method首先创建一个DelegatingMethodAccessorImpl对象,并设置一个被委托的NativeMethodAccessorImpl对象,那么method.invoke()就被转换成DelegatingMethodAccessorImpl.invoke(),然后又被委托给NativeMethodAccessorImp.invoke()实现。当NativeMethodAccessorImp.invoke()调用次数超过一定热度时(默认15次),被委托方又被转换成代理类来实现。
之前提到过在极端情况下,同一个方法的Method对象存在多个不同拷贝拷贝时,可能存在多个MethodAccessor对象。那么当多次调用后,必然会生成两个重复功能的代理类。当然,一般情况下,生成两个代理类并没有较大的影响。
其中代理类的具体字节码实现过程较为复杂,大体思想是生成一个如下所示的类:
public class GeneratedMethodAccessor1 extends MethodAccessorImpl { public GeneratedMethodAccessor1 () { super(); } public Object invoke(Object obj, Object[] args) throws IllegalArgumentException, InvocationTargetException { if (!(obj instanceof Cat)) { throw new ClassCastException(); } if (args != null && args.length != 0) { throw new IllegalArgumentException(); } try { Cat cat = (Cat) obj; cat.print(); return null; } catch (Throwable e) { throw new InvocationTargetException(e, "invoke error"); } } }
到目前为止,除了在代理的GeneratedMethodAccessor1 类中,方法的执行有多态的特性,而NativeMethodAccessorImp的invoke()实现是在jdk中的完成的。接下来我们将目光移到NativeMethodAccessorImp的native方法invoke0();
首先,在\jdk\src\share\native\sun\reflect路径下找到NativeAccessors.c, 其中有Java_sun_reflect_NativeMethodAccessorImpl _invoke0()方法,根据JNI定义函数名的规则"包名_类名_方法名",这就是我们要找的native方法实现入口。
JNIEXPORT jobject JNICALL Java_sun_reflect_NativeMethodAccessorImpl_invoke0 (JNIEnv *env, jclass unused, jobject m, jobject obj, jobjectArray args) { return JVM_InvokeMethod(env, m, obj, args); }
方法调用JVM_InvokeMethod(), 一般以JVM_开头的函数定义在jvm.cpp文件中,不熟悉的话可以通过头文件jvm.h看出来。继续追踪,发现jvm.cpp文件位于spot\src\share\vm\prims文件夹下。
JVM_ENTRY(jobject, JVM_InvokeMethod(JNIEnv *env, jobject method, jobject obj, jobjectArray args0)) JVMWrapper("JVM_InvokeMethod"); Handle method_handle; if (thread->stack_available((address) &method_handle) >= JVMInvokeMethodSlack) { method_handle = Handle(THREAD, JNIHandles::resolve(method)); Handle receiver(THREAD, JNIHandles::resolve(obj)); objArrayHandle args(THREAD, objArrayOop(JNIHandles::resolve(args0))); oop result = Reflection::invoke_method(method_handle(), receiver, args, CHECK_NULL); jobject res = JNIHandles::make_local(env, result); if (JvmtiExport::should_post_vm_object_alloc()) { oop ret_type = java_lang_reflect_Method::return_type(method_handle()); assert(ret_type != NULL, "sanity check: ret_type oop must not be NULL!"); if (java_lang_Class::is_primitive(ret_type)) { // Only for primitive type vm allocates memory for java object. // See box() method. JvmtiExport::post_vm_object_alloc(JavaThread::current(), result); } } return res; } else { THROW_0(vmSymbols::java_lang_StackOverflowError()); } JVM_END
其中oop result = Reflection::invoke_method(method_handle(), receiver, args, CHECK_NULL)是方法的执行过程,在\hotspot\src\share\vm\runtime路径下找到reflection.cpp文件。
oop Reflection::invoke_method(oop method_mirror, Handle receiver, objArrayHandle args, TRAPS) { oop mirror = java_lang_reflect_Method::clazz(method_mirror); int slot = java_lang_reflect_Method::slot(method_mirror); bool override = java_lang_reflect_Method::override(method_mirror) != 0; objArrayHandle ptypes(THREAD, objArrayOop(java_lang_reflect_Method::parameter_types(method_mirror))); oop return_type_mirror = java_lang_reflect_Method::return_type(method_mirror); BasicType rtype; if (java_lang_Class::is_primitive(return_type_mirror)) { rtype = basic_type_mirror_to_basic_type(return_type_mirror, CHECK_NULL); } else { rtype = T_OBJECT; } instanceKlassHandle klass(THREAD, java_lang_Class::as_Klass(mirror)); Method* m = klass->method_with_idnum(slot); if (m == NULL) { THROW_MSG_0(vmSymbols::java_lang_InternalError(), "invoke"); } methodHandle method(THREAD, m); return invoke(klass, method, receiver, override, ptypes, rtype, args, true, THREAD); } oop Reflection::invoke(instanceKlassHandle klass, methodHandle reflected_method, Handle receiver, bool override, objArrayHandle ptypes, BasicType rtype, objArrayHandle args, bool is_method_invoke, TRAPS) { ResourceMark rm(THREAD); methodHandle method; // actual method to invoke KlassHandle target_klass; // target klass, receiver's klass for non-static // Ensure klass is initialized klass->initialize(CHECK_NULL); bool is_static = reflected_method->is_static(); if (is_static) { // ignore receiver argument method = reflected_method; target_klass = klass; } else { // check for null receiver if (receiver.is_null()) { THROW_0(vmSymbols::java_lang_NullPointerException()); } // Check class of receiver against class declaring method if (!receiver->is_a(klass())) { THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "object is not an instance of declaring class"); } // target klass is receiver's klass target_klass = KlassHandle(THREAD, receiver->klass()); // no need to resolve if method is private or <init> if (reflected_method->is_private() || reflected_method->name() == vmSymbols::object_initializer_name()) { method = reflected_method; } else { // resolve based on the receiver if (reflected_method->method_holder()->is_interface()) { // resolve interface call if (ReflectionWrapResolutionErrors) { // new default: 6531596 // Match resolution errors with those thrown due to reflection inlining // Linktime resolution & IllegalAccessCheck already done by Class.getMethod() method = resolve_interface_call(klass, reflected_method, target_klass, receiver, THREAD); if (HAS_PENDING_EXCEPTION) { // Method resolution threw an exception; wrap it in an InvocationTargetException oop resolution_exception = PENDING_EXCEPTION; CLEAR_PENDING_EXCEPTION; JavaCallArguments args(Handle(THREAD, resolution_exception)); THROW_ARG_0(vmSymbols::java_lang_reflect_InvocationTargetException(), vmSymbols::throwable_void_signature(), &args); } } else { method = resolve_interface_call(klass, reflected_method, target_klass, receiver, CHECK_(NULL)); } } else { // if the method can be overridden, we resolve using the vtable index. assert(!reflected_method->has_itable_index(), ""); int index = reflected_method->vtable_index(); method = reflected_method; if (index != Method::nonvirtual_vtable_index) { // target_klass might be an arrayKlassOop but all vtables start at // the same place. The cast is to avoid virtual call and assertion. InstanceKlass* inst = (InstanceKlass*)target_klass(); method = methodHandle(THREAD, inst->method_at_vtable(index)); } if (!method.is_null()) { // Check for abstract methods as well if (method->is_abstract()) { // new default: 6531596 if (ReflectionWrapResolutionErrors) { ResourceMark rm(THREAD); Handle h_origexception = Exceptions::new_exception(THREAD, vmSymbols::java_lang_AbstractMethodError(), Method::name_and_sig_as_C_string(target_klass(), method->name(), method->signature())); JavaCallArguments args(h_origexception); THROW_ARG_0(vmSymbols::java_lang_reflect_InvocationTargetException(), vmSymbols::throwable_void_signature(), &args); } else { ResourceMark rm(THREAD); THROW_MSG_0(vmSymbols::java_lang_AbstractMethodError(), Method::name_and_sig_as_C_string(target_klass(), method->name(), method->signature())); } } } } } } // I believe this is a ShouldNotGetHere case which requires // an internal vtable bug. If you ever get this please let Karen know. if (method.is_null()) { ResourceMark rm(THREAD); THROW_MSG_0(vmSymbols::java_lang_NoSuchMethodError(), Method::name_and_sig_as_C_string(klass(), reflected_method->name(), reflected_method->signature())); } // In the JDK 1.4 reflection implementation, the security check is // done at the Java level if (!(JDK_Version::is_gte_jdk14x_version() && UseNewReflection)) { // Access checking (unless overridden by Method) if (!override) { if (!(klass->is_public() && reflected_method->is_public())) { bool access = Reflection::reflect_check_access(klass(), reflected_method->access_flags(), target_klass(), is_method_invoke, CHECK_NULL); if (!access) { return NULL; // exception } } } } // !(Universe::is_gte_jdk14x_version() && UseNewReflection) assert(ptypes->is_objArray(), "just checking"); int args_len = args.is_null() ? 0 : args->length(); // Check number of arguments if (ptypes->length() != args_len) { THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "wrong number of arguments"); } // Create object to contain parameters for the JavaCall JavaCallArguments java_args(method->size_of_parameters()); if (!is_static) { java_args.push_oop(receiver); } for (int i = 0; i < args_len; i++) { oop type_mirror = ptypes->obj_at(i); oop arg = args->obj_at(i); if (java_lang_Class::is_primitive(type_mirror)) { jvalue value; BasicType ptype = basic_type_mirror_to_basic_type(type_mirror, CHECK_NULL); BasicType atype = unbox_for_primitive(arg, &value, CHECK_NULL); if (ptype != atype) { widen(&value, atype, ptype, CHECK_NULL); } switch (ptype) { case T_BOOLEAN: java_args.push_int(value.z); break; case T_CHAR: java_args.push_int(value.c); break; case T_BYTE: java_args.push_int(value.b); break; case T_SHORT: java_args.push_int(value.s); break; case T_INT: java_args.push_int(value.i); break; case T_LONG: java_args.push_long(value.j); break; case T_FLOAT: java_args.push_float(value.f); break; case T_DOUBLE: java_args.push_double(value.d); break; default: THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "argument type mismatch"); } } else { if (arg != NULL) { Klass* k = java_lang_Class::as_Klass(type_mirror); if (!arg->is_a(k)) { THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "argument type mismatch"); } } Handle arg_handle(THREAD, arg); // Create handle for argument java_args.push_oop(arg_handle); // Push handle } } assert(java_args.size_of_parameters() == method->size_of_parameters(), "just checking"); // All oops (including receiver) is passed in as Handles. An potential oop is returned as an // oop (i.e., NOT as an handle) JavaValue result(rtype); JavaCalls::call(&result, method, &java_args, THREAD); if (HAS_PENDING_EXCEPTION) { // Method threw an exception; wrap it in an InvocationTargetException oop target_exception = PENDING_EXCEPTION; CLEAR_PENDING_EXCEPTION; JavaCallArguments args(Handle(THREAD, target_exception)); THROW_ARG_0(vmSymbols::java_lang_reflect_InvocationTargetException(), vmSymbols::throwable_void_signature(), &args); } else { if (rtype == T_BOOLEAN || rtype == T_BYTE || rtype == T_CHAR || rtype == T_SHORT) narrow((jvalue*) result.get_value_addr(), rtype, CHECK_NULL); return box((jvalue*) result.get_value_addr(), rtype, CHECK_NULL); } }
Reflection::invoke_method()中调用Reflection::invoke(),然后在Reflection::invoke()方法中,当反射调用的方法是接口方法时,调用Reflection::resolve_interface_call(),该方法依赖LinkResolver::resolve_interface_call()来完成方法的动态链接过程,具体实现就不在这里展示。
method = resolve_interface_call(klass, reflected_method, target_klass, receiver, CHECK_(NULL));
methodHandle Reflection::resolve_interface_call(instanceKlassHandle klass, methodHandle method, KlassHandle recv_klass, Handle receiver, TRAPS) { assert(!method.is_null() , "method should not be null"); CallInfo info; Symbol* signature = method->signature(); Symbol* name = method->name(); LinkResolver::resolve_interface_call(info, receiver, recv_klass, klass, name, signature, KlassHandle(), false, true, CHECK_(methodHandle())); return info.selected_method(); }
如果反射调用的方法是可以被覆盖的方法,例如Animal.print(), Reflection::invoke()最终通过查询虚方法表vtable来确定最终的method。
// if the method can be overridden, we resolve using the vtable index. assert(!reflected_method->has_itable_index(), ""); int index = reflected_method->vtable_index(); method = reflected_method; if (index != Method::nonvirtual_vtable_index) { // target_klass might be an arrayKlassOop but all vtables start at // the same place. The cast is to avoid virtual call and assertion. InstanceKlass* inst = (InstanceKlass*)target_klass(); method = methodHandle(THREAD, inst->method_at_vtable(index)); }
总结
1.method.invoke()方法支持多态特性,其native实现在方法真正执行之前通过动态连接或者虚方法表来实现。
2.框架中使用method.invoke()执行方法调用时,初始获取method对象时,可以先调用一次setAccessable(true),使得后面每次调用invoke()时,节省一次方法修饰符的判断,略微提升性能。业务允许的情况下,Field同样可以如此操作。
3.委托模式可以解决一种方案的多种实现之间自由切换,而代理模式只能根据传入的被代理对象来实现功能。
参考文章:
-
Java反射08 : 成员方法Method学习示例
2018-03-04 14:36:42java.lang.reflect.Method类提供了用于获取和操作成员方法的静态方法。 1.通过Method可以做什么 通过Method可以做以下事情: 如何通过Class对象获取Method?如何通过Method对象获取Class? 如何通过Method获取...java.lang.reflect.Method类提供了用于获取和操作成员方法的静态方法。
1.通过Method可以做什么
通过Method可以做以下事情:
- 如何通过Class对象获取Method?如何通过Method对象获取Class?
- 如何通过Method获取成员方法的相关信息如:方法名、修饰符、参数个数、参数类型、参数化类型、异常类、可变参数、访问权限、注解?
- 如何通过构造器Method进行方法(包括私有方法)调用?
2.代码实例
实体类:
/** * <p>用户表</p> * * @author hanchao 2018/2/14 22:30 */ public class User extends{ public String username = "张三"; private int password = 123456; //setter getter toString constructor ... /** * <p>Title: 为了测试可变参数</p> * * @author 韩超 2018/2/28 17:32 */ public void demo(String... args) { } /** * <p>Title: 泛型方法:为了测试method.getTypeParameters()参数化类型(泛型)</p> * * @author 韩超 2018/2/28 17:30 */ public static <T> void test(T t) { } /** * <p>为了测试通过Method获取参数注解的二维矩阵</p> * * @author hanchao 2018/3/4 14:24 **/ public void initUser(@MyAnnotationA @MyAnnotationB String username, @MyAnnotationB String password) { } /** * <p>私有方法,用来示例:通过反射调用私有方法</p> * * @author hanchao 2018/3/4 14:11 **/ private void setUsernameByDefault() { this.username = "default"; } /** * <p>Title: 为了测试注解、异常</p> * * @author 韩超 2018/2/28 17:31 */ @MyAnnotationA @MyAnnotationB public String getUsername() throws NullPointerException, ArrayStoreException { return username; } public void setUsername(String username) { this.username = username; } public int getPassword() { return password; } public void setPassword(int password) { this.password = password; } }
实例类:
/** * java.lang.reflect.Method示例 * Created by 韩超 on 2018/2/28. */ public class ReflectMethodDemo { private final static Logger LOGGER = Logger.getLogger(ReflectMethodDemo.class); /** * <p>Title: java反射-方法Method示例</p> * * @author 韩超 2018/2/28 14:54 */ public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { //首先获取Class对象 Class userClass = User.class; // Class对象与Method对象的相互转化 / LOGGER.info("// Class对象与Method对象的相互转化 /"); //通过clazz.getMethod(name,args...)和clazz.getDeclaredMethod(name,args...)获取CLass对象的指定方法 Method getUsrMethod = userClass.getMethod("getUsername"); Method setUsrMethod = userClass.getDeclaredMethod("setUsername", String.class); LOGGER.info("通过clazz.getMethod(name,args)获取CLass对象的指定方法:" + getUsrMethod); LOGGER.info("通过clazz.getDeclaredMethod(name,args)获取CLass对象的指定方法:" + setUsrMethod + "\n"); //通过clazz.getMethods()和clazz.getDeclaredMethods()获取CLass对象的全部方法 Method[] methods = userClass.getMethods(); for (Method method : methods) { LOGGER.info("通过clazz.getMethods()获取CLass对象的全部方法:" + method); } Method[] methods1 = userClass.getDeclaredMethods(); for (Method method : methods1) { LOGGER.info("通过clazz.getDeclaredMethods()获取CLass对象的全部方法:" + method); } System.out.println(); //通过method.getDeclaringClass()获取当前Method对象所属的Class Class userClass2 = getUsrMethod.getDeclaringClass(); LOGGER.info("通过method.getDeclaringClass()获取当前Method对象所属的Class:" + userClass2 + "\n"); // Method信息获取 / LOGGER.info("// Method信息获取 /"); //通过method.getModifiers()获取方法修饰符的int值 LOGGER.info("通过method.getModifiers()获取方法修饰符的int值" + Modifier.toString(getUsrMethod.getModifiers()) + "\n"); //通过method.getName()获取方法名 LOGGER.info("通过method.getName()获取方法名" + getUsrMethod.getName() + "\n"); //通过method.getGenericReturnType()获取返回值的类型(Type) LOGGER.info("通过method.getGenericReturnType()获取返回值的类型(Type):" + getUsrMethod.getGenericReturnType()); //通过method.getReturnType()获取返回值的类(Class) LOGGER.info("通过method.getReturnType()获取返回值的类(Class):" + getUsrMethod.getReturnType() + "\n"); //通过method.getGenericParameterTypes()获取参数的类型(Type) Type[] paramTypes = setUsrMethod.getGenericParameterTypes(); for (Type type : paramTypes) { LOGGER.info("通过method.getGenericParameterTypes()获取参数的类型(Type):" + type.getTypeName()); } //通过method.getParameterTypes()获取参数的类(Class) Class[] paramClasses = setUsrMethod.getParameterTypes(); for (Class clazz : paramClasses) { LOGGER.info("通过method.getParameterTypes()获取参数的类(Class):" + clazz); } System.out.println(""); //通过method.getParameters()获取参数(Parameter)数组 Parameter[] parameters = setUsrMethod.getParameters(); for (Parameter parameter : parameters) { LOGGER.info("通过method.getParameters()获取参数(Parameter)数组:" + parameter); } System.out.println(); //通过method.getGenericExceptionTypes()获取异常的类型(Type) Type[] exceptionTypes = getUsrMethod.getGenericExceptionTypes(); for (Type exception : exceptionTypes) { LOGGER.info("通过method.getGenericExceptionTypes()获取异常的类型(Type):" + exception.getTypeName()); } //通过method.getExceptionTypes()获取异常的类(Class) Class[] exceptionClasses = getUsrMethod.getExceptionTypes(); for (Class exception : exceptionClasses) { LOGGER.info("通过method.getExceptionTypes()获取异常的类(Class):" + exception); } System.out.println(); //通过method.toString()和method.toGenericString()获取方法的字符串描述 LOGGER.info("通过method.toString()获取方法的字符串描述:" + getUsrMethod.toString()); LOGGER.info("通过method.toGenericString()获取方法的字符串描述(包括通用类型):" + getUsrMethod.toGenericString() + "\n"); //通过equals()比较两个方法是否相同 LOGGER.info("通过equals()比较两个方法是否相同:" + getUsrMethod.equals(setUsrMethod)); //通过method.isBridge()判断是否是桥方法 LOGGER.info("通过method.isBridge()判断是否是桥方法:" + getUsrMethod.isBridge()); //通过method.isSynthetic()判断是否是合成方法 LOGGER.info("通过method.isSynthetic()判断是否是合成方法:" + getUsrMethod.isSynthetic()); //通过method.isVarArgs()判断是否使用了可变参数: Method demoMethod = userClass.getDeclaredMethod("demo", String[].class); LOGGER.info("通过method.isVarArgs()判断是否使用了可变参数:" + demoMethod.isVarArgs() + "\n"); //通过method.getParameterCount()获取参数个数 LOGGER.info("通过method.getParameterCount()获取参数个数,setUsername = " + setUsrMethod.getParameterCount()); LOGGER.info("通过method.getParameterCount()获取参数个数,getUsername = " + getUsrMethod.getParameterCount() + "\n"); //通过method.getDefaultValue()获取默认返回值 LOGGER.info("通过method.getDefaultValue()获取默认返回值,setUsername = " + setUsrMethod.getDefaultValue()); LOGGER.info("通过method.getDefaultValue()获取默认返回值,getUsrMethod = " + getUsrMethod.getDefaultValue() + "\n"); //通过method.getTypeParameters()获取泛型方法的参数化类型(泛型) TypeVariable[] typeVariables = getUsrMethod.getTypeParameters(); LOGGER.info("通过method.getTypeParameters()获取泛型方法的参数化类型(泛型),getUsrMethod()的参数化类型个数:" + typeVariables.length); Method toArrayMethod = userClass.getDeclaredMethod("test", Object.class); TypeVariable[] typeVariables1 = toArrayMethod.getTypeParameters(); LOGGER.info("通过method.getTypeParameters()获取泛型方法的参数化类型(泛型),ReflectMethodDemo.test()的参数化类型:" + typeVariables1[0].getName() + "\n"); // Method注解信息获取 / LOGGER.info("// Method注解信息获取 /"); //通过method.getAnnotatedReturnType()获取被注解的返回值类型(组合类型) AnnotatedType returnAnnotatedType = getUsrMethod.getAnnotatedReturnType(); LOGGER.info("通过method.getAnnotatedReturnType()获取被注解的返回值类型(组合类型):" + returnAnnotatedType); //获取被注解的返回值类型中的返回值类型 LOGGER.info("通过annotatedType.getType()获取被注解的返回值类型中的返回值类型:" + returnAnnotatedType.getType()); //获取被注解的返回值类型中的注解类型 Annotation[] annotations = returnAnnotatedType.getAnnotations(); LOGGER.info("通过annotatedType.getAnnotations()获取被注解的返回值类型中的注解类型"); setUsrMethod.getAnnotatedParameterTypes(); setUsrMethod.getAnnotatedExceptionTypes(); setUsrMethod.getAnnotatedReceiverType(); LOGGER.info("类似于method.getAnnotatedReturnType()的还有: method.getAnnotatedParameterTypes()"); LOGGER.info("类似于method.getAnnotatedReturnType()的还有: method.getAnnotatedExceptionTypes()"); LOGGER.info("类似于method.getAnnotatedReturnType()的还有: method.getAnnotatedReceiverType()" + "\n"); //获取指定的单个注解 Annotation annotation = getUsrMethod.getAnnotation(MyAnnotationA.class); Annotation annotation1 = getUsrMethod.getDeclaredAnnotation(MyAnnotationB.class); LOGGER.info("通过method.getAnnotation(Annotation.class)获取指定的注解: " + annotation); LOGGER.info("通过method.getDeclaredAnnotation(Annotation.class)获取指定的注解 :" + annotation1 + "\n"); //获取指定的一类注解 Annotation[] annotations1 = getUsrMethod.getAnnotationsByType(MyAnnotationA.class); for (Annotation annotation11 : annotations1) { LOGGER.info("通过method.getAnnotationsByType(MyAnnotation.class)获取一类注解: " + annotation11); } Annotation[] annotations2 = getUsrMethod.getDeclaredAnnotationsByType(MyAnnotationA.class); for (Annotation annotation22 : annotations2) { LOGGER.info("通过method.getDeclaredAnnotationsByType(MyAnnotation.class)获取一类注解: " + annotation22); } System.out.println(""); //获取全部的注解 Annotation[] annotations3 = getUsrMethod.getAnnotations(); for (Annotation annotation33 : annotations3) { LOGGER.info("通过method.getAnnotations()获取全部注解: " + annotation33); } Annotation[] annotations4 = getUsrMethod.getDeclaredAnnotations(); for (Annotation annotation44 : annotations4) { LOGGER.info("通过method.getDeclaredAnnotations()获取全部注解: " + annotation44); } System.out.println(""); //获取注解参数的方法 Method initUserMethod = userClass.getDeclaredMethod("initUser", String.class, String.class); //通过method.getParameterAnnotations()获取方法的所有参数注解(二维矩阵) LOGGER.info("通过method.getParameterAnnotations()获取方法的所有参数注解(二维矩阵)"); Annotation[][] annotations5 = initUserMethod.getParameterAnnotations(); for (int i = 0; i < annotations5.length; i++) { //第一个维度标识的是第i个参数的所有注解 Annotation[] paramAnnotations = annotations5[i]; for (int j = 0; j < paramAnnotations.length; j++) { //第二个维度标识的是第i个参数的第j个注解 Annotation paramAnnotation = paramAnnotations[j]; LOGGER.info("第" + (i + 1) + "个参数,第" + (j + 1) + "个注解: " + paramAnnotation); } } System.out.println(""); LOGGER.info("// Method 调用方法 ///"); // Method 调用方法 /// User user = new User(); LOGGER.info("通过直接方法user.getUsername()获取 user.username = " + user.getUsername()); //通过method.invoke(user,args...)调用方法 LOGGER.info("通过反射方法method.invoke(user,args...)设置 user.username"); setUsrMethod.invoke(user, "张三丰"); LOGGER.info("通过反射方法method.invoke(user,args...)获取 user.username = " + getUsrMethod.invoke(user) + "\n"); //可以通过method.setAccessible(true)将私有方法private method设置为可访问的,从而操作私有方法 Method privateMethod = userClass.getDeclaredMethod("setUsernameByDefault"); LOGGER.info("私有成员变量:" + privateMethod); LOGGER.info("可以通过method.setAccessible(true)将私有方法private method设置为可访问的,从而操作私有方法"); privateMethod.setAccessible(true); LOGGER.info("操作私有成员方法" ); privateMethod.invoke(user); LOGGER.info("查看私有成员方法调用结果:" + user.toString()); } }
3.运行结果
2018-03-04 14:18:49 INFO ReflectMethodDemo:28 - // Class对象与Method对象的相互转化 / 2018-03-04 14:18:49 INFO ReflectMethodDemo:32 - 通过clazz.getMethod(name,args)获取CLass对象的指定方法:public java.lang.String pers.hanchao.reflect.common.User.getUsername() throws java.lang.NullPointerException,java.lang.ArrayStoreException 2018-03-04 14:18:49 INFO ReflectMethodDemo:33 - 通过clazz.getDeclaredMethod(name,args)获取CLass对象的指定方法:public void pers.hanchao.reflect.common.User.setUsername(java.lang.String) 2018-03-04 14:18:49 INFO ReflectMethodDemo:38 - 通过clazz.getMethods()获取CLass对象的全部方法:public java.lang.String pers.hanchao.reflect.common.User.toString() 2018-03-04 14:18:49 INFO ReflectMethodDemo:38 - 通过clazz.getMethods()获取CLass对象的全部方法:public static void pers.hanchao.reflect.common.User.test(java.lang.Object) 2018-03-04 14:18:49 INFO ReflectMethodDemo:38 - 通过clazz.getMethods()获取CLass对象的全部方法:public java.lang.String pers.hanchao.reflect.common.User.getUsername() throws java.lang.NullPointerException,java.lang.ArrayStoreException 2018-03-04 14:18:49 INFO ReflectMethodDemo:38 - 通过clazz.getMethods()获取CLass对象的全部方法:public void pers.hanchao.reflect.common.User.setUsername(java.lang.String) 2018-03-04 14:18:49 INFO ReflectMethodDemo:38 - 通过clazz.getMethods()获取CLass对象的全部方法:public void pers.hanchao.reflect.common.User.demo(java.lang.String[]) 2018-03-04 14:18:49 INFO ReflectMethodDemo:38 - 通过clazz.getMethods()获取CLass对象的全部方法:public void pers.hanchao.reflect.common.User.initUser(java.lang.String,java.lang.String) 2018-03-04 14:18:49 INFO ReflectMethodDemo:38 - 通过clazz.getMethods()获取CLass对象的全部方法:public int pers.hanchao.reflect.common.User.getPassword() 2018-03-04 14:18:49 INFO ReflectMethodDemo:38 - 通过clazz.getMethods()获取CLass对象的全部方法:public void pers.hanchao.reflect.common.User.setPassword(int) 2018-03-04 14:18:49 INFO ReflectMethodDemo:38 - 通过clazz.getMethods()获取CLass对象的全部方法:public final void java.lang.Object.wait() throws java.lang.InterruptedException 2018-03-04 14:18:49 INFO ReflectMethodDemo:38 - 通过clazz.getMethods()获取CLass对象的全部方法:public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException 2018-03-04 14:18:49 INFO ReflectMethodDemo:38 - 通过clazz.getMethods()获取CLass对象的全部方法:public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException 2018-03-04 14:18:49 INFO ReflectMethodDemo:38 - 通过clazz.getMethods()获取CLass对象的全部方法:public boolean java.lang.Object.equals(java.lang.Object) 2018-03-04 14:18:49 INFO ReflectMethodDemo:38 - 通过clazz.getMethods()获取CLass对象的全部方法:public native int java.lang.Object.hashCode() 2018-03-04 14:18:49 INFO ReflectMethodDemo:38 - 通过clazz.getMethods()获取CLass对象的全部方法:public final native java.lang.Class java.lang.Object.getClass() 2018-03-04 14:18:49 INFO ReflectMethodDemo:38 - 通过clazz.getMethods()获取CLass对象的全部方法:public final native void java.lang.Object.notify() 2018-03-04 14:18:49 INFO ReflectMethodDemo:38 - 通过clazz.getMethods()获取CLass对象的全部方法:public final native void java.lang.Object.notifyAll() 2018-03-04 14:18:49 INFO ReflectMethodDemo:42 - 通过clazz.getDeclaredMethods()获取CLass对象的全部方法:public java.lang.String pers.hanchao.reflect.common.User.toString() 2018-03-04 14:18:49 INFO ReflectMethodDemo:42 - 通过clazz.getDeclaredMethods()获取CLass对象的全部方法:public static void pers.hanchao.reflect.common.User.test(java.lang.Object) 2018-03-04 14:18:49 INFO ReflectMethodDemo:42 - 通过clazz.getDeclaredMethods()获取CLass对象的全部方法:public java.lang.String pers.hanchao.reflect.common.User.getUsername() throws java.lang.NullPointerException,java.lang.ArrayStoreException 2018-03-04 14:18:49 INFO ReflectMethodDemo:42 - 通过clazz.getDeclaredMethods()获取CLass对象的全部方法:public void pers.hanchao.reflect.common.User.setUsername(java.lang.String) 2018-03-04 14:18:49 INFO ReflectMethodDemo:42 - 通过clazz.getDeclaredMethods()获取CLass对象的全部方法:public void pers.hanchao.reflect.common.User.demo(java.lang.String[]) 2018-03-04 14:18:49 INFO ReflectMethodDemo:42 - 通过clazz.getDeclaredMethods()获取CLass对象的全部方法:public void pers.hanchao.reflect.common.User.initUser(java.lang.String,java.lang.String) 2018-03-04 14:18:49 INFO ReflectMethodDemo:42 - 通过clazz.getDeclaredMethods()获取CLass对象的全部方法:private void pers.hanchao.reflect.common.User.setUsernameByDefault() 2018-03-04 14:18:49 INFO ReflectMethodDemo:42 - 通过clazz.getDeclaredMethods()获取CLass对象的全部方法:public int pers.hanchao.reflect.common.User.getPassword() 2018-03-04 14:18:49 INFO ReflectMethodDemo:42 - 通过clazz.getDeclaredMethods()获取CLass对象的全部方法:public void pers.hanchao.reflect.common.User.setPassword(int) 2018-03-04 14:18:49 INFO ReflectMethodDemo:48 - 通过method.getDeclaringClass()获取当前Method对象所属的Class:class pers.hanchao.reflect.common.User 2018-03-04 14:18:49 INFO ReflectMethodDemo:51 - // Method信息获取 / 2018-03-04 14:18:49 INFO ReflectMethodDemo:53 - 通过method.getModifiers()获取方法修饰符的int值public 2018-03-04 14:18:49 INFO ReflectMethodDemo:56 - 通过method.getName()获取方法名getUsername 2018-03-04 14:18:49 INFO ReflectMethodDemo:59 - 通过method.getGenericReturnType()获取返回值的类型(Type):class java.lang.String 2018-03-04 14:18:49 INFO ReflectMethodDemo:61 - 通过method.getReturnType()获取返回值的类(Class):class java.lang.String 2018-03-04 14:18:49 INFO ReflectMethodDemo:66 - 通过method.getGenericParameterTypes()获取参数的类型(Type):java.lang.String 2018-03-04 14:18:49 INFO ReflectMethodDemo:71 - 通过method.getParameterTypes()获取参数的类(Class):class java.lang.String 2018-03-04 14:18:49 INFO ReflectMethodDemo:77 - 通过method.getParameters()获取参数(Parameter)数组:java.lang.String arg0 2018-03-04 14:18:49 INFO ReflectMethodDemo:83 - 通过method.getGenericExceptionTypes()获取异常的类型(Type):java.lang.NullPointerException 2018-03-04 14:18:49 INFO ReflectMethodDemo:83 - 通过method.getGenericExceptionTypes()获取异常的类型(Type):java.lang.ArrayStoreException 2018-03-04 14:18:49 INFO ReflectMethodDemo:88 - 通过method.getExceptionTypes()获取异常的类(Class):class java.lang.NullPointerException 2018-03-04 14:18:49 INFO ReflectMethodDemo:88 - 通过method.getExceptionTypes()获取异常的类(Class):class java.lang.ArrayStoreException 2018-03-04 14:18:49 INFO ReflectMethodDemo:93 - 通过method.toString()获取方法的字符串描述:public java.lang.String pers.hanchao.reflect.common.User.getUsername() throws java.lang.NullPointerException,java.lang.ArrayStoreException 2018-03-04 14:18:49 INFO ReflectMethodDemo:94 - 通过method.toGenericString()获取方法的字符串描述(包括通用类型):public java.lang.String pers.hanchao.reflect.common.User.getUsername() throws java.lang.NullPointerException,java.lang.ArrayStoreException 2018-03-04 14:18:49 INFO ReflectMethodDemo:97 - 通过equals()比较两个方法是否相同:false 2018-03-04 14:18:49 INFO ReflectMethodDemo:99 - 通过method.isBridge()判断是否是桥方法:false 2018-03-04 14:18:49 INFO ReflectMethodDemo:101 - 通过method.isSynthetic()判断是否是合成方法:false 2018-03-04 14:18:49 INFO ReflectMethodDemo:104 - 通过method.isVarArgs()判断是否使用了可变参数:true 2018-03-04 14:18:49 INFO ReflectMethodDemo:107 - 通过method.getParameterCount()获取参数个数,setUsername = 1 2018-03-04 14:18:49 INFO ReflectMethodDemo:108 - 通过method.getParameterCount()获取参数个数,getUsername = 0 2018-03-04 14:18:49 INFO ReflectMethodDemo:111 - 通过method.getDefaultValue()获取默认返回值,setUsername = null 2018-03-04 14:18:49 INFO ReflectMethodDemo:112 - 通过method.getDefaultValue()获取默认返回值,getUsrMethod = null 2018-03-04 14:18:49 INFO ReflectMethodDemo:116 - 通过method.getTypeParameters()获取泛型方法的参数化类型(泛型),getUsrMethod()的参数化类型个数:0 2018-03-04 14:18:49 INFO ReflectMethodDemo:119 - 通过method.getTypeParameters()获取泛型方法的参数化类型(泛型),ReflectMethodDemo.test()的参数化类型:T 2018-03-04 14:18:49 INFO ReflectMethodDemo:122 - // Method注解信息获取 / 2018-03-04 14:18:49 INFO ReflectMethodDemo:125 - 通过method.getAnnotatedReturnType()获取被注解的返回值类型(组合类型):sun.reflect.annotation.AnnotatedTypeFactory$AnnotatedTypeBaseImpl@79fc0f2f 2018-03-04 14:18:49 INFO ReflectMethodDemo:127 - 通过annotatedType.getType()获取被注解的返回值类型中的返回值类型:class java.lang.String 2018-03-04 14:18:49 INFO ReflectMethodDemo:130 - 通过annotatedType.getAnnotations()获取被注解的返回值类型中的注解类型 2018-03-04 14:18:49 INFO ReflectMethodDemo:134 - 类似于method.getAnnotatedReturnType()的还有: method.getAnnotatedParameterTypes() 2018-03-04 14:18:49 INFO ReflectMethodDemo:135 - 类似于method.getAnnotatedReturnType()的还有: method.getAnnotatedExceptionTypes() 2018-03-04 14:18:49 INFO ReflectMethodDemo:136 - 类似于method.getAnnotatedReturnType()的还有: method.getAnnotatedReceiverType() 2018-03-04 14:18:49 INFO ReflectMethodDemo:141 - 通过method.getAnnotation(Annotation.class)获取指定的注解: @pers.hanchao.reflect.common.MyAnnotationA() 2018-03-04 14:18:49 INFO ReflectMethodDemo:142 - 通过method.getDeclaredAnnotation(Annotation.class)获取指定的注解 :@pers.hanchao.reflect.common.MyAnnotationB() 2018-03-04 14:18:49 INFO ReflectMethodDemo:146 - 通过method.getAnnotationsByType(MyAnnotation.class)获取一类注解: @pers.hanchao.reflect.common.MyAnnotationA() 2018-03-04 14:18:49 INFO ReflectMethodDemo:150 - 通过method.getDeclaredAnnotationsByType(MyAnnotation.class)获取一类注解: @pers.hanchao.reflect.common.MyAnnotationA() 2018-03-04 14:18:49 INFO ReflectMethodDemo:156 - 通过method.getAnnotations()获取全部注解: @pers.hanchao.reflect.common.MyAnnotationA() 2018-03-04 14:18:49 INFO ReflectMethodDemo:156 - 通过method.getAnnotations()获取全部注解: @pers.hanchao.reflect.common.MyAnnotationB() 2018-03-04 14:18:49 INFO ReflectMethodDemo:160 - 通过method.getDeclaredAnnotations()获取全部注解: @pers.hanchao.reflect.common.MyAnnotationA() 2018-03-04 14:18:49 INFO ReflectMethodDemo:160 - 通过method.getDeclaredAnnotations()获取全部注解: @pers.hanchao.reflect.common.MyAnnotationB() 2018-03-04 14:18:49 INFO ReflectMethodDemo:167 - 通过method.getParameterAnnotations()获取方法的所有参数注解(二维矩阵) 2018-03-04 14:18:49 INFO ReflectMethodDemo:175 - 第1个参数,第1个注解: @pers.hanchao.reflect.common.MyAnnotationA() 2018-03-04 14:18:49 INFO ReflectMethodDemo:175 - 第1个参数,第2个注解: @pers.hanchao.reflect.common.MyAnnotationB() 2018-03-04 14:18:49 INFO ReflectMethodDemo:175 - 第2个参数,第1个注解: @pers.hanchao.reflect.common.MyAnnotationB() 2018-03-04 14:18:49 INFO ReflectMethodDemo:180 - // Method 调用方法 /// 2018-03-04 14:18:49 INFO ReflectMethodDemo:183 - 通过直接方法user.getUsername()获取 user.username = 张三 2018-03-04 14:18:49 INFO ReflectMethodDemo:185 - 通过反射方法method.invoke(user,args...)设置 user.username 2018-03-04 14:18:49 INFO ReflectMethodDemo:187 - 通过反射方法method.invoke(user,args...)获取 user.username = 张三丰 2018-03-04 14:18:49 INFO ReflectMethodDemo:190 - 私有成员变量:private void pers.hanchao.reflect.common.User.setUsernameByDefault() 2018-03-04 14:18:49 INFO ReflectMethodDemo:191 - 可以通过method.setAccessible(true)将私有方法private method设置为可访问的,从而操作私有方法 2018-03-04 14:18:49 INFO ReflectMethodDemo:193 - 操作私有成员方法 2018-03-04 14:18:49 INFO ReflectMethodDemo:195 - 查看私有成员方法调用结果:User{username='default', password='123456'}
4.总结
根据代码实例和运行结果,总结如下:
- Class对象与Method对象的相互转化
- 通过clazz.getMethod(name,args…)和clazz.getDeclaredMethod(name,args…)获取CLass对象的指定方法
- 通过clazz.getMethods()和clazz.getDeclaredMethods()获取CLass对象的全部方法
- 通过method.getDeclaringClass()获取当前Method对象所属的Class
- Method信息获取
- 通过method.getModifiers()获取方法修饰符的int值
- 通过method.getName()获取方法名
- 通过method.getGenericReturnType()获取返回值的类型(Type),method.getReturnType()获取返回值的类(Class)
- 通过method.getGenericParameterTypes()获取参数的类型(Type),method.getParameterTypes()获取参数的类(Class)
- 通过method.getParameters()获取参数对象(Parameter[])数组
- 通过method.getGenericExceptionTypes()获取异常的类型(Type),method.getExceptionTypes()获取异常的类(Class)
- 通过method.toString()和method.toGenericString()获取方法的字符串描述
- 通过equals()比较两个方法是否相同
- 通过method.isBridge()判断是否是桥方法
- 通过method.isSynthetic()判断是否是合成方法
- 通过method.isVarArgs()判断是否使用了可变参数
- 通过method.getParameterCount()获取参数个数
- 通过method.getDefaultValue()获取默认返回值
- 通过method.getTypeParameters()获取泛型方法的参数化类型(泛型)
- 通过method.getAnnotatedXxxxType()获取被注解的类型(组合类型),Xxxx=[Return,Parameter,Exception,Receiver]
- 通过method.getAnnotation(Annotation.class)和method.getDeclaredAnnotation(Annotation.class)获取指定的注解
- 通过method.getAnnotationsByType(MyAnnotation.class)和method.getDeclaredAnnotationsByType(MyAnnotation.class)获取一组注解
- 通过method.getAnnotations()和method.getDeclaredAnnotations()获取全部注解
- 通过method.getParameterAnnotations()获取方法的所有参数注解(二维矩阵),数组元素表示第i个参数的第j个注解。
- Method调用方法
- 通过method.invoke(user,args…)调用方法
- 可以通过method.setAccessible(true)将私有方法private method设置为可访问的,从而操作私有方法
备注:
- 有关获取Class对象的三种方式参见:Java反射02 : Class对象获取的三种方式和通过反射实例化对象的两种方式
- 有关getXxxx和getDeclaredXxxx参见:Java反射 : Declared的作用 ( 例如 : getMethods和getDeclaredMethods )
- 有关Class与Type参见: Java中Type接口与Class类的区别联系
- 有关参数化类型(泛型)参见系列:Java泛型学习系列-绪论
- 有关参数类(Parameter)参见后续章节:Java反射09 : 参数Parameter学习示例
- 使用成员方法Method进行反射编程的主要用法:通过成员方法Method进行方法(包括private)调用
-
Java Method 类
2020-03-04 18:10:13本文介绍了 Java 中 Method 类的相关内容。。。 -
java入门(六) | 方法(Method)的定义和使用
2021-03-08 18:13:32上一期是对java的分支结构进行...这一期是对方法method的介绍,它也被称之为函数,它的基本格式为:方法的修饰符 方法的返回值 方法的名字 ( 参数列表 ) { 代码/方法体 }1、方法1.1 概述Java语言中的“方法”(Metho... -
Java反射之Method的invoke方法实现
2020-11-11 21:55:35在框架中经常会会用到method.invoke()方法,用来执行某个的对象的目标方法。以前写代码用到反射时,总是获取先获取Method,然后传入对应的Class实例对象执行方法。然而前段时间研究invoke方法时,发现invoke方法居然... -
springboot运行一段时间报错 nvalid character found in method name. HTTP method names must be tokens
2021-03-29 13:40:19java.lang.IllegalArgumentException: Invalid character found in method name [0x160x030x010x020x000x010x000x010xfc0x030x030x920xff0xdbN0xb40x890xa8q0x9d0x1c0xde0x0dZ0xb6:0xb00xbe0xd8_0x850xb10x950xeeB0... -
SpringBoot:Invalid character found in method name. HTTP method names must be tokens
2018-09-10 22:24:47关于SpringBoot应用挂了很久之后,会发生Invalid character found in method name. HTTP method names must be tokens的问题。 解决方案 据说是tomcat 的设置问题,如果出现相关情况,可以设置一下application.... -
MybatisPlusException: Error: Method queryTotal execution error of sql 的报错解决
2020-05-25 19:52:3862) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.web.method.support.... -
编译报错: error: method does not override or implement a method from a supertype
2021-09-17 13:53:52error: method does not override or implement a method from a supertype @Override error: TestDocumentClipper is not abstract and does not override abstract method copyFromClipboard(DocumentInfo,... -
从Method中获取完整类名和方法名
2021-03-06 23:11:45需求假设:假设在包com.zhoutao.controller下有方法getKey()方法,在JavaEE中,通过AOP获得该方法的的对象method,现在通过该对象的getName方法,仅仅只能获得getKey的结果,现在我需要的是...查找官方API并未发现此方法... -
Error: Method queryTotal execution error. 报错解决
2019-01-10 16:09:49Error: Method queryTotal execution error. [已解决] 先看错误代码: org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException: ### Error querying ... -
IDEA警告:Boolean method ‘xxx‘ is always inverted
2020-08-06 14:25:06文章目录IDEA警告:Boolean method ‘xxx‘ is always inverted1、如图2、说明3、IDEA 提供的解决方案 IDEA警告:Boolean method ‘xxx‘ is always inverted 1、如图 2、说明 你的方法的返回值是一个布尔值,但是... -
HV000151: A method overriding another method must not redefine the parameter 2021-07-29
2021-07-29 19:23:55} } 引发的 HV000151: A method overriding another method must not redefine the parameter constraint configuration, but method FaController #category(FaDto) redefines the configuration of FaApi#... -
Springboot中如何自定义init-method和destroy-method
2020-10-10 21:49:48如果我们想在初始化某个bean对象时自定义自己的init-method和destroy-method方法,我们可以使用通过Java配置文件方式注入要自定义自己init-method和destroy方法的bean,然后通过注解指定init-method和destroy-method... -
【小家Spring】探索Spring AOP中aopalliance的Joinpoint、MethodInvocation、Interceptor、...
2019-04-09 16:41:08前言 在这篇博文:【小家Spring】详解Spring AOP中底层代理...我们已经能够知道了,代理对象创建好后,其实最终的拦截工作都是交给了MethodInvocation,JDK交给:ReflectiveMethodInvocation,CGLIB交给CglibMeth... -
OpenSSL中那些方法之ssl_method_st
2018-05-03 21:47:23在ssl_locl.h中定义了整个协议栈结构的三个非常重要的结构体ssl_ctx_st,ssl_st以及ssl_method_st。本次主要分析结构体变量ssl_method_st,因此其他的结构暂且不表。 -
fiddler如何添加RequestMethod列
2021-11-10 16:41:30fiddler刚开始是默认没有RequestMethod这一列的 添加步骤: 1、在该横栏的空白处右键,如图 2、选择Customizecolimns,会跳转如下: 3、在cllection里选择最后的Miscellaneous 4、在field name处选择 ... -
报错为method does not override method from its superclass解决
2020-11-30 14:49:07你要重写接口的方法就得让实现类实现接口 public class UserServiceImpl implements UserService{} 没有实现接口就加重写注解@Override,系统不知道重写了什么接口方法,肯定报错 建议巩固一下接口方面的知识 ... -
Spring AOP MethodInvocation拦截器调用原理
2020-04-03 21:31:35前言 通过对JdkDynamicAopProxy的invoke方法的探究,发现invoke的核心是: 由匹配当前方法的advisor,例如与当前方法所匹配的所有before、...MethodInvocation invocation = new ReflectiveMethodInvocation(pro... -
HTTP ERROR 405 Method Not Allowed
2022-04-14 20:37:44一般访问web UI的时候出现以上错误,都是浏览器的防火墙问题 可以进行在安全设置里取消一些防护功能即可 -
【python】@abstractmethod的用法
2021-09-24 17:04:33见下图的代码,基类Foo的fun方法被@abstractmethod装饰了,所以Foo不能被实例化;子类SubA没有实现基类的fun方法也不能被实例化;子类SubB实现了基类的抽象方法fun所以能实例化。 完整代码: 在Python3.4中,... -
Request Method OPTIONS
2020-10-11 23:44:12最近在devtools查看接口时发现前端每次都会请求两遍接口,带着好奇的心理,发现每次多的一次请求都是OPTIONS请求。 然后网上查了一番,发现这个其实和CORS有关系。很多时候,浏览器为了确定服务端能够接受本次请求... -
method call expected
2020-08-30 11:48:09这个报错是因为: List是对象,不是方法,对象要用new 创建 -
Python中function和method
2018-02-03 00:55:02这两个概念已经有很多人解释过了,从本文的『参考』中就可以看出来。...method通常是面向对象的概念,即method是属于一个类或类的对象的。method是与类或类的对象相关的函数。 下面讲一下我对这两个概念的更具 -
@RequestMapping注解中的method属性
2021-07-16 17:03:21method属性 method属性用来指示方法仅仅处理哪些http请求方式,可支持一个或多个请求方式。 @RequestMapping("/hello",method=RequestMethod.POST)表示只支持POST请求方式。 @RequestMapping("/hello",method={... -
Channel shutdown: connection error; protocol method: #method<connection.close>
2021-03-09 17:12:042019-09-24 13:05:30.145 ERROR 8444 — [168.47.131:5672] o.s.a.r.c.... protocol method: #method<connection.close>(reply-code=503, reply-text=COMMAND_INVALID - unknown exchange type ‘x-del -
Channel shutdown: channel error; protocol method: #method(reply-code=406, reply-text=
2022-04-18 10:05:23protocol method: #method<channel.close>(reply-code=406, reply-text=PRECONDITION_FAILED - unknown delivery tag 1, class-id=60, method-id=80) 在配置文件中配置了手动签收 spring: rabbitmq: ... -
关于A method overriding another method must not redefine the parameter constraint configuration解决...
2021-03-01 14:44:15关于A method overriding another method must not redefine the parameter constraint configuration解决方法 使用的@Validated校验参数接口参数和实现类参数要保持一直,不然会报错。 接口: 实现类: