服务端如何将某些指定的方法暴露出去,比如服务端有:
类A,方法A1()
类B,方法B1(),方法B2()
类C,方法C1()
我们想把类中的方法暴露一部分出来,供客户端调用,如:
类A :暴露,方法A1():暴露
类B:暴露,方法B1():暴露,方法B2():不暴露
类C:不暴露,方法C1()
怎么才能做到动态方便的进行设置?
这种情况下,注解方式则派上了用场。
我们编写2个注解,1个为类注解,表示该类暴露给客户端;另一个为方法注解,表示该方法暴露给客户端。
类级别的注解:
package com.leehao.rpc.anno;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @ClassName RpcClazz
* @Description RpcClazz
* @Author lihao
* @Date 2019/9/25 14:58
* @Version 1.0
**/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE )
public @interface RpcClazz {
}
方法级别的注解:
package com.leehao.rpc.anno;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @ClassName RpcClazz
* @Description RpcClazz
* @Author lihao
* @Date 2019/9/25 14:58
* @Version 1.0
**/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD )
public @interface RpcMethod {
}
具体步骤为:
1、传入包名,得到all业务类,得到文件名
2、通过反射得到类
3、解析类是否有注解
4、解析方法是否有注解 *
5、发布
package com.leehao.rpc.utils;
import com.leehao.rpc.anno.RpcClazz;
import com.leehao.rpc.anno.RpcMethod;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.io.File;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @ClassName AnnoUtil
* @Description AnnoUtil
* @Author lihao
* @Date 2019/9/25 15:02
* @Version 1.0
**/
public class AnnoUtil {
//传入包名packageName
//返回多个类 Map表示
//一个类、多个方法
//一个方法,多个参数
//所以最后返回结果为:Map<String, List<Map<String,List<String>>>>
public static Map<String, List<Map<String,List<String>>>> parseAnno(String packageName) throws Exception {
Map<String, List<Map<String,List<String>>>> map = new HashMap<>();
//获取项目跟路径
String basePath = AnnoUtil.class.getResource("/").getPath();
//获取当前包所在的路径,将.替换为/
File file = new File(basePath + packageName.replace(".", "/"));
//获取包路径下所有的文件(严格讲,需要获取.class后缀的文件)
String[] names = file.list();
for (String name : names) {
//去掉后缀,拿到类名
name = name.replaceAll(".class", "");
//通过反射获取该类
Class<?> clazz = Class.forName(packageName + "." + name);
//是否有类级别的注解
if (clazz.isAnnotationPresent(RpcClazz.class)) {
List<Map<String,List<String>>> methodsReturn = new ArrayList<>();
//通过反射获取所有方法,包括私有方法
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
//判断方法是否有注解
if (method.isAnnotationPresent(RpcMethod.class)){
Map<String,List<String>> methodReturn = new HashMap<>();
List<String> paras = new ArrayList<>();
//遍历方法类型
Class<?>[] paraTypes = method.getParameterTypes();
for (Class<?> paraType:paraTypes){
//将变量类型加入list中
paras.add(paraType.getSimpleName());
}
//将该方法中所有的参数类型加入map中,其中key为方法名
methodReturn.put(method.getName(),paras);
//将方法都加入到list中去
methodsReturn.add(methodReturn);
}
}
//将该类下的所有暴露方法都加入到map中,其中key为包全名
map.put(packageName+"."+ name,methodsReturn);
}
}
//返回最终结果
return map;
}
}
编写几个类和方法,加入我们的注解来测试:
package com.leehao.rpc.server.dao;
import com.leehao.rpc.anno.RpcClazz;
import com.leehao.rpc.anno.RpcMethod;
/**
* @ClassName OrderDao
* @Description OrderDao
* @Author lihao
* @Date 2019/9/24 18:58
* @Version 1.0
**/
@RpcClazz
public class OrderDao {
@RpcMethod
public void query(String name){
System.out.println("name="+name);
}
@RpcMethod
public void query1(String name1,String name2){
System.out.println("name="+name1+name2);
}
@RpcMethod
public void query2(int name){
System.out.println("name="+name);
}
public void query3(int name){
System.out.println("name="+name);
}
}
package com.leehao.rpc.server.dao;
import com.leehao.rpc.anno.RpcClazz;
import com.leehao.rpc.anno.RpcMethod;
/**
* @ClassName UserDao
* @Description UserDao
* @Author lihao
* @Date 2019/9/24 18:58
* @Version 1.0
**/
@RpcClazz
public class UserDao {
@RpcMethod
public void sayHello(String name){
System.out.println("name="+name);
}
@RpcMethod
public void sayBye(String name1,String name2){
System.out.println("name="+name1+name2);
}
}
package com.leehao.rpc.server.dao;
import com.leehao.rpc.anno.RpcClazz;
import com.leehao.rpc.anno.RpcMethod;
/**
* @ClassName UserDao
* @Description UserDao
* @Author lihao
* @Date 2019/9/24 18:58
* @Version 1.0
**/
public class OrgDao {
@RpcMethod
public void test(){
System.out.println("name");
}
}
预期:
OrderDao类有注解,query、query1、query2方法有注解:
所以query、query1、query2暴露,query3不暴露出来
UserDao类有注解,sayHello、sayBye有注解,
所以2个均暴露出来
OrgDao类没有注解,所以下面的方法无论是否加注解,均无法暴露。
在这里我们采用SpringBoot作为web容器,调用上述的接口,来将结果显示到页面上,如对springboot了解不够,可自行学习,默认大家都了解Maven、springboot等相关知识。
pom中引入依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
编写Controller
package com.leehao.rpc.controller;
import com.leehao.rpc.utils.AnnoUtil;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
import java.util.Map;
/**
* @ClassName RegistryController
* @Description RegistryController
* @Author lihao
* @Date 2019/9/25 15:36
* @Version 1.0
**/
@Controller
@RequestMapping("/")
public class RegistryController {
@ResponseBody
@GetMapping("/getInstance")
public Map<String, List<Map<String, List<String>>>> getInstance(@RequestParam("packageName") String packageName) throws Exception {
return AnnoUtil.parseAnno(packageName);
}
}
启动类启动:
package com.leehao.rpc;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class RpcServerApplication {
public static void main(String[] args) {
SpringApplication.run(RpcServerApplication.class, args);
}
}
在浏览器地址栏输入(端口号根据实际情况而定):http://localhost:8765/getInstance?packageName=com.leehao.rpc.server.dao
即可发现已暴露的所有接口方法:
和我们的预期是一致的,至此服务注册和发现已完成。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有