一、你真的懂注解嗎
你是否使用過@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
方法完成屬性的注入!
總結
- 注解只是一段信息
- 注解不是具體的處理邏輯
- 處理邏輯由其他代碼實現