Skip to content

Commit

Permalink
利用反射机制,自定义注解,实现服务端自动注册
Browse files Browse the repository at this point in the history
  • Loading branch information
fzzfrjf committed Jun 2, 2022
1 parent 1b44d89 commit e33497a
Show file tree
Hide file tree
Showing 12 changed files with 247 additions and 60 deletions.
14 changes: 14 additions & 0 deletions rpc-common/src/main/java/cn/fzzfrjf/annotation/Service.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package cn.fzzfrjf.annotation;


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 Service {

public String name() default "";
}
14 changes: 14 additions & 0 deletions rpc-common/src/main/java/cn/fzzfrjf/annotation/ServiceScan.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package cn.fzzfrjf.annotation;


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 ServiceScan {

public String value() default "";
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ public enum RpcError {
CLIENT_CONNECT_SERVER_FAILURE("客户端连接服务器失败"),
COMPLETABLE_ERROR("异步调用中出现错误"),
CONNECT_REGISTRATION_FAILURE("连接到注册中心失败"),
REGISTERED_SERVICE_FAILURE("将服务注册到注册中心失败");
REGISTERED_SERVICE_FAILURE("将服务注册到注册中心失败"),
SERVICE_SCAN_ANNOTATION_NOT_FOUND("未发现ServiceScan注解"),
RPC_UNKNOWN_ERROR("出现未知错误");

private String message;
}
99 changes: 99 additions & 0 deletions rpc-common/src/main/java/cn/fzzfrjf/utils/ReflectUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package cn.fzzfrjf.utils;

import java.io.File;
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;

public class ReflectUtils {


public static String getClassName(){
StackTraceElement[] stackTrace = new Throwable().getStackTrace();
String className = stackTrace[stackTrace.length - 1].getClassName();
return className;
}


public static Set<Class<?>> getClasses(String packageName){
Set<Class<?>> setClasses = 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");
findClassesInPackageByFile(packageName,filePath,recursive,setClasses);
}else if("jar".equals(protocol)){
JarFile jarFile;
try{
jarFile = ((JarURLConnection)url.openConnection()).getJarFile();
Enumeration<JarEntry> entries = jarFile.entries();
finaClassesInPackageByJar(packageName,entries,packageDirName,recursive,setClasses);
}catch (IOException e){
e.printStackTrace();
}
}
}
}catch (IOException e){
e.printStackTrace();
}
return setClasses;
}

private static void findClassesInPackageByFile(String packageName,String packagePath,final boolean recursive,Set<Class<?>> set){
File dir = new File(packagePath);
if(!dir.exists() || !dir.isDirectory()){
return;
}
File[] dirFiles = dir.listFiles(pathname -> (recursive || pathname.isDirectory()) || (pathname.getName().endsWith(".class")));
for(File file:dirFiles){
if(file.isDirectory()){
findClassesInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), recursive,set);
}else{
String className = file.getName().substring(0,file.getName().length() - 6);
try {
set.add(Thread.currentThread().getContextClassLoader().loadClass(packageName + "." +className));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}

private static void finaClassesInPackageByJar(String packageName, Enumeration<JarEntry> entries,String packageDirName , final boolean recursive,Set<Class<?>> set){
while(entries.hasMoreElements()){
JarEntry jarEntry = entries.nextElement();
String name = jarEntry.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){
if(name.endsWith(".class") && !jarEntry.isDirectory()){
String className = name.substring(packageName.length()+1,name.length() - 6);
try {
set.add(Thread.currentThread().getContextClassLoader().loadClass(packageName + "." + className));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
}
}
}
74 changes: 74 additions & 0 deletions rpc-server/src/main/java/cn/fzzfrjf/core/AbstractServer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package cn.fzzfrjf.core;

import cn.fzzfrjf.annotation.Service;
import cn.fzzfrjf.annotation.ServiceScan;
import cn.fzzfrjf.enumeration.RpcError;
import cn.fzzfrjf.exception.RpcException;
import cn.fzzfrjf.service.RegisterService;
import cn.fzzfrjf.service.ServerPublisher;
import cn.fzzfrjf.utils.ReflectUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetSocketAddress;
import java.util.List;
import java.util.Set;

public abstract class AbstractServer implements CommonServer{
private static final Logger logger = LoggerFactory.getLogger(AbstractServer.class);

protected ServerPublisher serverPublisher;
protected RegisterService registerService;
protected String host;
protected int port;


@Override
public void scanServices(){
String mainClassName = ReflectUtils.getClassName();
Class<?> clazz;
try{
clazz = Class.forName(mainClassName);
if(!clazz.isAnnotationPresent(ServiceScan.class)){
logger.error("启动类缺少 @ServiceScan 注解");
throw new RpcException(RpcError.SERVICE_SCAN_ANNOTATION_NOT_FOUND);
}
} catch (ClassNotFoundException e) {
logger.error("出现未知错误");
throw new RpcException(RpcError.RPC_UNKNOWN_ERROR);
}
String basePackage = clazz.getAnnotation(ServiceScan.class).value();
if("".equals(basePackage)){
basePackage = mainClassName.substring(0,mainClassName.lastIndexOf("."));
}
Set<Class<?>> classes = ReflectUtils.getClasses(basePackage);
for(Class<?> oneClass : classes){
if(oneClass.isAnnotationPresent(Service.class)) {
Object service;
try {
service = oneClass.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
logger.error("创建" + oneClass + "时发生错误");
continue;
}
serverPublisher.addService(service);
Class<?>[] interfaces = service.getClass().getInterfaces();
for (Class<?> anInterface : interfaces) {
registerService.registry(anInterface.getCanonicalName(),new InetSocketAddress(host,port));
}
}
}
}

@Override
public void publishService(List<Object> services) {
for(Object service : services){
serverPublisher.addService(service);
Class<?>[] interfaces = service.getClass().getInterfaces();
for (Class<?> anInterface : interfaces) {
registerService.registry(anInterface.getCanonicalName(),new InetSocketAddress(host,port));
}
}
start();
}
}
2 changes: 2 additions & 0 deletions rpc-server/src/main/java/cn/fzzfrjf/core/CommonServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@ public interface CommonServer {
public void start();

void publishService(List<Object> services);

void scanServices();
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
public class DefaultServerPublisher implements ServerPublisher {

private static final Logger logger = LoggerFactory.getLogger(DefaultServerPublisher.class);
private final ConcurrentHashMap<String,Object> serviceMap = new ConcurrentHashMap<>();
private final Set<String> registeredService = ConcurrentHashMap.newKeySet();
private static final ConcurrentHashMap<String,Object> serviceMap = new ConcurrentHashMap<>();
private static final Set<String> registeredService = ConcurrentHashMap.newKeySet();
@Override
public synchronized <T> void addService(T service) {
String serviceName = service.getClass().getCanonicalName();
Expand Down
28 changes: 3 additions & 25 deletions rpc-server/src/main/java/cn/fzzfrjf/core/NettyServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,7 @@
import cn.fzzfrjf.codec.MyDecoder;
import cn.fzzfrjf.codec.MyEncoder;
import cn.fzzfrjf.serializer.CommonSerializer;
import cn.fzzfrjf.serializer.ProtobufSerializer;
import cn.fzzfrjf.service.RegisterService;
import cn.fzzfrjf.service.ServerPublisher;
import cn.fzzfrjf.utils.NacosUtils;
import cn.fzzfrjf.utils.ShutdownHook;
import cn.fzzfrjf.utils.SingletonFactory;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
Expand All @@ -20,25 +15,20 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetSocketAddress;
import java.util.List;
import java.util.concurrent.TimeUnit;


public class NettyServer implements CommonServer{
public class NettyServer extends AbstractServer {

private static final Logger logger = LoggerFactory.getLogger(NettyServer.class);
private final ServerPublisher serverPublisher;
private final CommonSerializer serializer;
private final RegisterService registerService;
private final String host;
private final int port;
public NettyServer(CommonSerializer serializer,String host,int port){
this.serverPublisher = SingletonFactory.getInstance(DefaultServerPublisher.class);
serverPublisher = new DefaultServerPublisher();
this.serializer = serializer;
registerService = new NacosRegisterService();
this.host = host;
this.port = port;
scanServices();
}
@Override
public void start() {
Expand Down Expand Up @@ -73,16 +63,4 @@ protected void initChannel(SocketChannel ch) throws Exception {
worker.shutdownGracefully();
}
}

@Override
public void publishService(List<Object> services) {
for(Object service : services){
serverPublisher.addService(service);
Class<?>[] interfaces = service.getClass().getInterfaces();
for (Class<?> anInterface : interfaces) {
registerService.registry(anInterface.getCanonicalName(),new InetSocketAddress(host,port));
}
}
start();
}
}
21 changes: 3 additions & 18 deletions rpc-server/src/main/java/cn/fzzfrjf/core/SocketServer.java
Original file line number Diff line number Diff line change
@@ -1,27 +1,21 @@
package cn.fzzfrjf.core;


import cn.fzzfrjf.service.RegisterService;
import cn.fzzfrjf.service.ServerPublisher;

import cn.fzzfrjf.utils.SingletonFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.List;
import java.util.concurrent.*;

public class SocketServer implements CommonServer{
public class SocketServer extends AbstractServer{

private final ExecutorService threadPool;
private static final Logger logger = LoggerFactory.getLogger(SocketServer.class);
private final ServerPublisher serverPublisher;
private final RegisterService registerService;
private final String host;
private final int port;



public SocketServer(String host,int port){
Expand Down Expand Up @@ -51,13 +45,4 @@ public void start(){
logger.error("服务器启动时发生错误:",e);
}
}

@Override
public void publishService(List<Object> services) {
for(Object service:services){
serverPublisher.addService(service);
registerService.registry(service.getClass().getCanonicalName(),new InetSocketAddress(host,port));
}
start();
}
}
14 changes: 14 additions & 0 deletions test-server/src/main/java/cn/fzzfrjf/test/ByeServiceImpl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package cn.fzzfrjf.test;

import cn.fzzfrjf.annotation.Service;
import cn.fzzfrjf.entity.ByeService;
import cn.fzzfrjf.entity.RpcObject;


@Service
public class ByeServiceImpl implements ByeService {
@Override
public String bye(RpcObject object) {
return "(" + object.getMessage() + "),bye!";
}
}
14 changes: 14 additions & 0 deletions test-server/src/main/java/cn/fzzfrjf/test/HelloServiceImpl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package cn.fzzfrjf.test;

import cn.fzzfrjf.annotation.Service;
import cn.fzzfrjf.entity.HelloService;
import cn.fzzfrjf.entity.RpcObject;


@Service
public class HelloServiceImpl implements HelloService {
@Override
public String sayHello(RpcObject object) {
return "这是id为:" + object.getId() + "发送的:" + object.getMessage();
}
}
19 changes: 5 additions & 14 deletions test-server/src/main/java/cn/fzzfrjf/test/NettyServerTest.java
Original file line number Diff line number Diff line change
@@ -1,26 +1,17 @@
package cn.fzzfrjf.test;

import cn.fzzfrjf.core.DefaultServerPublisher;

import cn.fzzfrjf.annotation.ServiceScan;
import cn.fzzfrjf.core.NettyServer;
import cn.fzzfrjf.entity.ByeService;
import cn.fzzfrjf.entity.HelloService;
import cn.fzzfrjf.serializer.ProtobufSerializer;
import cn.fzzfrjf.service.ByeServiceImpl;
import cn.fzzfrjf.service.HelloServiceImpl;
import cn.fzzfrjf.service.ServerPublisher;

import java.util.ArrayList;
import java.util.List;


@ServiceScan
public class NettyServerTest {

public static void main(String[] args) {
HelloService helloService = new HelloServiceImpl();
ByeService byeService = new ByeServiceImpl();
NettyServer server = new NettyServer(new ProtobufSerializer(),"127.0.0.1",9999);
List<Object> services = new ArrayList<>();
services.add(helloService);
services.add(byeService);
server.publishService(services);
server.start();
}
}

0 comments on commit e33497a

Please sign in to comment.