模仿 spring IOC Annotation版自动装配
spring 有两大核心 IOC和AOP。 IOC (inversion of control) 译为 控制反转,也可以称为 依赖注入 ; AOP(Aspect Oriented Programming)即面向切面编程。
我们此次所模仿的是 spring IOC 中的 Annotation 版的自动装配;Spring 在2.5版本后 引入了 @Autowired 以及一系列的 Annotation,它可以对类成员变量、方法及构造函数进行注解,完成自动装配的工作。相比于我们繁琐的传统xml配置注入来说,Annotation 的自动装配会更加简便,给需要注入的属性或方法加上** @Autowired** 后即可对该属性或方法进行自动注入,如果我们的属性是接口,
或者是一个父类的话,我们可以再加一个 @Qualifier 并为其设置一个value 即可指定该接口或该父类所指定的`
实现类或子类(对应于实现类或父类中 @Component 中的value)。
一、实现功能:
Annotation版的spring自动装配
二、实现思路:
spring ioc 底层也是基于java反射技术实现的,本次模仿牵扯到很多关于java反射方面的知识,如果各位小伙伴对java反射还不是太了解的的话可能这篇博文你会听的晕乎乎的噢!
创建我们需要的Annotation @Component @Autowired @Qualifier
创建ApplicationContext接口,里面一个getBean()方法,创建AnnotationConfigApplicationContext类实现ApplicationContext接口
AnnotationConfigApplicationContext的构造方法会接收一个包名,然后负责把这个包下面的所有java类的路径拿出来,再将路径处理一下即可得到类全名,并放入集合,再通Class.forName(类全名)得到所有Java类的Class 并放入集合
遍历集合所有的class判断该类上是否加了@Component, 再把加了@Component 的Class放置一个集合,然后再判断Class 的@Component 是否存在value,如果存在,则把valuevalue作为key 该Class作为value 放置一个Map集合
AnnotationConfigApplicationContext重写的 getBean() 接收一个类的Class, 得到接收Class的实例对象,进行相应属性的依赖注入,解决完依赖后return实例对象。得到Class所有的Field,遍历Field是否加了 @Autowired,如果加了 @Autowired再次判断是否加了 @Qualifier,如果加了 @Qualifier ,用 @Qualifier的value去Map集合 得到对应的Class,然后使用Field.set为实例对象的该Field赋值如(field.set(object,value))value为回调本方法后的返回值(本方法会返回Class的实例), 如果没有加 @Qualifier 则得到该Field的类型的Class ,使用Field.set为实例对象的该Field赋值,值为回调本方法后的返回值。待处理完所有的依赖注入后返回实例对象。
三、Java代码:
创建需要的Annotation
1、创建@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、创建@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、创建@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 ""; }
主要功能实现
1、创建ApplicationContext接口
package com.custom.controller;public interface ApplicationContext { public Object getBean(Class clazz); }
2、创建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();//项目路径 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) {//遍历传进来的包 filePaths=getFileName(projectPath+(tempPackageName.replaceAll("[.]","/"))); try { //把扫描到包下的类都放入clazzList集合 clazzList.addAll(getFileClass(filePaths)) ; //遍历所有类,看是否加了@Component isComponent(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } @Override public Object getBean(Class clazz) { try { //判断传入的类是否加了@Component if(existComponentClassMap.get(clazz.getName())!=null){ //解决clazz依赖并返回clazz的实例 return isAutowired(clazz); }else{ //抛出异常 throw new CustomException("not found "+clazz.getName()+" mapping class"); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } //循环判断是否加了@Component private void isComponent(){ for (Class tempClass : clazzList) { //判断该类是否加有@Component if(tempClass.isAnnotationPresent(Component.class)){ //把加了@Component注解的类放入集合 existComponentClassMap.put(tempClass.getName(),tempClass); Component component=(Component)tempClass.getAnnotation(Component.class); //得出@Component中的value String componentValue=component.value(); //判断@Component中的value是否有值 if(componentValue.length()>0){ //把@Component中的value和当前类的class放入Map集合中 existComponentValueClassMap.put(componentValue, tempClass); } } } } //循环判断加了Component注解类里面是否有加了@Autowired注解,和@Qualifier的属性或方法 private Object isAutowired(Class clazz) throws Exception{ //得到传入clazz的实例 Object object=clazz.newInstance(); //得到clazz的所有的属性 Field fields[]=clazz.getDeclaredFields(); //遍历所有属性 for (Field field : fields) { //判断该属性是否加了@Autowired if(field.isAnnotationPresent(Autowired.class)){ //判断该属性是否加了@Qualifier if(field.isAnnotationPresent(Qualifier.class)){ Qualifier qualifier=field.getAnnotation(Qualifier.class); //使用@Qualifier的值从Map集合中拿出对该值对应的class Class Tempclazz=existComponentValueClassMap.get(qualifier.value()); if(Tempclazz!=null){ //为属性设置赋值权限 field.setAccessible(true); //为实例出来的clazz对象的该属性赋值,赋值之前再次递归调用本方法,传入该属性类型的class field.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()){ //递归调用 filePaths.addAll(getFileName(file2.getPath())); }else{ //如果后缀为class则把该文件路径放入集合 if(file2.getName().substring(file2.getName().lastIndexOf(".")+1).equals("class")){ filePaths.add(file2.getPath()); } } } } return filePaths; } //返回所有java文件的class public List<Class> getFileClass(List<String> filePath) throws ClassNotFoundException{ List<Class> list=new ArrayList<Class>(); for (String tempFileName : filePath) { //从项目路径之后开始截取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; }
作者:芷恋灬
链接:https://www.jianshu.com/p/998515eb520c
共同学习,写下你的评论
评论加载中...
作者其他优质文章