1 通过包名获取下面所有的类名集合
2 通过类名集合反射获得类对象
-->可以选择拿到标记自定义注解的接口
.filter(clazz -> clazz.getAnnotation(TrpcApi.class) != null)
-->也可以不标记拿到全部接口
3 通过类对象拿到所有的接口
/**
* 实现包扫描,通过包名拿到其下面所有的接口
* @param packageName 包名
*/
public RpcBootStart scan(String packageName) {
//1根据包名拿到所有类名
Listclassnames=getClassName(packageName);
//2反射过滤后的接口集合
//.filter(clazz -> clazz.getAnnotation(TrpcApi.class) != null)
//用于只获取自己标记的接口,删除可变为标记全部
List> classes = classnames.stream()
.map(classname -> {
try {
//通过名字反射得到class对象
return Class.forName(classname);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
//过滤所有不含注解的类
}).filter(clazz -> clazz.getAnnotation(TrpcApi.class) != null)
.collect(Collectors.toList());
for (Class> clazz : classes) {
//获取接口集合
Class>[] interfaces = clazz.getInterfaces();
Object instance=null;
try {
instance= clazz.getConstructor().newInstance();
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
e.printStackTrace();
}
}
1 进行数据清洗,得到一个合适的路径,去除中文乱码,得到一个包的基本路径
2 返回一个类名集合
/**
*
* @param packageName 包名
* @return 其下面---类名集合
*/
private List getClassName(String packageName) {
//1 获取绝对路径 转义拿到
String basePath=packageName.replaceAll("\\.","/");
URL url = ClassLoader.getSystemClassLoader().getResource(basePath);
if (url == null){
throw new RuntimeException("包扫描路径发生异常");
}
//转义包名
String absolutePath = url.getPath();
try {
absolutePath = URLDecoder.decode(absolutePath, "utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
ArrayList classNames = new ArrayList<>();
recursionFile(absolutePath,classNames,basePath);
return classNames;
}
1 通过拿到基本路径去递归得到文件
/**
* 递归获取包名下所有类名
* @param absolutePath 转义包名
* @param classNames 所有类名
*/
private ArrayList recursionFile( String absolutePath,ArrayList classNames,String basePath) {
File file = new File(absolutePath);
//判断是否是文件夹
if (file.isDirectory()){
File []childedFile=file.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.isDirectory() || pathname.getPath().contains(".class");
}
});
if (childedFile.length==0 || childedFile==null) return classNames;
for (File child : childedFile) {
if (child.isDirectory()){
//如果是文件价夹递归调用
recursionFile(child.getAbsolutePath(),classNames,basePath);
}else {
//不是文件夹放在集合中
String className= getClassNameByAbsolutePath(child.getAbsolutePath(), basePath);
classNames.add(className);
}
}
}else {
//不是文件夹放在集合中
String className= getClassNameByAbsolutePath(absolutePath, basePath);
classNames.add(className);
}
return classNames;
}
再次进行数据清洗,得到所有.class开头的类的绝对路径加入集合返回
/**
*
* @param absolutePath 当前包名
* @param basePath 绝对包名路径
* @return 类名的绝对路径
*/
private String getClassNameByAbsolutePath(String absolutePath,String basePath) {
//D:\0_项目管理\TRpc\TRpc_Framework\TRpc_Framework_Core\target\classes\com\trpc\channelHandler\ConsumerChannelInitializer.class
//转成com\trpc\channelHandler
String fileName = absolutePath.substring(
absolutePath.indexOf(
basePath.replaceAll("/","\\\\")
)
);
//转成com.trpc.channelHandler
fileName=fileName.replaceAll("\\\\", ".");
fileName=fileName.substring(0,fileName.indexOf(".class"));
return fileName;
}
标记注解:用于添加在接口上,添加是可以在包扫描是获取到该接口
package com.trpc.annotation;
import com.sun.istack.internal.Interned;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 自定义注解
*/
@Target(ElementType.TYPE) //在类上面使用
@Retention(RetentionPolicy.RUNTIME) //允行时生效
public @interface TrpcApi {
}
接口
package com.trpc.api;
import com.trpc.annotation.TryTimes;
public interface HaloApi {
String halo(String name);
}
需要添加在具体实现上
package com.trpc.service.Imp;
import com.trpc.annotation.TrpcApi;
import com.trpc.api.HaloApi;
@TrpcApi
public class HaloServiceImp implements HaloApi {
@Override
public String halo(String name) {
return "halo"+name;
}
}