java spring注解_spring注解是如何实现的?
注解呢,是java本身自帶的一個東西,它基于java的接口進行實現(xiàn),是一種特殊的接口類型,通常對于注解來說,三種情況,一個是在編譯前就會被丟棄的,一個是編譯后留在class中的,另一種是會一直存在,運行的時候注解也會被保留,而框架的注解一般都是第三種。
Class對象,Method對象,Parameter對象,Constructor對象等java反射對象通常都具有g(shù)etAnnotation方法可以直接獲取保留到運行時的注解實例,就像這樣:
@Component
class AnnoTest {
}
這樣的一個類,有一個component注解,我們可以通過這樣:
Component comp = AnnoTest.class.getAnnotation(Component.class);
Annotation[] annotations = AnnoTest.class.getAnnotations();
// 其實還有兩個注解的get方法,你可以自己去看,這里不多說。
就直接得到了class上面的注解。
注解和普通接口不一樣,他聲明的語法比較特別,public @interface 注解名這個樣子。為了標識注解的使用范圍,你需要使用一些java提供的幾個其他注解,這些用來描述注解的注解被稱為元注解。
@Retention,保留范圍(在源碼中存在,還是在字節(jié)碼里面,還是一直留到運行環(huán)境),一般是Runtime,
@Target 注解的作用對象,類型還是字段還是方法,這個注解是寫在什么地方的。
@Inherited 是否可以繼承此注解,這個注解僅僅在針對類的注解中起效,如果一個類繼承了使用了含有他的注解的父類,那么這個類也會擁有父類的那個注解。
@Documented 注解再生成JavaDoc的時候是否會被寫入Javadoc。
總之,這樣就是有一個注解了,比如這樣:
@Retention(RUNTIME)
@Target(ElementType.TYPE)
public @interface Component {
/*** 組件名稱* @return*/
String name() default "";
/*** 組件創(chuàng)建類型* @return*/
Scope scope() default Scope.SINGLE;
}
這里要特別的說下注解接口的方法:這些方法由返回值,方法名稱構(gòu)成,具體的值是你寫注解的時候填進去的,例如上述注解的name,實際上是你在使用注解的時候放在@component(name="xxxx")這里面的那個name,這些方法可以使用default指定一個默認返回值,即,你在使用注解的時候沒有填寫這個東西,會返回的內(nèi)容。
接下來,你要用反射的手法拿到這些帶有注解的class,method,field之類的,然后get到他們的注解,然后對注解進行處理,無論是aop還是注入,按照你的需要自己實現(xiàn)。
這里有一個例子,這個是仿照spring進行properties文件進行值注入的方法,他通過讀取class的configProperties注解得到properties文件的位置,然后注入到bean的字段中。
public Object prcess(Object target, Definition definition, IFactory factory) {
Class> clazz = definition.getClazz();
ConfigProperties config = clazz.getAnnotation(ConfigProperties.class);
if (config == null) {
return target;
}
String location = config.value();
if (!location.startsWith(File.separator)) {
location = File.separator + location;
}
URL url = clazz.getResource(location);
Properties props = new Properties();
try {
props.load(url.openStream());
// 這個只是對properties的封裝,就當他是普通properties好了PropertiesConfig propsConfig = new PropertiesConfig();
propsConfig.setProperties(props);
Set keys = props.stringPropertyNames();
for (String propName : keys) {
String fieldName = propName.replace(config.prefix() + ".", "");
try {
//按照properties的key,去掉前綴后讀取類的字段FieldField field = clazz.getDeclaredField(fieldName);
// 開啟操作權(quán)限field.setAccessible(true);
// 字段不是string型就需要轉(zhuǎn)換一下if (field.getType() != String.class) {
// 獲取類型轉(zhuǎn)換器ICovertor covertor = Covertors
.getCovertor(String.class, field.getType());
if (covertor != null) {
// 轉(zhuǎn)換類型并且注入field.set(target, covertor
.covert(propsConfig.get(propName)));
} else {
// 反向獲取類型轉(zhuǎn)換器(這里的轉(zhuǎn)換器接口//是雙向的,其實這樣區(qū)分方向轉(zhuǎn)換不是很好,//但是我現(xiàn)在沒有來得及改他。covertor = Covertors
.getCovertorRev(field.getType(),
String.class);
// 轉(zhuǎn)換并注入, 其實這里應(yīng)該判空,// 但是當時應(yīng)該是我忘記了field.set(target, covertor.
covertRev(propsConfig.get(propName)));
}
} else {
// 類型一致,直接注入field.set(target, propsConfig.get(propName));
}
} catch (Exception e) {
// 注入失敗也無所謂,無視這個字段下一個注入}
}
} catch (IOException e) {
throw new RuntimeException(e);
}
return target;
}
注解接口:
@Retention(RUNTIME)
@Target(TYPE)
@Component
public @interface ConfigProperties {
String value();
String prefix();
}
附一個近期手寫的ioc容器,仿springboot,用注解驅(qū)動的那種,雖然水平比較菜,但是注解還是用了不少的,哦,對了,這個代碼需要Java11才行。仿制IOC的GitHub?github.com
總結(jié)
以上是生活随笔為你收集整理的java spring注解_spring注解是如何实现的?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CAD批量提取数值lisp插件_CAD批
- 下一篇: 大学Mooc电脑版中的视频资源下载