Java利用反射如何查找使用指定注解的类详解
前言
最近有些空,想自己写个跟spring里的注解一样的注解来用,然后希望能找到使用了自己写了注解的类,下面来介绍一下实现方法
声明,下面代码是没看过spring源码写的,基本上都是网上找的博客,整理的
定义注解
Controller.java
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public@interfaceController{ }
RequestMapping.java
@Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public@interfaceRequestMapping{ Stringvalue(); }
使用注解
@Controller publicclassIndexController{ @RequestMapping("/") publicvoidindex(){ System.out.println("indexmethod") } @RequestMapping("/about") publicvoidabout(Stringargs){ System.out.println("aboutmethod") } }
扫描包下所有类
下面这段代码摘自网络博客上的
/** *从包package中获取所有的Class * *@parampackageName *@return */ publicstaticList>getClasses(StringpackageName){ //第一个class类的集合 List >classes=newArrayList >(); //是否循环迭代 booleanrecursive=true; //获取包的名字并进行替换 StringpackageDirName=packageName.replace('.','/'); //定义一个枚举的集合并进行循环来处理这个目录下的things Enumeration dirs; try{ dirs=Thread.currentThread().getContextClassLoader().getResources(packageDirName); //循环迭代下去 while(dirs.hasMoreElements()){ //获取下一个元素 URLurl=dirs.nextElement(); //得到协议的名称 Stringprotocol=url.getProtocol(); //如果是以文件的形式保存在服务器上 if("file".equals(protocol)){ //获取包的物理路径 StringfilePath=URLDecoder.decode(url.getFile(),"UTF-8"); //以文件的方式扫描整个包下的文件并添加到集合中 findAndAddClassesInPackageByFile(packageName,filePath,recursive,classes); }elseif("jar".equals(protocol)){ //如果是jar包文件 //定义一个JarFile JarFilejar; try{ //获取jar jar=((JarURLConnection)url.openConnection()).getJarFile(); //从此jar包得到一个枚举类 Enumeration entries=jar.entries(); //同样的进行循环迭代 while(entries.hasMoreElements()){ //获取jar里的一个实体可以是目录和一些jar包里的其他文件如META-INF等文件 JarEntryentry=entries.nextElement(); Stringname=entry.getName(); //如果是以/开头的 if(name.charAt(0)=='/'){ //获取后面的字符串 name=name.substring(1); } //如果前半部分和定义的包名相同 if(name.startsWith(packageDirName)){ intidx=name.lastIndexOf('/'); //如果以"/"结尾是一个包 if(idx!=-1){ //获取包名把"/"替换成"." packageName=name.substring(0,idx).replace('/','.'); } //如果可以迭代下去并且是一个包 if((idx!=-1)||recursive){ //如果是一个.class文件而且不是目录 if(name.endsWith(".class")&&!entry.isDirectory()){ //去掉后面的".class"获取真正的类名 StringclassName=name.substring(packageName.length()+1,name.length()-6); try{ //添加到classes classes.add(Class.forName(packageName+'.'+className)); }catch(ClassNotFoundExceptione){ e.printStackTrace(); } } } } } }catch(IOExceptione){ e.printStackTrace(); } } } }catch(IOExceptione){ e.printStackTrace(); } returnclasses; }
传入一个包名,就会自动扫描下面所有的类
找出用了注解的类
//找也用了Controller注解的类 privateList>controllers; publicList >getControllers(){ if(controllers==null){ controllers=newArrayList<>(); List >clsList=getAllClass(); if(clsList!=null&&clsList.size()>0){ for(Class>cls:clsList){ if(cls.getAnnotation(Controller.class)!=null){ Map ,Object>map=newHashMap<>(); controllers.add(cls); } } } } returncontrollers; }
查找使用RequestMapping注解的方法,并查出注入的参数
for(Class>cls:getControllers()){ Method[]methods=cls.getMethods(); for(Methodmethod:methods){ RequestMappingannotation=method.getAnnotation(RequestMapping.class); if(annotation!=null){ Stringvalue=annotation.value();//找到RequestMapping的注入value值 if(value.equals("/about")){//判断是不是/about,是的话,就调用about(args)方法 method.invoke(cls.newInstance(),"args");//第二个参数是方法里的参数 } } } }
这样一来,java项目里用纯servlet写的项目,就可以做自己的注解映射路由了,方便极了
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对毛票票的支持。