手写IOC容器(xml,注解)

手写IOC容器(xml,注解),第1张

手写IOC容器(xml,注解) 手写IOC容器(xml,注解)

软件设计模式期末作业的设计内容:

在网上参考了资料,将两份资料,再加上自己的理解融合成一份!!

xml的参考资料’君君要上天’手写的IOC容器
注解的参考资料’楠哥教你学Java’手写的IOC容器

1.概念
IOC又称控制反转,把原先我们代码里面需要实现的对象的创建、依赖的代码,反转给容器来帮忙实现。

2.设计思路
A.配置文件配置包扫描路径
B.递归包扫描获取.class文件
C.反射确定需要交给IOC管理的类
D.对需要注入的类进行依赖注入

3.XMl配置
3.1导入依赖


            
                dom4j
                dom4j
                1.6.1
            

            
                jaxen
                jaxen
                1.1.4
            

            
                org.projectlombok
                lombok
                1.18.10
                compile
            
            
 

3.2编写Property

package com.myspring.bean;


public class Property {

    private String name;
    private String value;
    private String ref;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getValue() {
        return value;
    }
    public void setValue(String value) {
        this.value = value;
    }
    public String getRef() {
        return ref;
    }
    public void setRef(String ref) {
        this.ref = ref;
    }

}

3.3编写Bean

package com.myspring.bean;

import java.util.ArrayList;
import java.util.List;



public class Bean {

    private String beanName;
    private String className;
    private Class beanClass;
    private List properties = new ArrayList();//bean节点下可以有多个property节点

    public Bean(){}
    public Bean(String beanName,Class beanClass){
        this.beanName=beanName;
        this.beanClass=beanClass;
    }

    public String getBeanName() {
        return beanName;
    }

    public void setBeanName(String beanName) {
        this.beanName = beanName;
    }

    public String getClassName() {
        return className;
    }

    public void setClassName(String className) {
        this.className = className;
    }

    public Class getBeanClass() {
        return beanClass;
    }

    public void setBeanClass(Class beanClass) {
        this.beanClass = beanClass;
    }

    public List getProperties() {
        return properties;
    }

    public void setProperties(List properties) {
        this.properties = properties;
    }

    @Override
    public String toString() {
        return "Bean{" +
                "beanName='" + beanName + ''' +
                ", className='" + className + ''' +
                ", beanClass=" + beanClass +
                ", properties=" + properties +
                '}';
    }
}

3.4编写工具类BeanUtil

package com.myspring.utils;
import java.lang.reflect.Method;

public class BeanUtil {

    
    public static Method getSetterMethod(Object obj,String name){
        Method method = null;
        //setter方法名称(驼峰)
        name = "set"+name.substring(0,1).toUpperCase()+name.substring(1);
        try {
            Method[] methods = obj.getClass().getMethods();
            //遍历该类的所有方法
            for(int i=0;i 

3.5编写扫描器XmlScanner

package com.myspring.scanner;

import com.myspring.bean.Bean;
import com.myspring.bean.Property;
import org.dom4j.document;
import org.dom4j.documentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


public class XmlScanner {
    
    public static Map getBeanMap(String path){

        Map beanMap = new HashMap();
        //使用dom4j和xpath读取xml文件
        //使用SAXReader需要导入dom4j-full.jar包。
        //dom4j是一个Java的XML API,用来读写XML文件的。
        // 定义一个文档
        document doc = null;
        // 创建xml解析对象
        SAXReader reader = new SAXReader();
        //getResourceAsStream为读取文件,返回的是inputStream类型的(path传进来的参数)
        InputStream in = XmlScanner.class.getResourceAsStream(path);
        try {
            //xml解析对象对输入流进行解析,解析完放在doc文档中
            doc = reader.read(in);
        } catch (documentException e) {
            e.printStackTrace();
            throw new RuntimeException("请检查您的xml配置文件路径是否正确!");
        }
        //定义xpath,取出所有的bean
        String xpath = "//bean";
        //对bean进行遍历 文档进行选则节点(bean)
        List list = doc.selectNodes(xpath);
        //当文件的bean有至少一个,则list!=null
        if(list!=null){
            //for加强循环,把list中的element取出来(bean)
            for (Element beanEle : list) {
                //new一个bean对象
                Bean bean = new Bean();
                //bean节点的id
                String id = beanEle.attributevalue("id");
                //bean节点的class属性
                String className = beanEle.attributevalue("class");
                //封装到bean对象中
                bean.setBeanName(id);
                bean.setClassName(className);

                //获取bean节点下所有的property节点(属性)
                List proList = beanEle.elements("property");
                //当bean中的属性对象个数大于0,至少含有一个
                if(proList != null){
                    for (Element pro : proList) {
                        Property prop = new Property();
                        String propName = pro.attributevalue("name");
                        String propValue = pro.attributevalue("value");
                        String propRef = pro.attributevalue("ref");
                        //封装到property属性中
                        prop.setName(propName);
                        prop.setValue(propValue);
                        prop.setRef(propRef);

                        bean.getProperties().add(prop);
                    }
                }
                //id是不应重复的(如果后注册的一个新Bean与之前注册过的存在重复)
                if(beanMap.containsKey(id)){
                    throw new RuntimeException("bean节点ID重复:" + id);
                }
                //将bean封装到map中
                beanMap.put(id, bean);
            }
        }
        return beanMap;
    }
}

3.6编写BeanFactory

package com.myspring.context;


public interface BeanFactory {
    Object getBean(String beanName);
}

3.7编写ClassPathXmlApplicationContext

package com.myspring.context;

import com.myspring.bean.Bean;
import com.myspring.bean.Property;
import com.myspring.scanner.XmlScanner;
import com.myspring.utils.BeanUtil;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;



public class ClassPathXmlApplicationContext implements BeanFactory {

    //定义一个IOC容器
    private Map iocMap;

    //定义一个存储Bean的容器
    private Map beanMap;

    
    public ClassPathXmlApplicationContext(String path){
        //初始化IOC容器
        iocMap = new HashMap();
        //读取配置文件
        beanMap = XmlScanner.getBeanMap(path);
        if(beanMap!=null){
            for(Entry entry : beanMap.entrySet()){
                String beanId = entry.getKey();
                Bean bean = entry.getValue();

                //根据bean生成相应的对象
                Object object = createBean(bean);
                iocMap.put(beanId, object);
            }
        }
    }
    
    private Object createBean(Bean bean) {
        String beanId = bean.getBeanName();
        String className = bean.getClassName();

        Class c = null;
        Object object = null;

        try {
            //根据bean的class属性生成对象--》反射
            c = Class.forName(className);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException("您配置的class属性不合法:"+className);
        }

        try {
            //该方法调用的是类的无参构造方法
            object = c.newInstance();
        } catch (Exception e) {
            throw new RuntimeException("该类缺少一个无参构造方法:"+className);
        }
        //将bean的属性封装到对象中
        if(bean.getProperties() != null){
            for(Property p : bean.getProperties()){
                //情况一:配置文件中使用的是value属性注入
                if(p.getValue() != null){
                    //获取属性对应的setter方法
                    Method getMethod = BeanUtil.getSetterMethod(object,p.getName());
                    try {
                        //调用set方法注入
                        getMethod.invoke(object, p.getValue());
                    } catch (Exception e) {
                        throw new RuntimeException("属性名称不合法或者没有相应的getter方法:"+p.getName());
                    }
                }
                //情况二:配置文件中使用的是ref属性注入
                if(p.getRef() != null){
                    //获取属性对应的setter方法
                    Method getMethod = BeanUtil.getSetterMethod(object,p.getName());
                    //从容器中找到依赖的对象
                    Object obj = iocMap.get(p.getRef());
                    if(obj == null){
                        throw new RuntimeException("没有找到依赖的对象:"+p.getRef());
                    }else{
                        //调用set方法注入
                        try {
                            getMethod.invoke(object, obj);
                        } catch (Exception e) {
                            throw new RuntimeException("属性名称不合法或者没有相应的getter方法:"+p.getName());
                        }
                    }
                }
            }
        }
        return object;
    }

    @Override
    public Object getBean(String beanName) {
        return iocMap.get(beanName);
    }

}

3.8测试
3.8.1编写Cat类

package com.myspring.test;

public class Cat {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Cat{" +
                "name='" + name + ''' +
                '}';
    }
}

3.8.2编写People类

package com.myspring.test;

public class People {

    private String name;
    private Cat cat;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }


    public Cat getCat() {
        return cat;
    }

    public void setCat(Cat cat) {
        this.cat = cat;
    }


    @Override
    public String toString() {
        return "People{" +
                "name='" + name + ''' +
                ", cat=" + cat +
                '}';
    }
}

3.8.3编写ApplicationContext.xml



    
        
    

    
        
        
    



3.8.4编写Test类

package com.myspring.test;

import com.myspring.bean.Bean;
import com.myspring.context.BeanFactory;
import com.myspring.context.ClassPathXmlApplicationContext;
import com.myspring.scanner.XmlScanner;

import java.util.Map;

public class Test {

    public static void main(String[] args) {
        //测试xml
        BeanFactory factory = new ClassPathXmlApplicationContext("/applicationContext.xml");
        People people = (People) factory.getBean("people");
        System.out.println(people.toString());
        Cat cat = (Cat) factory.getBean("cat");
        System.out.println(cat.toString());
    }

}

测试成功!!

4.注解配置【注解所需要的Bean、BeanFactory不需要重写,故注解省略】
4.1编写注解
4.1.1编写注解@Autowired

package com.myspring.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {
}

4.1.2编写注解@Component

package com.myspring.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Component {
    String value() default "";
}

4.1.3编写注解@Qualifier

package com.myspring.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Qualifier {
    String value();
}

4.1.4编写注解@Value

package com.myspring.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Value {
    String value();
}

4.2编写注解扫描器AnnotationScanner

package com.myspring.scanner;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.linkedHashSet;
import java.util.Set;


public class AnnotationScanner {

    public static Set> getClasses(String pack) {

        // 第一个class类的集合
        Set> classes = new linkedHashSet>();
        // 是否循环迭代
        boolean flag = true;
        // 获取包的名字 并进行替换
        String packageName = pack;
        String packageDirName = packageName.replace('.', '/');
        // 定义一个枚举的集合 并进行循环来处理这个目录下的things
        Enumeration dirs;
        try {
            dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
            // 循环迭代下去
            while (dirs.hasMoreElements()) {
                // 获取下一个元素
                URL url = dirs.nextElement();
                // 得到协议的名称
                String protocol = url.getProtocol();
                // 如果是以文件的形式保存在服务器上
                if ("file".equals(protocol)) {
                    // 获取包的物理路径
                    String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
                    // 以文件的方式扫描整个包下的文件 并添加到集合中
                    findByFile(packageName, filePath, flag, classes);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return classes;
    }


    private static void findByFile(String packageName, String packagePath, final boolean flag, Set> classes) {
        // 获取此包的目录 建立一个File
        File dir = new File(packagePath);
        // 如果不存在或者 也不是目录就直接返回
        if (!dir.exists() || !dir.isDirectory()) {
            return;
        }
        // 如果存在 就获取包下的所有文件 包括目录
        File[] dirfiles = dir.listFiles(new FileFilter() {
            // 自定义过滤规则 如果可以循环(包含子目录) 或则是以.class结尾的文件(编译好的java类文件)
            @Override
            public boolean accept(File file) {
                return (flag && file.isDirectory()) || (file.getName().endsWith(".class"));
            }
        });
        // 循环所有文件
        for (File file : dirfiles) {
            // 如果是目录 则继续扫描
            if (file.isDirectory()) {
                findByFile(packageName + "." + file.getName(), file.getAbsolutePath(), flag, classes);
            } else {
                // 如果是java类文件 去掉后面的.class 只留下类名
                String className = file.getName().substring(0, file.getName().length() - 6);
                try {
                    // 添加到集合中去
                    classes.add(Thread.currentThread().getContextClassLoader().loadClass(packageName + '.' + className));
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}


4.3编写AnnotationApplicationContext

package com.myspring.context;

import com.myspring.annotation.Autowired;
import com.myspring.annotation.Component;
import com.myspring.annotation.Qualifier;
import com.myspring.annotation.Value;
import com.myspring.bean.Bean;
import com.myspring.scanner.AnnotationScanner;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;


public class AnnotationApplicationContext implements BeanFactory {

    private Map iocMap = new HashMap<>();
    private List beanNames = new ArrayList<>();

    public AnnotationApplicationContext(String pack) {
        //遍历包,找到目标类(原材料)
        Set bean = findBean(pack);
        //根据原材料创建bean
        createObject(bean);
        //自动装载
        autowireObject(bean);
    }

    public void autowireObject(Set bean){
        Iterator iterator = bean.iterator();
        while (iterator.hasNext()) {
            Bean beanDefinition = iterator.next();
            Class clazz = beanDefinition.getBeanClass();
            Field[] declaredFields = clazz.getDeclaredFields();
            for (Field declaredField : declaredFields) {
                Autowired annotation = declaredField.getAnnotation(Autowired.class);
                if(annotation!=null){
                    Qualifier qualifier = declaredField.getAnnotation(Qualifier.class);
                    if(qualifier!=null){
                        //byName
                        try {
                            String beanName = qualifier.value();
                            Object beanOb = getBean(beanName);
                            String fieldName = declaredField.getName();
                            String methodName = "set"+fieldName.substring(0, 1).toUpperCase()+fieldName.substring(1);
                            Method method = clazz.getMethod(methodName, declaredField.getType());
                            Object object = getBean(beanDefinition.getBeanName());
                            method.invoke(object, beanOb);
                        } catch (NoSuchMethodException e) {
                            e.printStackTrace();
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        } catch (InvocationTargetException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }

    public Object getBean(String beanName){
        return iocMap.get(beanName);
    }

    public String[] getBeanNames(){
        return beanNames.toArray(new String[0]);
    }

    public Integer getBeanCount(){
        return beanNames.size();
    }

    public void createObject(Set bean){
        Iterator iterator = bean.iterator();
        while (iterator.hasNext()) {
            Bean beanDefinition = iterator.next();
            Class clazz = beanDefinition.getBeanClass();
            String beanName = beanDefinition.getBeanName();
            try {
                //创建的对象
                Object object = clazz.getConstructor().newInstance();
                //完成属性的赋值
                Field[] declaredFields = clazz.getDeclaredFields();
                for (Field declaredField : declaredFields) {
                    Value valueAnnotation = declaredField.getAnnotation(Value.class);
                    if(valueAnnotation!=null){
                        String value = valueAnnotation.value();
                        String fieldName = declaredField.getName();
                        String methodName = "set"+fieldName.substring(0, 1).toUpperCase()+fieldName.substring(1);
                        Method method = clazz.getMethod(methodName,declaredField.getType());
                        //完成数据类型转换
                        Object val = null;
                        switch (declaredField.getType().getName()){
                            case "java.lang.Integer":
                                val = Integer.parseInt(value);
                                break;
                            case "java.lang.String":
                                val = value;
                                break;
                            case "java.lang.Float":
                                val = Float.parseFloat(value);
                                break;
                        }
                        method.invoke(object, val);
                    }
                }
                //存入缓存
                iocMap.put(beanName, object);
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
        }
    }

    public Set findBean(String pack){
        //1、获取包下的所有类
        Set> classes = AnnotationScanner.getClasses(pack);
        Iterator> iterator = classes.iterator();
        Set bean = new HashSet<>();
        while (iterator.hasNext()) {
            //2、遍历这些类,找到添加了注解的类
            Class clazz = iterator.next();
            Component componentAnnotation = clazz.getAnnotation(Component.class);
            if(componentAnnotation!=null){
                //获取Component注解的值
                String beanName = componentAnnotation.value();
                if("".equals(beanName)){
                    //获取类名首字母小写
                    String className = clazz.getName().replaceAll(clazz.getPackage().getName() + ".", "");
                    beanName = className.substring(0, 1).toLowerCase()+className.substring(1);
                }
                //3、将这些类封装成BeanDefinition,装载到集合中
                bean.add(new Bean(beanName, clazz));
                beanNames.add(beanName);
            }
        }
        return bean;
    }
}


4.4测试
4.4.1编写Book类

package com.myspring.test;


import com.myspring.annotation.Component;
import com.myspring.annotation.Value;
import lombok.Data;

@Component
//@Data
public class Book {
    @Value("BOOK1001")
    private String id;
    @Value("软件设计模式")
    private String name;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Book{" +
                "id='" + id + ''' +
                ", name='" + name + ''' +
                '}';
    }
}

4.4.2编写Student类

package com.myspring.test;

import com.myspring.annotation.Autowired;
import com.myspring.annotation.Component;
import com.myspring.annotation.Qualifier;
import com.myspring.annotation.Value;

@Component
public class Student {

    @Value("小红")
    private String name;
    @Value("18")
    private Integer age;

    @Autowired
    @Qualifier("book")
    private Book book;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Book getBook() {
        return book;
    }

    public void setBook(Book book) {
        this.book = book;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + ''' +
                ", age=" + age +
                ", book=" + book +
                '}';
    }
}

4.4.3编写Test类

package com.myspring.test;


import com.myspring.bean.Bean;
import com.myspring.context.AnnotationApplicationContext;
import com.myspring.context.BeanFactory;

import java.util.Map;

public class Test {

    public static void main(String[] args) {
        //测试注解
        BeanFactory factory1 = new AnnotationApplicationContext("com.myspring.test");
        Student student = (Student) factory1.getBean("student");
        System.out.println(student);
        Book book = (Book) factory1.getBean("book");
        System.out.println("book->"+book.toString());

    }

}

测试成功!!

有需要可以找我要源码!!侵权私聊删!!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5709040.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存