-
Notifications
You must be signed in to change notification settings - Fork 192
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
9c79075
commit dd7d02f
Showing
21 changed files
with
334 additions
and
98 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
10 changes: 10 additions & 0 deletions
10
rpc-api/src/main/java/top/guoziyang/rpc/api/ByeService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package top.guoziyang.rpc.api; | ||
|
||
/** | ||
* @author ziyang | ||
*/ | ||
public interface ByeService { | ||
|
||
String bye(String name); | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
152 changes: 152 additions & 0 deletions
152
rpc-common/src/main/java/top/guoziyang/rpc/util/ReflectUtil.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
package top.guoziyang.rpc.util; | ||
|
||
import java.io.File; | ||
import java.io.FileFilter; | ||
import java.io.IOException; | ||
import java.net.JarURLConnection; | ||
import java.net.URL; | ||
import java.net.URLDecoder; | ||
import java.util.Enumeration; | ||
import java.util.LinkedHashSet; | ||
import java.util.Set; | ||
import java.util.jar.JarEntry; | ||
import java.util.jar.JarFile; | ||
|
||
/** | ||
* @author ziyang | ||
*/ | ||
public class ReflectUtil { | ||
|
||
public static String getStackTrace() { | ||
StackTraceElement[] stack = new Throwable().getStackTrace(); | ||
return stack[stack.length - 1].getClassName(); | ||
} | ||
|
||
public static Set<Class<?>> getClasses(String packageName) { | ||
Set<Class<?>> classes = new LinkedHashSet<>(); | ||
boolean recursive = true; | ||
String packageDirName = packageName.replace('.', '/'); | ||
Enumeration<URL> dirs; | ||
try { | ||
dirs = Thread.currentThread().getContextClassLoader().getResources( | ||
packageDirName); | ||
// 循环迭代下去 | ||
while (dirs.hasMoreElements()) { | ||
// 获取下一个元素 | ||
URL url = dirs.nextElement(); | ||
// 得到协议的名称 | ||
String protocol = url.getProtocol(); | ||
// 如果是以文件的形式保存在服务器上 | ||
if ("file".equals(protocol)) { | ||
// 获取包的物理路径 | ||
String filePath = URLDecoder.decode(url.getFile(), "UTF-8"); | ||
// 以文件的方式扫描整个包下的文件 并添加到集合中 | ||
findAndAddClassesInPackageByFile(packageName, filePath, | ||
recursive, classes); | ||
} else if ("jar".equals(protocol)) { | ||
// 如果是jar包文件 | ||
// 定义一个JarFile | ||
JarFile jar; | ||
try { | ||
// 获取jar | ||
jar = ((JarURLConnection) url.openConnection()) | ||
.getJarFile(); | ||
// 从此jar包 得到一个枚举类 | ||
Enumeration<JarEntry> entries = jar.entries(); | ||
// 同样的进行循环迭代 | ||
while (entries.hasMoreElements()) { | ||
// 获取jar里的一个实体 可以是目录 和一些jar包里的其他文件 如META-INF等文件 | ||
JarEntry entry = entries.nextElement(); | ||
String name = entry.getName(); | ||
// 如果是以/开头的 | ||
if (name.charAt(0) == '/') { | ||
// 获取后面的字符串 | ||
name = name.substring(1); | ||
} | ||
// 如果前半部分和定义的包名相同 | ||
if (name.startsWith(packageDirName)) { | ||
int idx = name.lastIndexOf('/'); | ||
// 如果以"/"结尾 是一个包 | ||
if (idx != -1) { | ||
// 获取包名 把"/"替换成"." | ||
packageName = name.substring(0, idx) | ||
.replace('/', '.'); | ||
} | ||
// 如果可以迭代下去 并且是一个包 | ||
if ((idx != -1) || recursive) { | ||
// 如果是一个.class文件 而且不是目录 | ||
if (name.endsWith(".class") | ||
&& !entry.isDirectory()) { | ||
// 去掉后面的".class" 获取真正的类名 | ||
String className = name.substring( | ||
packageName.length() + 1, name | ||
.length() - 6); | ||
try { | ||
// 添加到classes | ||
classes.add(Class | ||
.forName(packageName + '.' | ||
+ className)); | ||
} catch (ClassNotFoundException e) { | ||
// log | ||
// .error("添加用户自定义视图类错误 找不到此类的.class文件"); | ||
e.printStackTrace(); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} catch (IOException e) { | ||
// log.error("在扫描用户定义视图时从jar包获取文件出错"); | ||
e.printStackTrace(); | ||
} | ||
} | ||
} | ||
} catch (IOException e) { | ||
e.printStackTrace(); | ||
} | ||
|
||
return classes; | ||
} | ||
|
||
private static void findAndAddClassesInPackageByFile(String packageName, | ||
String packagePath, final boolean recursive, Set<Class<?>> classes) { | ||
// 获取此包的目录 建立一个File | ||
File dir = new File(packagePath); | ||
// 如果不存在或者 也不是目录就直接返回 | ||
if (!dir.exists() || !dir.isDirectory()) { | ||
// log.warn("用户定义包名 " + packageName + " 下没有任何文件"); | ||
return; | ||
} | ||
// 如果存在 就获取包下的所有文件 包括目录 | ||
File[] dirfiles = dir.listFiles(new FileFilter() { | ||
// 自定义过滤规则 如果可以循环(包含子目录) 或则是以.class结尾的文件(编译好的java类文件) | ||
public boolean accept(File file) { | ||
return (recursive && file.isDirectory()) | ||
|| (file.getName().endsWith(".class")); | ||
} | ||
}); | ||
// 循环所有文件 | ||
for (File file : dirfiles) { | ||
// 如果是目录 则继续扫描 | ||
if (file.isDirectory()) { | ||
findAndAddClassesInPackageByFile(packageName + "." | ||
+ file.getName(), file.getAbsolutePath(), recursive, | ||
classes); | ||
} else { | ||
// 如果是java类文件 去掉后面的.class 只留下类名 | ||
String className = file.getName().substring(0, | ||
file.getName().length() - 6); | ||
try { | ||
// 添加到集合中去 | ||
//classes.add(Class.forName(packageName + '.' + className)); | ||
//经过回复同学的提醒,这里用forName有一些不好,会触发static方法,没有使用classLoader的load干净 | ||
classes.add(Thread.currentThread().getContextClassLoader().loadClass(packageName + '.' + className)); | ||
} catch (ClassNotFoundException e) { | ||
// log.error("添加用户自定义视图类错误 找不到此类的.class文件"); | ||
e.printStackTrace(); | ||
} | ||
} | ||
} | ||
} | ||
|
||
} |
18 changes: 18 additions & 0 deletions
18
rpc-core/src/main/java/top/guoziyang/rpc/annotation/Service.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package top.guoziyang.rpc.annotation; | ||
|
||
import java.lang.annotation.ElementType; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.RetentionPolicy; | ||
import java.lang.annotation.Target; | ||
|
||
/** | ||
* 表示一个服务提供类,用于远程接口的实现类 | ||
* @author ziyang | ||
*/ | ||
@Target(ElementType.TYPE) | ||
@Retention(RetentionPolicy.RUNTIME) | ||
public @interface Service { | ||
|
||
public String name() default ""; | ||
|
||
} |
18 changes: 18 additions & 0 deletions
18
rpc-core/src/main/java/top/guoziyang/rpc/annotation/ServiceScan.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package top.guoziyang.rpc.annotation; | ||
|
||
import java.lang.annotation.ElementType; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.RetentionPolicy; | ||
import java.lang.annotation.Target; | ||
|
||
/** | ||
* 服务扫描的基包 | ||
* @author ziyang | ||
*/ | ||
@Target(ElementType.TYPE) | ||
@Retention(RetentionPolicy.RUNTIME) | ||
public @interface ServiceScan { | ||
|
||
public String value() default ""; | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
75 changes: 75 additions & 0 deletions
75
rpc-core/src/main/java/top/guoziyang/rpc/transport/AbstractRpcServer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
package top.guoziyang.rpc.transport; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
import top.guoziyang.rpc.annotation.Service; | ||
import top.guoziyang.rpc.annotation.ServiceScan; | ||
import top.guoziyang.rpc.enumeration.RpcError; | ||
import top.guoziyang.rpc.exception.RpcException; | ||
import top.guoziyang.rpc.provider.ServiceProvider; | ||
import top.guoziyang.rpc.registry.ServiceRegistry; | ||
import top.guoziyang.rpc.util.ReflectUtil; | ||
|
||
import java.net.InetSocketAddress; | ||
import java.util.Set; | ||
|
||
/** | ||
* @author ziyang | ||
*/ | ||
public abstract class AbstractRpcServer implements RpcServer { | ||
|
||
protected Logger logger = LoggerFactory.getLogger(this.getClass()); | ||
|
||
protected String host; | ||
protected int port; | ||
|
||
protected ServiceRegistry serviceRegistry; | ||
protected ServiceProvider serviceProvider; | ||
|
||
public void scanServices() { | ||
String mainClassName = ReflectUtil.getStackTrace(); | ||
Class<?> startClass; | ||
try { | ||
startClass = Class.forName(mainClassName); | ||
if(!startClass.isAnnotationPresent(ServiceScan.class)) { | ||
logger.error("启动类缺少 @ServiceScan 注解"); | ||
throw new RpcException(RpcError.SERVICE_SCAN_PACKAGE_NOT_FOUND); | ||
} | ||
} catch (ClassNotFoundException e) { | ||
logger.error("出现未知错误"); | ||
throw new RpcException(RpcError.UNKNOWN_ERROR); | ||
} | ||
String basePackage = startClass.getAnnotation(ServiceScan.class).value(); | ||
if("".equals(basePackage)) { | ||
basePackage = mainClassName.substring(0, mainClassName.lastIndexOf(".")); | ||
} | ||
Set<Class<?>> classSet = ReflectUtil.getClasses(basePackage); | ||
for(Class<?> clazz : classSet) { | ||
if(clazz.isAnnotationPresent(Service.class)) { | ||
String serviceName = clazz.getAnnotation(Service.class).name(); | ||
Object obj; | ||
try { | ||
obj = clazz.newInstance(); | ||
} catch (InstantiationException | IllegalAccessException e) { | ||
logger.error("创建 " + clazz + " 时有错误发生"); | ||
continue; | ||
} | ||
if("".equals(serviceName)) { | ||
Class<?>[] interfaces = clazz.getInterfaces(); | ||
for (Class<?> oneInterface: interfaces){ | ||
publishService(obj, oneInterface.getCanonicalName()); | ||
} | ||
} else { | ||
publishService(obj, serviceName); | ||
} | ||
} | ||
} | ||
} | ||
|
||
@Override | ||
public <T> void publishService(T service, String serviceName) { | ||
serviceProvider.addServiceProvider(service, serviceName); | ||
serviceRegistry.register(serviceName, new InetSocketAddress(host, port)); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.