模拟springIOC容器的annotation
spring 有兩大核心 IOC和AOP。 ?IOC (inversion of control) 譯為 控制反轉(zhuǎn),也可以稱為 依賴注入 ; AOP(Aspect Oriented Programming)即面向切面編程。
我們此次所模仿的是?spring IOC?中的 Annotation 版的自動裝配;Spring 在2.5版本后 引入了?@Autowired?以及一系列的 Annotation,它可以對類成員變量、方法及構(gòu)造函數(shù)進(jìn)行注解,完成自動裝配的工作。相比于我們繁瑣的傳統(tǒng)xml配置注入來說,Annotation 的自動裝配會更加簡便,給需要注入的屬性或方法加上** @Autowired** 后即可對該屬性或方法進(jìn)行自動注入,如果我們的屬性是接口,
?或者是一個父類的話,我們可以再加一個?@Qualifier?并為其設(shè)置一個value 即可指定該接口或該父類所指定的實(shí)現(xiàn)類或子類(對應(yīng)于實(shí)現(xiàn)類或父類中?@Component?中的value)。
一、實(shí)現(xiàn)功能:
Annotation版的spring自動裝配
二、實(shí)現(xiàn)思路:
spring ioc 底層也是基于java反射技術(shù)實(shí)現(xiàn)的,本次模仿牽扯到很多關(guān)于java反射方面的知識,如果各位小伙伴對java反射還不是太了解的的話可能這篇博文你會聽的暈乎乎的噢!
-
創(chuàng)建我們需要的Annotation?@Component @Autowired @Qualifier
-
創(chuàng)建ApplicationContext接口,里面一個getBean()方法,創(chuàng)建AnnotationConfigApplicationContext類實(shí)現(xiàn)ApplicationContext接口
-
AnnotationConfigApplicationContext的構(gòu)造方法會接收一個包名,然后負(fù)責(zé)把這個包下面的所有java類的路徑拿出來,再將路徑處理一下即可得到類全名,并放入集合,再通Class.forName(類全名)得到所有Java類的Class 并放入集合
-
遍歷集合所有的class判斷該類上是否加了@Component, 再把加了@Component?的Class放置一個集合,然后再判斷Class 的@Component?是否存在value,如果存在,則把valuevalue作為key 該Class作為value 放置一個Map集合
-
AnnotationConfigApplicationContext重寫的?getBean()??接收一個類的Class, 得到接收Class的實(shí)例對象,進(jìn)行相應(yīng)屬性的依賴注入,解決完依賴后return實(shí)例對象。得到Class所有的Field,遍歷Field是否加了?@Autowired,如果加了?@Autowired再次判斷是否加了?@Qualifier,如果加了?@Qualifier?,用?@Qualifier的value去Map集合 得到對應(yīng)的Class,然后使用Field.set為實(shí)例對象的該Field賦值如(field.set(object,value))value為回調(diào)本方法后的返回值(本方法會返回Class的實(shí)例), 如果沒有加?@Qualifier?則得到該Field的類型的Class ,使用Field.set為實(shí)例對象的該Field賦值,值為回調(diào)本方法后的返回值。待處理完所有的依賴注入后返回實(shí)例對象。
三、Java代碼:
創(chuàng)建需要的Annotation
1、創(chuàng)建@Component
package com.custom.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(value={ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface Component {public String value() default ""; }2、創(chuàng)建@Autowired
package com.custom.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.Target; @Target(value={ElementType.FIELD,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface Autowired { }3、創(chuàng)建@Qualifier
package com.custom.annotation; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @Retention(RetentionPolicy.RUNTIME) public @interface Qualifier {public String value() default ""; }主要功能實(shí)現(xiàn)
1、創(chuàng)建ApplicationContext接口
package com.custom.controller; public interface ApplicationContext {public Object getBean(Class clazz); }2、創(chuàng)建AnnotationConfigApplicationContext類
package com.custom.controller; import java.io.File; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import com.custom.annotation.Autowired; import com.custom.annotation.Component; import com.custom.annotation.Qualifier; import com.custom.exception.CustomException; import com.example.Hello; import com.example.World;public class AnnotationConfigApplicationContext implements ApplicationContext {private String projectPath=this.getClass().getResource("/").getPath();//項(xiàng)目路徑private List<Class> clazzList;//包下所有類private List<String> filePaths;//包下所有文件名private Map<String,Class> existComponentClassMap;//含有@Component注解的類private Map<String,Class> existComponentValueClassMap;//含有@Qualifier值的類public AnnotationConfigApplicationContext(String... strings){clazzList=new ArrayList<Class>();existComponentClassMap=new HashMap<>();existComponentValueClassMap=new HashMap<>();for (String tempPackageName : strings) {//遍歷傳進(jìn)來的包filePaths=getFileName(projectPath+(tempPackageName.replaceAll("[.]","/")));try {//把掃描到包下的類都放入clazzList集合clazzList.addAll(getFileClass(filePaths)) ;//遍歷所有類,看是否加了@Component isComponent();} catch (Exception e) {// TODO Auto-generated catch block e.printStackTrace();}}}@Overridepublic Object getBean(Class clazz) {try {//判斷傳入的類是否加了@Componentif(existComponentClassMap.get(clazz.getName())!=null){//解決clazz依賴并返回clazz的實(shí)例return isAutowired(clazz);}else{//拋出異常throw new CustomException("not found "+clazz.getName()+" mapping class");}} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}return null;}//循環(huán)判斷是否加了@Componentprivate void isComponent(){for (Class tempClass : clazzList) {//判斷該類是否加有@Componentif(tempClass.isAnnotationPresent(Component.class)){//把加了@Component注解的類放入集合existComponentClassMap.put(tempClass.getName(),tempClass);Component component=(Component)tempClass.getAnnotation(Component.class);//得出@Component中的valueString componentValue=component.value();//判斷@Component中的value是否有值if(componentValue.length()>0){//把@Component中的value和當(dāng)前類的class放入Map集合中existComponentValueClassMap.put(componentValue, tempClass);}}}}//循環(huán)判斷加了Component注解類里面是否有加了@Autowired注解,和@Qualifier的屬性或方法private Object isAutowired(Class clazz) throws Exception{//得到傳入clazz的實(shí)例Object object=clazz.newInstance();//得到clazz的所有的屬性Field fields[]=clazz.getDeclaredFields();//遍歷所有屬性for (Field field : fields) {//判斷該屬性是否加了@Autowiredif(field.isAnnotationPresent(Autowired.class)){//判斷該屬性是否加了@Qualifierif(field.isAnnotationPresent(Qualifier.class)){Qualifier qualifier=field.getAnnotation(Qualifier.class);//使用@Qualifier的值從Map集合中拿出對該值對應(yīng)的classClass Tempclazz=existComponentValueClassMap.get(qualifier.value());if(Tempclazz!=null){//為屬性設(shè)置賦值權(quán)限field.setAccessible(true);//為實(shí)例出來的clazz對象的該屬性賦值,賦值之前再次遞歸調(diào)用本方法,傳入該屬性類型的classfield.set(object,isAutowired(Tempclazz));}else{throw new CustomException("not found "+qualifier.value()+" mapping class");}}else{//得到該屬性的類型Class fieldType=field.getType();Class Tempclazz=existComponentClassMap.get(fieldType.getName());if(Tempclazz!=null){field.setAccessible(true);field.set(object,isAutowired(Tempclazz));}else{throw new CustomException("not found "+fieldType.getName()+" mapping class");}}}}return object;}//得到指定包下面的所有java文件路徑public List<String> getFileName(String packgePath){List<String> filePaths=new ArrayList<>();String filePath=packgePath;File file=new File(filePath);//判斷是否為目錄if(file.isDirectory()){//得到包下所有文件File files[]=file.listFiles();for (File file2 : files) {//判斷是否為目錄if(file2.isDirectory()){//遞歸調(diào)用filePaths.addAll(getFileName(file2.getPath()));}else{//如果后綴為class則把該文件路徑放入集合if(file2.getName().substring(file2.getName().lastIndexOf(".")+1).equals("class")){filePaths.add(file2.getPath());}}}}return filePaths;}//返回所有java文件的classpublic List<Class> getFileClass(List<String> filePath) throws ClassNotFoundException{List<Class> list=new ArrayList<Class>();for (String tempFileName : filePath) {//從項(xiàng)目路徑之后開始截取java文件名String tempClassName=tempFileName.substring(projectPath.length()-1);//把路徑中的“\”替換成“.”例如“com\test\test.java”替換后“com.test.test.java”tempClassName=tempClassName.replaceAll("\\\\",".");//再把后面的“.java”截取掉 然后使用Class.forName得到該類的class,并放入集合list.add(Class.forName(tempClassName.substring(0,tempClassName.lastIndexOf("."))));}return list;} }當(dāng)然Annotation 自動裝配也不是特別完美的,就比如我們要自動裝配一個類的話 ?必須為其設(shè)置?@Component?,比如我們要實(shí)例一些第三方j(luò)ar包中的類,我們總不可能讓第三方為我們加上@Component吧,當(dāng)然 這是不現(xiàn)實(shí)的,不過如果你面子夠大的話還是可以試一下的哈!所以在我們的實(shí)際開發(fā)中結(jié)合Annotation和xml使用才是最佳王道、當(dāng)然,前者是基于普通是ssm項(xiàng)目、如果是基于springboot來的話 我們要配合javaConfig配置模式
?
總結(jié)
以上是生活随笔為你收集整理的模拟springIOC容器的annotation的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: spring FactoryBean的知
- 下一篇: AnnotationConfigAppl