您的位置:首页 > 编程语言 > Java开发

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

2017-06-08 09:22 786 查看
我们需要开发一个类加载器,来加载该基础包名下的所有类,比如使用了某注解的类,或实现了某接口的类,在或者继承了某父类的所有子类。
       下一个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("%20", "");  
                        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。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐