盘点Java框架常用的3大底层技术!

盘点Java框架常用的3大底层技术!

这段时间很久没有更新自己的博客了,对自己的不严谨和不自律批评下自己,以后更加严格要求自己。

这篇博客像往常一样主要复习底层知识点,本文所介绍的三个Java底层技术,有着逐渐递进的特点,Java注解中使用了JDK动态代理,而JDK动态代理中运用了Java反射。

同样的是通过架构师这个微信公众号来学习的。

Java注解

当我们阅读框架源码时,会看到其中包含着大量的注解,注解被广泛使用的原因在于,可以生成一些通用的“模板化”代码,来避免重复性的工作。使用注解的工作模式是,通过注解来描述我们的意图,然后用注解解析工具对注解进行解析。

实验:自定义注解

首先我们通过@interface关键字定义一个注解@Tree,定义注解时,需要定义两个内容:元注解,注解属性。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Tree {

    String name() default "tree";
}

元注解:

可以看到我在上面还添加了@Target@Retention,这个是元注解,也就是添加到注解之上的注解,元注解有5种:

@Retention:声明注解的的存活时间

RetentionPolicy.SOURCE 注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视。

RetentionPolicy.CLASS 注解只被保留到编译进行的时候,它并不会被加载到 JVM 中。

RetentionPolicy.RUNTIME 注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们。

@Target:声明注解运用的地方

ElementType.ANNOTATION_TYPE 应用到注解

ElementType.CONSTRUCTOR 应用到构造方法

ElementType.FIELD 应用到属性

ElementType.LOCAL_VARIABLE 应用到局部变量

ElementType.METHOD 应用到方法

ElementType.PACKAGE 应用到包

ElementType.PARAMETER 应用到方法内的参数

ElementType.TYPE 应用到类型(类、接口、枚举)

@Documented:将注解中的元素包含到 Javadoc 中
@Inherited:使用了这个注解的子类,就继承了该注解
@Repeatable:Java1.8新增特性,应用于注解的值可以取多个的场景

注解属性:

可以类比为普通类中的成员变量,注解中只有成员变量没有方法,在使用该注解时为该属性赋值,也可以在定义时赋默认值。

【注解处理器】

在注解处理器中,我们可以为注解定义逻辑,例如在下面的例子中,就是调用AnnotationClient类中所有方法,把@Tree中name属性值注入到方法中。

public class TreeProcessor {
    public void parseMethod(final Class<?> clazz) throws Exception {
        final Object obj = clazz.getConstructor(new Class[] {}).newInstance(new Object[] {});
        final Method[] methods = clazz.getDeclaredMethods();
        for (final Method method : methods) {
            final Tree my = method.getAnnotation(Tree.class);
            if (null != my) {
                method.invoke(obj, my.name());
            }
        }
    }
}

接下来做一下测试:

public class AnnotationClient {

    @Tree
    public static void sayHello(final String name) {
        System.out.println("==>> Hi, " + name + " [sayHello]");
    }

    @Tree(name = "Someone")
    public static void sayHelloToSomeone(final String name) {
        System.out.println("==>> Hi, " + name + " [sayHelloToSomeone]");
    }

    public static void main(final String[] args) throws Exception {
        final TreeProcessor treeProcessor = new TreeProcessor();
        treeProcessor.parseMethod(AnnotationClient.class);
    }

}

实现:

==>> Hi, Someone [syaHelloToSomeone]
==>> Hi, tree [sayHello]
深入理解注解

如果换一个角度理解注解:它的本质是一个继承了Annotation接口的接口

当我们通过getAnnotation()方法获取一个注解的时候,JDK会通过动态代理生成注解的代理类$Proxy1,这个代理类代理了Tree中的所有方法,其实本质上还是通过反射来实现的,但是我们逐步递进的分析,先研究注解,下一步研究JDK动态代理,最后才能到达反射。

JAVA 中专门用于处理注解的 Handler:

sun.reflect.annotation.AnnotationInvocationHandler

AnnotationInvocationHandler有如下几个属性:

private final Class<? extends Annotation> type;
private final Map<String, Object> memberValues;
private transient volatile Method[] memberMethods = null;

其中memberValues在初始化后,key是注解的属性值,value是我们为属性的赋值,可能你已经忘了我们在程序中是怎么做的了 : @Tree(name = "Someone")

在这里插入图片描述

所有动态代理类生成的方法,都会走这个invoke()方法。

而这个invoke方法做的事情,概括起来就是:通过方法名获取属性值。

public Object invoke(Object var1, Method var2, Object[] var3) {
        String var4 = var2.getName();
   
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值