源码篇--MethodIntrospector.selectMethods 获取类中符合条件的方法


前言

Spring 提供了MethodIntrospector 可以传入类以及筛选条件获取到符合该条件的方法集合,本文通过源码方式介绍其工作的内容。


一、MethodIntrospector 作用:

MethodIntrospector是Spring Framework中的一个工具类,主要用于对类进行方法的分析和筛选。

具体来说,MethodIntrospector类提供了一个selectMethods静态方法,该方法可以根据传入的MethodFilter接口实例或MetadataLookup接口实例来选择类中符合条件的方法。MethodFilter接口用于定义筛选条件,可以通过实现matches方法决定哪些方法应该被选择,而MetadataLookup接口则可以用来在选择方法时进行元数据查找。

通过MethodIntrospector类,可以方便地对类中的方法进行筛选和分析,例如选择带有特定注解的方法、选择符合特定条件的方法等。这在编写通用性较高的框架或工具类时非常有用,可以提高代码的灵活性和可复用性。

二、 案例:

利用MethodIntrospector.selectMethods 获取类中标识了 MyAnnotation 注解的方法;


import com.xxl.job.core.handler.annotation.XxlJob;
import org.springframework.core.MethodIntrospector;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.ReflectionUtils;

import java.lang.annotation.*;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Set;

public class MethodSelectorDemo {

    public static void main(String[] args) {
        // 定义一个目标类
        Class<MyClass> clazz = MyClass.class;

        // 使用MethodIntrospector.selectMethods方法,选择出不带参数的方法
        Set<Method> selectedMethods = MethodIntrospector.selectMethods(clazz,
                new ReflectionUtils.MethodFilter() {
                    @Override
                    public boolean matches(Method method) {
                        return AnnotationUtils.findAnnotation(method, MyAnnotation.class) != null;
                    }
                });
        // 遍历选择出的方法
        for (Method selectedMethod : selectedMethods) {
            System.out.println("Method with annotation: " + selectedMethod.getName());
        }

        Map<Method, MyAnnotation> annotatedMethods = MethodIntrospector.selectMethods(clazz,
                new MethodIntrospector.MetadataLookup<MyAnnotation>() {
                    @Override
                    public MyAnnotation inspect(Method method) {
                        return AnnotatedElementUtils.findMergedAnnotation(method, MyAnnotation.class);
                    }
                });

        for (Map.Entry<Method, MyAnnotation> methodMyAnnotationEntry : annotatedMethods.entrySet()) {
            System.out.println("Method with annotation: " +  methodMyAnnotationEntry.getKey().getName());
        }


    }

    static class MyClass {
        @MyAnnotation("test")
        public void doSomething() {
            // do something
        }

        public void doAnotherThing(String param) {
            // do another thing
        }
    }
    @Target({ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @Inherited
    public @interface MyAnnotation {

        /**
         * jobhandler name
         */
        String value();

        /**
         * init handler, invoked when JobThread init
         */
        String init() default "";

        /**
         * destroy handler, invoked when JobThread destroy
         */
        String destroy() default "";
    }
}

三、MethodIntrospector 源码内容

3.1 selectMethods 方法:

MethodIntrospector 提供了两个MethodIntrospector 来进行方法的筛选;

3.1.1 selectMethods(Class<?> targetType, MetadataLookup metadataLookup):

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.springframework.core;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;

public final class MethodIntrospector {
    private MethodIntrospector() {
    }
	/**
	* targetType 某个类 class 对象
	*  MetadataLookup 实现了 MetadataLookup类下 inspect 方法的函数是接口
	**/
    public static <T> Map<Method, T> selectMethods(Class<?> targetType, MetadataLookup<T> metadataLookup) {
        Map<Method, T> methodMap = new LinkedHashMap();
        Set<Class<?>> handlerTypes = new LinkedHashSet();
        Class<?> specificHandlerType = null;
        // 判断是否是被代理的类
        if (!Proxy.isProxyClass(targetType)) {
            specificHandlerType = ClassUtils.getUserClass(targetType);
            handlerTypes.add(specificHandlerType);
        }
		// 获取指定类targetType实现的所有接口的集合
        handlerTypes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetType));
        Iterator var5 = handlerTypes.iterator();

        while(var5.hasNext()) {
        	// 遍历类
            Class<?> currentHandlerType = (Class)var5.next();
            Class<?> targetClass = specificHandlerType != null ? specificHandlerType : currentHandlerType;
            // doWithMethods 遍历本类及其父类
            ReflectionUtils.doWithMethods(currentHandlerType, (method) -> {
            	// 获取类中真正要去执行的方法
                Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
                // inspect 接口调用
                T result = metadataLookup.inspect(specificMethod);
                if (result != null) {
                	// 如果result  不为null 则说明 条件匹配
                    Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
                    // 获取方法并放入到 methodMap map 集合 key 为方法,value 为 inspect 方法返回的值
                    if (bridgedMethod == specificMethod || metadataLookup.inspect(bridgedMethod) == null) {
                        methodMap.put(specificMethod, result);
                    }
                }

            }, ReflectionUtils.USER_DECLARED_METHODS);
        }
		// 返回map 集合
        return methodMap;
    }

    @FunctionalInterface
    public interface MetadataLookup<T> {
        @Nullable
        T inspect(Method var1);
    }
}

改方法针对下面的调用:通过MethodIntrospector.MetadataLookup 重写 inspect 类

Map<Method, MyAnnotation> annotatedMethods = MethodIntrospector.selectMethods(clazz,
         new MethodIntrospector.MetadataLookup<MyAnnotation>() {
             @Override
             public MyAnnotation inspect(Method method) {
                 return AnnotatedElementUtils.findMergedAnnotation(method, MyAnnotation.class);
             }
         });

 for (Map.Entry<Method, MyAnnotation> methodMyAnnotationEntry : annotatedMethods.entrySet()) {
     System.out.println("Method with annotation: " +  methodMyAnnotationEntry.getKey().getName());
 }

3.1.2 selectMethods(Class<?> targetType, ReflectionUtils.MethodFilter methodFilter):

public static Set<Method> selectMethods(Class<?> targetType, ReflectionUtils.MethodFilter methodFilter) {
    // selectMethods 会调用到   selectMethods(Class<?> targetType, MetadataLookup<T> metadataLookup) 方法
    /**
    * 其中 method 部分:会被封装为 MetadataLookup 的函数式接口 { } 中的部分作为inspect 方法的实现逻辑;
    *    T result = metadataLookup.inspect(specificMethod) 调用inspect 会回调到  { } 中的部分
    *    进而回调到 我我们自己业务中 覆盖的 matches 方法
    * (method) -> {
        return methodFilter.matches(method) ? Boolean.TRUE : null;
    }
    **/
    return selectMethods(targetType, (method) -> {
        return methodFilter.matches(method) ? Boolean.TRUE : null;
    }).keySet();
}

改方法针对下面的调用:通过MethodIntrospector.selectMethods 重写 matches类

 // 定义一个目标类
 Class<MyClass> clazz = MyClass.class;

 // 使用MethodIntrospector.selectMethods方法,选择出不带参数的方法
 Set<Method> selectedMethods = MethodIntrospector.selectMethods(clazz,
         new ReflectionUtils.MethodFilter() {
             @Override
             public boolean matches(Method method) {
                 return AnnotationUtils.findAnnotation(method, MyAnnotation.class) != null;
             }
         });
 // 遍历选择出的方法
 for (Method selectedMethod : selectedMethods) {
     System.out.println("Method with annotation: " + selectedMethod.getName());
 }

总结

本文对MethodIntrospector.selectMethods 获取类中符合条件的方法源码内容进行介绍。

  • 36
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
安装 MySQL 源码可以分为以下几个步骤: 1. 下载 MySQL 源码包:可以从 MySQL 官网下载最新的 MySQL 源码包,也可以从镜像站点下载。这里以 MySQL 8.0.20 版本的源码包为例,下载地址为:https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-boost-8.0.20.tar.gz 2. 解压源码包:使用以下命令解压源码包: ``` tar -zxvf mysql-boost-8.0.20.tar.gz ``` 3. 安装依赖库:在编译安装 MySQL 前需要安装一些依赖库,以 CentOS 7 为例,可以使用以下命令安装: ``` yum install -y cmake make gcc gcc-c++ bison ncurses-devel zlib-devel openssl-devel ``` 4. 创建 MySQL 用户和用户组:使用以下命令创建 MySQL 用户和用户组: ``` groupadd mysql useradd -r -g mysql -s /bin/false mysql ``` 5. 编译安装 MySQL:使用以下命令编译和安装 MySQL: ``` cd mysql-boost-8.0.20 cmake . -DCMAKE_INSTALL_PREFIX=/usr/local/mysql \ -DMYSQL_DATADIR=/usr/local/mysql/data \ -DDOWNLOAD_BOOST=1 -DWITH_BOOST=/usr/local/boost \ -DWITH_SSL=system -DWITH_INNODB_MEMCACHE=ON \ -DWITH_INNOBASE_STORAGE_ENGINE=ON \ -DWITH_MYISAM_STORAGE_ENGINE=ON \ -DENABLED_LOCAL_INFILE=1 \ -DWITH_DEBUG=0 make -j4 make install ``` 注意:上述命令中需要根据自己的实际情况修改安装路径和 Boost 库路径。 6. 配置 MySQL:使用以下命令配置 MySQL: ``` cd /usr/local/mysql cp support-files/my-default.cnf /etc/my.cnf bin/mysqld --initialize --user=mysql --basedir=/usr/local/mysql --datadir=/usr/local/mysql/data ``` 注意:上述命令中需要根据自己的实际情况修改 MySQL 的安装路径和数据存储路径。 7. 启动 MySQL:使用以下命令启动 MySQL: ``` bin/mysqld_safe --user=mysql & ``` 注意:上述命令中需要根据自己的实际情况修改 MySQL 的安装路径和用户。 8. 修改 MySQL 密码:使用以下命令修改 MySQL root 用户的密码: ``` bin/mysqladmin -u root password 'new-password' ``` 注意:上述命令中需要将 'new-password' 替换为自己的密码。 9. 连接 MySQL:使用以下命令连接 MySQL: ``` bin/mysql -u root -p ``` 注意:上述命令中需要输入 MySQL root 用户的密码。 至此,MySQL 源码安装完成。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值