从零开始写javaweb框架笔记13-搭建轻量级JAVAWEB框架-开发一个类加载器

xiaoxiao2021-02-28  88

我们需要开发一个类加载器,来加载该基础包名下的所有类,比如使用了某注解的类,或实现了某接口的类,在或者继承了某父类的所有子类。

       下一个ClassUtil工具类作为类加载器,提供与类相关的方法,比如获取类加载器,加载类,获取指定包下的所有类。ClassUtil的代码如下:

[java] view plain copy print ? package org.smart4j.framework.org.smart4j.framework.util;    import org.apache.commons.lang3.StringUtils;  import org.slf4j.Logger;  import org.slf4j.LoggerFactory;    import java.io.File;  import java.io.FileFilter;  import java.net.JarURLConnection;  import java.net.URL;  import java.util.Enumeration;  import java.util.HashSet;  import java.util.Set;  import java.util.jar.JarEntry;  import java.util.jar.JarFile;    /**  * Created by jack on 2017/5/22.  * 类操作工具类  */  public final class ClassUtil {      private static final Logger LOGGER = LoggerFactory.getLogger(ClassUtil.class);        /**      * 获取类加载器      * 获取加载器类的实现比较简单,只需获取当前线程的ClassLoader      */      public static ClassLoader getClassLoader() {          return Thread.currentThread().getContextClassLoader();      }        /**      * 加载类      * 加载类需要提供类名与是否初始化的标志,这里提到的初始化指是否执行类的静态代码块;      * 为了提高加载类的性能,可以将loadClass方法的isInitialized参数设置false      */      public static Class<?> loadClass(String className, boolean isInitialized) {          Class<?> cls = null;          try {              //进行类加载              cls = Class.forName(className, isInitialized, getClassLoader());          } catch (ClassNotFoundException e) {              LOGGER.error("load class failure.", e);              throw new RuntimeException(e);          }          return cls;      }        /**      * 获取指定包名下所有的类;      * 获取指定包名下所有的类,需要根据包名并将其转换为文件路径,读取class文件或jar包,获取指定的类名去加载类      */      public static Set<Class<?>> getClassSet(String packageName) {          Set<Class<?>> classSet = new HashSet<Class<?>>();          try {              Enumeration<URL> urls = getClassLoader().getResources(packageName.replace(".""/"));              while (urls.hasMoreElements()) {                  URL url = urls.nextElement();                  if (url != null) {                      String protocol = url.getProtocol();                      if ("file".equals(protocol)) {                          String packagePath = url.getPath().replace(" """);                          addClass(classSet, packagePath, packageName);                      } else if ("jar".equals(protocol)) {                          JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();                          if (jarURLConnection != null) {                              JarFile jarFile = jarURLConnection.getJarFile();                              if (jarFile != null) {                                  Enumeration<JarEntry> jarEntries = jarFile.entries();                                  while (jarEntries.hasMoreElements()) {                                      JarEntry jarEntry = jarEntries.nextElement();                                      String jarEntryName = jarEntry.getName();                                      if (jarEntryName.endsWith(".class")) {                                          String className = jarEntryName.substring(0, jarEntryName.lastIndexOf("."))                                                  .replaceAll("/"".");                                          doAddClass(classSet, className);                                      }                                  }                              }                          }                      }                  }              }          } catch (Exception e) {              LOGGER.error("get class set failure.", e);              throw new RuntimeException(e);          }          return classSet;      }        private static void addClass(Set<Class<?>> classSet, String packagePath, String packageName) {          File[] files = new File(packagePath).listFiles(new FileFilter() {              public boolean accept(File file) {                  return (file.isFile() && file.getName().endsWith(".class")) || file.isDirectory();              }          });          for (File file : files) {              String fileName = file.getName();              if (file.isFile()) {                  String className = fileName.substring(0, fileName.lastIndexOf("."));                  if (StringUtils.isNotEmpty(packageName)) {                      className = packageName + "." + className;                  }                  doAddClass(classSet, className);              } else {                  String subPackagePath = fileName;                  if (StringUtils.isNotEmpty(packageName)){                      subPackagePath = packagePath +"/"+subPackagePath;                  }                  String subPackageName = fileName;                  if (StringUtils.isNotEmpty(packageName)){                      subPackageName = packageName +"."+subPackageName;                  }                  addClass(classSet,subPackagePath,subPackageName);              }          }      }        private static void doAddClass(Set<Class<?>> classSet, String className) {          Class<?> cls = loadClass(className, false);          classSet.add(cls);      }  }  

       我们的目标是在控制器类上使用Controller注解,在控制器类的方法上使用Action注解,在服务类上使用Service注解,在控制器类中可以使用Inject注解将服务依赖注入进来。因此我们需要自定义4个注解类。

       控制器类注解代码如下:

[java] view plain copy print ? package org.smart4j.framework.annotation;    import java.lang.annotation.ElementType;  import java.lang.annotation.Retention;  import java.lang.annotation.RetentionPolicy;  import java.lang.annotation.Target;    /**  * Created by jack on 2017/5/22.  * 控制器注解  */  @Target(ElementType.TYPE)  @Retention(RetentionPolicy.RUNTIME)  public @interface Controller {  }         Action方法注解代码如下:

[java] view plain copy print ? package org.smart4j.framework.annotation;    import java.lang.annotation.ElementType;  import java.lang.annotation.Retention;  import java.lang.annotation.RetentionPolicy;  import java.lang.annotation.Target;    /**  * Created by jack on 2017/5/22.  * Action 方法注解  */  @Target(ElementType.METHOD)  @Retention(RetentionPolicy.RUNTIME)  public @interface Action {      /**      * 请求路径      */      String value();  }  

     服务类注解代码如下:

[java] view plain copy print ? package org.smart4j.framework.annotation;    import java.lang.annotation.ElementType;  import java.lang.annotation.Retention;  import java.lang.annotation.RetentionPolicy;  import java.lang.annotation.Target;    /**  * Created by jack on 2017/5/22.  * 服务类注解  */  @Target(ElementType.TYPE)  @Retention(RetentionPolicy.RUNTIME)  public @interface Service {  }  

      依赖注解代码如下:

[java] view plain copy print ? package org.smart4j.framework.annotation;    import java.lang.annotation.ElementType;  import java.lang.annotation.Retention;  import java.lang.annotation.RetentionPolicy;  import java.lang.annotation.Target;    /**  * Created by jack on 2017/5/22.  * 依赖注解类  */  @Target(ElementType.FIELD)  @Retention(RetentionPolicy.RUNTIME)  public @interface Inject {  }  

    由于我们在smart.properties配置文件中指定了

smart.framework.app.base_package

   他是整个应用的基础包名,所以我们有必要提供一个ClassHelper助手类,让它分别获取应用包名下的所有的类,应用包名下所有的Service类,应用包名下所有的Controller类。此外可以将带有Controller注解和Service注解的类所产生的对象理解为smart框架所管理的bean,所以有必要在ClassHelper类中增加一个获取应用包名下所有bean类的方法,ClassHelper类的代码如下:

     

[java] view plain copy print ? package org.smart4j.framework.helper;    import org.smart4j.framework.annotation.Controller;  import org.smart4j.framework.annotation.Service;  import org.smart4j.framework.org.smart4j.framework.util.ClassUtil;    import java.util.HashSet;  import java.util.Set;    /**  * Created by jack on 2017/5/22.  * 类操作助手类  */  public class ClassHelper {      /**      * 定义类集合,用于存放所加载的类      */      private static final Set<Class<?>> CLASS_SET;        static {          String basePackage = ConfigHelper.getAppBasePackage();          CLASS_SET = ClassUtil.getClassSet(basePackage);      }        /**      * 获取应用包下的所有类      */      public static Set<Class<?>> getClassSet() {          return CLASS_SET;      }        /**      * 获取应用包名下所有Service类      */      public static Set<Class<?>> getServiceClassSet() {          Set<Class<?>> classSet = new HashSet<Class<?>>();          for (Class<?> cls : CLASS_SET) {              if (cls.isAnnotationPresent(Service.class)) {                  classSet.add(cls);              }          }          return classSet;      }        /**      * 获取应用包名下所有Controller类      */      public static Set<Class<?>> getControllerClassSet() {          Set<Class<?>> classSet = new HashSet<Class<?>>();          for (Class<?> cls : CLASS_SET) {              if (cls.isAnnotationPresent(Controller.class)) {                  classSet.add(cls);              }          }          return classSet;      }      /**      * 获取应用包名下所有Bean类(包括Service,Controller)      */      public static Set<Class<?>> getBeanClassSet() {         Set<Class<?>> beanClassSet = new HashSet<Class<?>>();         beanClassSet.addAll(getServiceClassSet());         beanClassSet.addAll(getControllerClassSet());          return beanClassSet;      }  }  

     像上面这样,我们使用ClassHelper封装了ClassUtil,并提供了一系列的助手方法,通过这些方法我们可以直接获取我们想要的类集合,在后面的我们会经常使用到ClassHelper。

转载请注明原文地址: https://www.6miu.com/read-67982.html

最新回复(0)