MyBatis-ResolverUtil

ResolverUtil
ResolverUtil用于查找在类路径可用并满足条件的类。最常见的两种条件是判断一个类是否继承或实现了另一个类 ,比如:IsA 类的matches方法。或者判断此类是否被指定的注解标记了比如:AnnotatedWith 类的matches方法。然而,通过实现Test类,自己编写matches的逻辑,可以满足相对应的条件搜索。

其中有一个接口、两个内部类。用到的设计模式原则之开放-封闭原则,对于扩展是开放的(Open for extension),对于更改是封闭的(Closed for modification)。
1.0
如此设计:
我们可以自己实现Test接口,调用find方法时以参数的形式传入,而不用修改ResolverUtil的内部方法。这是我自定义的类并实现Test 接口,这里可以写自己想定义的逻辑。

public class Testtest implements Test {
    @Override
    public boolean matches(Class<?> type) {
        if (type == Testtest.class) {
            return true;
        }
        return false;
    }

}

看看Test接口和两个内部类是怎样的:

public class ResolverUtil<T> {
	private static final Log log = LogFactory.getLog(ResolverUtil.class);

	//定义Test接口
	public interface Test {
	    boolean matches(Class<?> type);
  	}
	
	//IsA方法实现Test接口
	public static class IsA implements Test {
	
	    private Class<?> parent;
	    
	    public IsA(Class<?> parentType) {
	      this.parent = parentType;
	    }

		/*
		parent类是否是type类的父类
		isAssignableFrom方法解释可以看这篇文章
		https://blog.csdn.net/qq_36666651/article/details/81215221
		*/
	    @Override
	    public boolean matches(Class<?> type) {
	      return type != null && parent.isAssignableFrom(type);
	    }
	
	    @Override
	    public String toString() {
	      return "is assignable to " + parent.getSimpleName();
	    }
	  }

	//AnnotatedWith方法实现Test接口
	public static class AnnotatedWith implements Test {
	    private Class<? extends Annotation> annotation;
	
	    
	    public AnnotatedWith(Class<? extends Annotation> annotation) {
	      this.annotation = annotation;
	    }
		/*
		注解annotation否是在type类上
		isAnnotationPresent方法解释可以看这篇文章
		https://blog.csdn.net/qq_41084324/article/details/83787052
		*/
		@Override
	    public boolean matches(Class<?> type) {
	      return type != null && type.isAnnotationPresent(annotation);
	    }
	
	    @Override
	    public String toString() {
	      return "annotated with @" + annotation.getSimpleName();
	    }
	  }
	  	//省略其他代码
}

接着看看ResolverUtil类的其他的方法
find方法:

public class ResolverUtil<T> {

	/** The set of matches being accumulated. */
  	private Set<Class<? extends T>> matches = new HashSet<>();
	
	//省略其他代码
	public ResolverUtil<T> find(Test test, String packageName) {
	    String path = getPackagePath(packageName);
	
	    try {
	      /*
	      找到path包下所有资源,
	      VFS含义是虚拟文件系统;主要是通过程序能够方便读取本地文件系统、FTP文件系统等系统中的文件资源。
	      */
	      List<String> children = VFS.getInstance().list(path);
	      for (String child : children) {
	      	//是否以.class的后缀结束
	        if (child.endsWith(".class")) {
	          addIfMatching(test, child);
	        }
	      }
	    } catch (IOException ioe) {
	      log.error("Could not read package: " + packageName, ioe);
	    }
	
	    return this;
  }

	/**
	* 把Java类的包名转换成路径名
	* @param packageName 要转换成路径的Java包名
	*/
   protected String getPackagePath(String packageName) {
    return packageName == null ? null : packageName.replace('.', '/');
  }
  
  @SuppressWarnings("unchecked")
  protected void addIfMatching(Test test, String fqn) {
    try {
      //fqn是类的路径名,将路径名带有/替换为.
      //例如:com/example/maybatissource/dao/main.class  将/替换为.
      String externalName = fqn.substring(0, fqn.indexOf('.')).replace('/', '.');
      ClassLoader loader = getClassLoader();
      if (log.isDebugEnabled()) {
        log.debug("Checking to see if class " + externalName + " matches criteria [" + test + "]");
      }

      Class<?> type = loader.loadClass(externalName);
      /*检测是否满足,IsA类的matches方法或者AnnotatedWith类的matches方法,
      或者自定义的类实现Test接口的matches方法
      */
      if (test.matches(type)) {
      	//添加到set集合中
        matches.add((Class<T>) type);
      }
    } catch (Throwable t) {
      log.warn("Could not examine class '" + fqn + "'" + " due to a " +
          t.getClass().getName() + " with message: " + t.getMessage());
    }
  }
  	/**
	* 用于查找类的类加载器。
	*/
    private ClassLoader classLoader;

	public Set<Class<? extends T>> getClasses(){
		return matches;
	}
	/*
	如果classLoader 为空就得到当前线程的类加载器,否者就用classLoader 
	*/
	public ClassLoader getClassLoaer(){
		return classLoader == null ? Thread.currentThread().getContextClassLoader() : classLoader;
	}
	
	public void setClassLoader(ClassLoader classloader){
		this.classloader = classloader;
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值