继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

模仿 spring IOC Annotation版自动装配

慕村9548890
关注TA
已关注
手记 1296
粉丝 227
获赞 991

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


打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP