《注解的江湖:一场元数据的“宫斗剧”》
一、你真的懂注解吗
你是否使用过@Autowired
却不知道是如何生效的?
这几个注解你一定很熟悉:
@Override
@Deprecated
@Transactional
那么你有进一步思考过怎么生效的吗?注解到底是什么?注解,到底是信息?还是指令?是标签?还是注释?
二、注解是一封写给反射器的“情书”
- 注解 = 元数据
举个例子,你在缅甸被嘎腰子了,这时你想了一个办法,偷偷张贴一张小纸条,上面写着“救我”
。那么,路过的人看到这个纸条就会想着替你做点什么。
再来讲讲注解的生命周期:
source
写完就撕掉(例如override
)只作用在源码时期。class
打包了但是JVM不看,作用在class期间(小纸条被翻译成class,但是JVM不看)。runtime
这个小纸条可以在程序运行时期被读取。
三、实战一:自定义一个注解,实现“自动字段注入”
“太监宣旨”→ 注解写在类上,反射器执行“圣旨”。
- 创建一个圣旨
import java.lang.annotation.*;@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface ShannonAnnotation {int age() default 1 ;String name() default "";
}
- 宣读圣旨(放在类上)
@ShannonAnnotation(name = "shannon",age = 18)public static class People{int age;String name;public void sayHello(){System.out.println("hello i am shannon");}}
- 执行圣旨(反射器调用)
public static void main(String[] args) {Class<People> peopleClass = People.class;Annotation[] annotations = peopleClass.getAnnotations();// 遍历类上所有的注解,找到我们的圣旨!for (Annotation annotation : annotations) {if (annotation instanceof ShannonAnnotation){ShannonAnnotation annotation1 = (ShannonAnnotation) annotation;System.out.println("age:"+annotation1.age());System.out.println("name:"+annotation1.name());}}
// invoketry {peopleClass.getMethod("sayHello").invoke(new People());} catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {throw new RuntimeException(e);}}
- 结果:
四、实战二:解析 Spring 是如何将“尊贵妃”变“宠妃”
- 搭建Spring Debug环境
– 搭建方法见编译Spring - 创建一个项目如下:
@Service
public class HelloService {public void sayHi(){System.out.println("hello world");}
}
@Service
public class MyService {@Autowiredpublic HelloService helloService;
}
由上可知,在MyService中使用@Autowired
注解,将HelloService注入。
- 进入方法打断点
这里解释一下方法的作用,scan
方法主要是扫描basePackage的所有bean,注册到BeanDefinitions
当中,refresh
是真正启动整个容器。
在这个方法打断点org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean
,这个方法是注入bean属性的方法。
可以看到,上图,有一个AutoWiredAnnontationBeanPostProcessor
类,这个就是@AutoWired
的处理方法,点进去看看!
可以看到上图中,metadata
中包含一个injectedElements
包含了HelloService
。spring 调用metadata
的inject
方法完成属性的注入!
总结
- 注解只是一段信息
- 注解不是具体的处理逻辑
- 处理逻辑由其他代码实现