精华内容
下载资源
问答
  • method
    千次阅读
    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步:

    1. 检查override,如果override为true,跳过检查;否则继续;
    2. 快速检查,判断该方法的修饰符modifiers是否为public,如果是跳过检查;否则继续;
    3. 详细检查,通过方法的(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的实现机制。

    copy

    在前面代码中,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的委托类设置为这个生成的代理对象。这么说可能有点绕,下面用一幅图表示这个过程。

    delegate

    总体来说,当调用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();

    openJDK下载地址

    首先,在\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深入研究——Method的Invoke方法

    展开全文
  • Java反射08 : 成员方法Method学习示例

    千次阅读 2018-03-04 14:36:42
    java.lang.reflect.Method类提供了用于获取和操作成员方法的静态方法。 1.通过Method可以做什么 通过Method可以做以下事情: 如何通过Class对象获取Method?如何通过Method对象获取Class? 如何通过Method获取...

    超级通道: Java泛型学习系列-绪论

    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对象所属的Classclass 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()获取方法修饰符的intpublic
    
    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对象的相互转化
      1. 通过clazz.getMethod(name,args…)和clazz.getDeclaredMethod(name,args…)获取CLass对象的指定方法
      2. 通过clazz.getMethods()和clazz.getDeclaredMethods()获取CLass对象的全部方法
      3. 通过method.getDeclaringClass()获取当前Method对象所属的Class
    • Method信息获取
      1. 通过method.getModifiers()获取方法修饰符的int值
      2. 通过method.getName()获取方法名
      3. 通过method.getGenericReturnType()获取返回值的类型(Type),method.getReturnType()获取返回值的类(Class)
      4. 通过method.getGenericParameterTypes()获取参数的类型(Type),method.getParameterTypes()获取参数的类(Class)
      5. 通过method.getParameters()获取参数对象(Parameter[])数组
      6. 通过method.getGenericExceptionTypes()获取异常的类型(Type),method.getExceptionTypes()获取异常的类(Class)
      7. 通过method.toString()和method.toGenericString()获取方法的字符串描述
      8. 通过equals()比较两个方法是否相同
      9. 通过method.isBridge()判断是否是桥方法
      10. 通过method.isSynthetic()判断是否是合成方法
      11. 通过method.isVarArgs()判断是否使用了可变参数
      12. 通过method.getParameterCount()获取参数个数
      13. 通过method.getDefaultValue()获取默认返回值
      14. 通过method.getTypeParameters()获取泛型方法的参数化类型(泛型)
      15. 通过method.getAnnotatedXxxxType()获取被注解的类型(组合类型),Xxxx=[Return,Parameter,Exception,Receiver]
      16. 通过method.getAnnotation(Annotation.class)和method.getDeclaredAnnotation(Annotation.class)获取指定的注解
      17. 通过method.getAnnotationsByType(MyAnnotation.class)和method.getDeclaredAnnotationsByType(MyAnnotation.class)获取一组注解
      18. 通过method.getAnnotations()和method.getDeclaredAnnotations()获取全部注解
      19. 通过method.getParameterAnnotations()获取方法的所有参数注解(二维矩阵),数组元素表示第i个参数的第j个注解。
    • Method调用方法
      1. 通过method.invoke(user,args…)调用方法
      2. 可以通过method.setAccessible(true)将私有方法private method设置为可访问的,从而操作私有方法

    备注:

    展开全文
  • Java Method

    千次阅读 2020-03-04 18:10:13
    本文介绍了 Java 中 Method 类的相关内容。。。
  • 上一期是对java的分支结构进行...这一期是对方法method的介绍,它也被称之为函数,它的基本格式为:方法的修饰符 方法的返回值 方法的名字 ( 参数列表 ) { 代码/方法体 }1、方法1.1 概述Java语言中的“方法”(Metho...
  • Java反射之Method的invoke方法实现

    千次阅读 2020-11-11 21:55:35
    在框架中经常会会用到method.invoke()方法,用来执行某个的对象的目标方法。以前写代码用到反射时,总是获取先获取Method,然后传入对应的Class实例对象执行方法。然而前段时间研究invoke方法时,发现invoke方法居然...
  • java.lang.IllegalArgumentException: Invalid character found in method name [0x160x030x010x020x000x010x000x010xfc0x030x030x920xff0xdbN0xb40x890xa8q0x9d0x1c0xde0x0dZ0xb6:0xb00xbe0xd8_0x850xb10x950xeeB0...
  • 关于SpringBoot应用挂了很久之后,会发生Invalid character found in method name. HTTP method names must be tokens的问题。 解决方案 据说是tomcat 的设置问题,如果出现相关情况,可以设置一下application....
  • 62) 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 @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. [已解决] 先看错误代码: org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException: ### Error querying ...
  • 文章目录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 constraint configuration, but method FaController #category(FaDto) redefines the configuration of FaApi#...
  • 如果我们想在初始化某个bean对象时自定义自己的init-method和destroy-method方法,我们可以使用通过Java配置文件方式注入要自定义自己init-method和destroy方法的bean,然后通过注解指定init-method和destroy-method...
  • 前言 在这篇博文:【小家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:30
    fiddler刚开始是默认没有RequestMethod这一列的 添加步骤: 1、在该横栏的空白处右键,如图 2、选择Customizecolimns,会跳转如下: 3、在cllection里选择最后的Miscellaneous 4、在field name处选择 ...
  • 你要重写接口的方法就得让实现类实现接口 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:21
    method属性 method属性用来指示方法仅仅处理哪些http请求方式,可支持一个或多个请求方式。 @RequestMapping("/hello",method=RequestMethod.POST)表示只支持POST请求方式。 @RequestMapping("/hello",method={...
  • 2019-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
  • protocol 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解决方法 使用的@Validated校验参数接口参数和实现类参数要保持一直,不然会报错。 接口: 实现类:

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,348,421
精华内容 1,339,368
关键字:

method