注解:
大部分都用来设计JAVA框架 , 由于他的写法简单 , 重复利用高的特点。
注解用修饰符:@interface , 表示 , 实现了java.lang.annotation接口。属性
@Target , @Retention。
@Target 用来修饰类型, ElementType.TYPE 是用来修饰类,
ElementType .METHOD , 是用来修饰方法。
@Retention 是运行类型 , RetentionPolicy.RUNTIME 运行当中的状态。
有方法 , 必须要加默认值
以下我们以前端发送来的消息为列:
找到对应的handler , 去处理对应的方法
例子如下:
package com.game.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 类的注解
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MessageAnnotation {
/**
* 开启还是关闭
*/
boolean isGm() default true;
}
package com.game.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 方法的注解
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MethodAnnotation {
boolean isGm() default true;
}
修饰的类:
package com.game.handler;
import com.game.annotation.MessageAnnotation;
import com.game.annotation.MethodAnnotation;
import com.game.mahjonggame.message.BroadcastOwnDrawWinActionMessage;
@MessageAnnotation
public class TestHandler {
@MethodAnnotation
public void testHandler(BroadcastOwnDrawWinActionMessage message){
System.out.println("aaa-bbb");
}
}
怎样通过外部调用,去访问到@MessageAnnotation的方法呢?
/**
* 所有的类初始化一遍 , 把符合情况的保存下来
*/
public RegisterMessage(URL url){
//把符合情况的拉下来
try {
load(url , new ArrayList<Class<?>>());
} catch (Exception e) {
e.printStackTrace();
}
}
private void load(URL url, List<Class<?>> classes) throws Exception {
if ("jar".equals(url.getProtocol())) {
findClassByJar(url.getFile(), classes);
} else {
File root = new File(url.getPath());
String prefix = root.getAbsolutePath();
findClassByCls(root, prefix, classes, PATH);
for(Class<?> class1:classes){
registerMessage(class1);
}
}
}
/**
* 根据路径遍历获得JAR包下的所有.class文件
*
* @param path
* @return
* @throws IOException
* @throws ClassNotFoundException
*/
@SuppressWarnings("resource")
private void findClassByJar(String path, List<Class<?>> list) {
try {
path = URLDecoder.decode(path,"utf-8");
String jarInfo = path.substring(0, path.lastIndexOf(".jar!"));
String jarFilePath = jarInfo.substring(jarInfo.indexOf("/"));
JarFile jarFile = new JarFile(jarFilePath + ".jar");
Enumeration<JarEntry> entrys = jarFile.entries();
while (entrys.hasMoreElements()) {
JarEntry entry = entrys.nextElement();
if (!entry.isDirectory()) {
if (entry.getName().endsWith("Handler.class")) {
String clasPath = entry.getName().substring(0, entry.getName().length() - 6);
list.add(Class.forName(clasPath.replace("/", ".")));
}
}
}
} catch (Exception e) {
throw new RuntimeException("error in findClassByJar", e);
}
}
// 通过 file.listFiles 方法 找到对应的所有文件 , 用递归的方法 , 找到对应的类
private void findClassByCls(File file, String prefix, List<Class<?>> list, String packages) {
try {
if (file.isDirectory()) {
for (File f : file.listFiles())
findClassByCls(f, prefix, list, packages);
} else {
if (file.getName().endsWith("Handler.class")) {
String parent = file.getParent();
String name = file.getName();
String packageName = null;
if (parent.equals(prefix))// 如果是根路径
packageName = "";
else
packageName = parent.substring(prefix.length() + 1) + File.separator;
String className = name.substring(0, name.length() - 6);
String classpath = (packageName + className).replace(File.separator, ".");
list.add(Class.forName(packages + "." + classpath));
}
}
} catch (Exception e) {
throw new RuntimeException("error in findClassByCls", e);
}
}
@SuppressWarnings("unchecked")
private void registerMessage(Class<?> cls) throws Exception {
MessageAnnotation handler = cls.getAnnotation(MessageAnnotation.class);
if( null != handler ) {
Method[] methods = cls.getDeclaredMethods();
for(Method m : methods){
MethodAnnotation action = m.getAnnotation(MethodAnnotation.class);
if (action != null) {
Class[] params = m.getParameterTypes();
if (params.length != 1) {
//多个参数
//throw new IllegalArgumentException("参数只能有一个," + getPositionMsg(cls, m, params[0]));
}
Object msg = params[0].newInstance();
if (!(msg instanceof Message)) {
/*throw new IllegalArgumentException(
"参数必须是Message子类," + getPositionMsg(cls, m, params[0]));*/
}
Message message = (Message) msg;
int messageId = message.getId();
MessageSend msgSwap = messageSwaps.get(messageId);
// 加载已有的HANDLER
Object msgHandler = cls.newInstance();
MethodAccess methodAccess = MethodAccess.get(cls);
msgSwap = new MessageSend(params[0], msgHandler, m, methodAccess);
messageSwaps.put(messageId, msgSwap);
msgSwap.setGm(action.isGm());
}
}
}
}
public MessageSend getMessageSend(int sendId){
return messageSwaps.get(sendId);
}
调用方法:
通过 methodAccess.invoke(handler, method.getName(), msg); 方法调用对应的类
package com.game.annotation;
import java.lang.reflect.Method;
import com.esotericsoftware.reflectasm.MethodAccess;
import com.game.message.Message;
public class MessageSend {
private Class<Message> msgCls;
private Object handler;
private Method method;
private MethodAccess methodAccess;
private boolean isGm;
public MessageSend(Class<Message> msgCls, Object handler, Method method, MethodAccess methodAccess) {
this.msgCls = msgCls;
this.method = method;
this.handler = handler;
this.methodAccess = methodAccess;
}
Class<Message> getMsgCls() {
return msgCls;
}
public Method getMethod() {
return method;
}
public Object getHandler() {
return handler;
}
public boolean isGm() {
return isGm;
}
void setGm(boolean gm) {
isGm = gm;
}
public void action(Message msg) throws Exception {
// method.invoke(handler, msg);//性能太差了
methodAccess.invoke(handler, method.getName(), msg);
}
public String getHandlerClassName() {
return handler.getClass().getName() + ":" + method.getName();
}
main 函数:
public class TestMain {
public static void main(String[] args) {
RegisterMessage message = new RegisterMessage(TestMain.class.getResource("/com"));
try {
message.getMessageSend(254123).action( new BroadcastOwnDrawWinActionMessage());
} catch (Exception e) {
e.printStackTrace();
};
}
希望对你有用。