[杂记]自定义注解以及反射的应用

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[杂记]自定义注解以及反射的应用相关的知识,希望对你有一定的参考价值。

序:对于注解的认知是从spring开始的,不管是aop还是ioc,对于其概念是比较清楚的,但真正的实现却没有一个比较好的认知,前段时间看了下《从零开始写web框架》,但当时看的比较仓促,再说因为时间的原因,并没有细揪很多东西,这两天研究了下公司一个系统的代码,突然间对于这块有了比较好的理解,故做潦草记录。

  项目使用自定义注解和反射主要是为了在webSocket请求发过来的时候,通过请求中的参数定位到类和方法,然后去执行具体的业务逻辑,具体整个流程如下。

  1、自定义注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SocketCommand {
/**
* 请求的命令号
* @return
*/
short cmd();
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface SocketModule {

/**
* 请求的模块号
* @return
*/
short module();
}
第一个注解配置在方法上,第二个注解配置到类上。
2、利用BeanPostProcessor类中的postProcessAfterInitialization方法,在实例化类之后开始做注解扫描。
@Component
public class HandlerScanner implements BeanPostProcessor{
private Logger logger = Logger.getLogger(HandlerScanner.class);
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
Class<? extends Object> clazz = bean.getClass();
Class<?>[] interfaces = clazz.getInterfaces();
if(interfaces != null && interfaces.length>0){
for (Class<?> interFace :interfaces){
SocketModule socketModule = interFace.getAnnotation(SocketModule.class);--获取类注解
if (socketModule == null){
continue;
}
Method[] methods = interFace.getMethods();
if(methods != null && methods.length>0){
for (Method method:methods){
SocketCommand socketCommand = method.getAnnotation(SocketCommand.class);--获取自定义方法注解
if (socketCommand == null){
continue;
}
short module = socketModule.module();
short cmd = socketCommand.cmd();
try {
if (InvokerHoler.getInvoker(module,cmd)==null){
InvokerHoler.addInvoker(module,cmd, Invoker.valueOf(method,bean));--将符合条件的加入到map中
}else {
logger.error("重复命令:"+"module:"+module+" "+"cmd: "+cmd);
}
} catch (Exception e) {
logger.error("获取失败: "+e.getMessage());
}
}
}
}
}
return bean;
}
}
附录InvokerHoler:
public class InvokerHoler {

/**
* 命令调用器
*/
private static Map<Short,Map<Short,Invoker>> invokers = new HashMap<Short, Map<Short, Invoker>>();

/**
* 添加命令调用
* @param module
* @param cmd
* @param invoker
*/
public static void addInvoker(short module,short cmd,Invoker invoker){
Map<Short , Invoker> map = invokers.get(module);
if(map == null){
map = new HashMap<Short, Invoker>();
invokers.put(module,map);
}
map.put(cmd,invoker);
}

/**
* 获取命令调用
* @param module
* @param cmd
* @return
* @throws Exception
*/
public static Invoker getInvoker(Short module,Short cmd)throws Exception{
Invoker invoker = null;
Map<Short,Invoker> map = invokers.get(module);
if(map!=null){
invoker = map.get(cmd);
}
return invoker;
}
}
附录Invoker:
public class Invoker {

private Logger logger = Logger.getLogger(Invoker.class);

/**
* 方法
*/
private Method method;

/**
* 目标对象
*/
private Object target;

/**
* 获取实体类
* @param method
* @param target
* @return
*/
public static Invoker valueOf(Method method,Object target){
Invoker invoker = new Invoker();
invoker.setMethod(method);
invoker.setTarget(target);
return invoker;
}

public Object invoke(Object... paramValues){
try {
return method.invoke(target,paramValues);
} catch (IllegalAccessException e) {
logger.error(e.getMessage());
} catch (InvocationTargetException e) {
logger.error(e.getMessage());
}
return null;
}
public void setMethod(Method method) {
this.method = method;
}

public void setTarget(Object target) {
this.target = target;
}

public Method getMethod() {
return method;
}

public Object getTarget() {
return target;
}
}
3、第二步的操作相当于已经把所有自定义注解表标识的类放入到了map中,map的结构为Map<Short,Map<Short,Invoker>>,此时在webscoket连链接中获取传入的参数,并寻找指定的方法。
@Override
protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame frame) throws Exception {
SessionImpl session = new SessionImpl(ctx.channel());
Channel channel = ctx.channel();
String request = frame.text();
logger.debug("收到信息:"+request);
WebSocketRequest webSocketRequest = JsonUtils.readValue(request, WebSocketRequest.class);
checkParameters(webSocketRequest);
Invoker invoker = InvokerHoler.getInvoker(webSocketRequest.getModule(), webSocketRequest.getCmd());--获取执行方法
if (invoker == null){
throw new Exception("没有找到相应的执行器");
}
invoker.invoke(session,webSocketRequest);执行方法

附录MsgHandler:
@SocketModule(module = 1)
public interface MsgHandler {

@SocketCommand(cmd = 1)
void sendMessage(Session session,Object message) throws Exception;
}
链接数据: ‘{"version":"1","module":1,"cmd":1,"data":"‘+message+‘"}‘;
通过Moudlue和cmd定位到1:1方法,寻找其实现类进行执行。

以上是关于[杂记]自定义注解以及反射的应用的主要内容,如果未能解决你的问题,请参考以下文章

自定义注解以及通过反射获取注解

Java自定义注解的定义与使用

自定义注解的实现

Java注解--一张图一案例掌握自定义注解

Java自定义注解

Java反射与自定义注解