前言:
我写了很多上层框架的知识,自以为会有很多人会很感兴趣,但发现其实看的人
很少。于是我自己反思了一下为什么会这样,因为框架这种东西真的比较好学,
随便买本书,或者看个什么什么视频,就比我写的博文好太多了,我思前想后很
久,还是打算从那些容易忽略的细小知识出发,重新创建个javase模块,写点有
质量的东西出来。
相信很多买过java基础书籍的同学都知道—java对注解这一块的描述普遍少的可怜,网上也找不到什么好的视频,于是我打算从jdk自带的注解来模仿别人是怎么写的。我会在讲述过程中加上自己的学习时的心得。好了,话不多说了,直奔主题吧。
直接上图说明问题:下图是jdk内置注解 @SuppressWarnings 的源码 , 我们可以很清晰的发现,自定义的注解需要如下的三个东西(元注解、@interface、方法形式的属性)
我来说明一下上面的三个关键因素!
先从@interface说起吧。看下图我们能很直观的看出Annotation(注解) 是和Class(类)、Interface(接口)平级的东西,而写上@interface 就可以表明你写的这个文件是个注解类。
元注解:修饰注解的注解,有下面四个:
注解 | 功能 |
---|---|
@Target | 限制注解,限制注解使用的地方(属性、方法、类);如果一个注解没有@Target描述,则该 注解可以修饰任何类型的元素;如果有@Target修饰,则该注解就只能用于被@Target修饰的地方,属性的填写参考 ElementType 枚举类 |
@Retention | 限制注解的生命周期,属性的填写参考 RetentionPolicy 枚举类(里面只有三个,SOURCE:该注解无效、CLASS:程序在编译时会使用该注解,在运行是不会使用、RUNTIME:程序在编译以及运行时,都会使用注解) |
@Document | 默认情况下,javadoc 不包含注解的解释;如果现在javadoc文档中也包含对注解的说明,则需要使用@Document标注 |
@Inherited | 默认情况下子类不会继承父类的注解。除非父类的注解里面写有该元注解,则子类也会享有父类的注解(里面写有该元注解) |
方法形式的属性:想要给注解定义一些属性,则必须将需要定义的属性写成抽象方法的形式。
下面我将展示一下通过自定义注解,来完成加法运算
- 1.编写注解类:
package annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(value = {ElementType.FIELD,ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface luzelong {
int x() default 0;//给x属性的默认值设为0
int y() default 0;//给y属性的默认值设为0
}
- 2.通过反射来获取注解的属性并完成加法操作:
package annotation;
import java.lang.annotation.Annotation;
import static java.lang.Class.forName;
public class Test {
@luzelong(x = 12, y = 25)
public static int longlong() {
luzelong lzl = null;
try {
lzl = forName("annotation.Test").getMethod("longlong").getAnnotation(luzelong.class);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
if(lzl != null)
return lzl.x() + lzl.y();
else
return -1;
}
public static void main(String[] args) {
System.out.println(longlong());
}
}
运行结果如下:
配合注解的常用反射方法
第三个方法存在部分标有注解的方法未能执行的问题,大佬能解决的话评论区留言!
/**
* 获取某个包中的所有类
* @param packageName
* @return
* @throws IOException
* @throws ClassNotFoundException
*/
private List<Class> getAllClazz(String packageName) throws IOException, ClassNotFoundException {
List<Class> ret = new ArrayList<>();
PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver = new PathMatchingResourcePatternResolver();
CachingMetadataReaderFactory cachingMetadataReaderFactory = new CachingMetadataReaderFactory();
Resource[] resources = (Resource[]) pathMatchingResourcePatternResolver.getResources("classpath*:"+packageName+"/**/*.class");
ClassLoader loader = ClassLoader.getSystemClassLoader();
for (Resource resource : resources) {
MetadataReader reader = cachingMetadataReaderFactory.getMetadataReader((org.springframework.core.io.Resource) resource);
String className = reader.getClassMetadata().getClassName();
Class aClass = loader.loadClass(className);
ret.add(aClass);
}
return ret;
}
/**
* 获取某个包中的所有 k-v = class-method
* @return
* @throws IOException
* @throws ClassNotFoundException
*/
public HashMap<Class,Method> getAllFMethod(String packageName) throws IOException, ClassNotFoundException {
HashMap<Class,Method> mothods = new HashMap<>();
List<Class> allClazz = getAllClazz(packageName);
for (Class clazz : allClazz) {
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
mothods.put(clazz,declaredMethod);
}
}
return mothods;
}
/**
* 执行某个包中 带有annotation注解的全部方法(该方法存在问题,大佬能解决的话评论区留言)
* @param packageName
* @param annotation
* @throws IOException
* @throws ClassNotFoundException
* @throws InstantiationException
* @throws IllegalAccessException
* @throws InvocationTargetException
*/
public void exeMethod_Obtain_Some_Annotation(String packageName,Class annotation) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException {
HashMap<Class, Method> allFMethods = getAllFMethod(packageName);
for (Map.Entry<Class,Method> funcMethod : allFMethods.entrySet()){
funcMethod.getValue().setAccessible(true);
if (funcMethod.getValue().isAnnotationPresent(annotation)){
System.out.println(funcMethod);
funcMethod.getValue().invoke(funcMethod.getKey().newInstance());
}
}
}