简单实现spring的IOC

简单实现spring的IOC

当我们熟练使用Spring框架后 发现在项目中最常见的就是注解,那么注解到底是如何在后台运转的?
实际上在框架中我们使用的所有的注解本身都没有任何用处,在框架里边,注解本身只有一个表示的作用(类似于注解),在框架中的注解之所以能实现很多功能,原因是因为每一个注解下面都有大量的反射代码对其进行支持。

IOC 常用的注解如下:

@Component

@Repository

@Service

@Controller

DI 注解:

@Autowried

创建一个maven项目 导入依赖

后续会用到dom解析 导入dom4j依赖

 <dependency>
     <groupId>dom4j</groupId>
     <artifactId>dom4j</artifactId>
     <version>1.6.1</version>
</dependency>
创建Spring对应的自定义注解

@Component

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface Component {

    String value() default "";

}

IOC的其他三个注解创建方式同上

@Autowrited

/**
 * @Target({ElementType.FIELD}) 标识此注解只能用于属性上
 */
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowrited {

    String value() default "";

}
创建BeanFactory接口
/**
 * IOC容器的顶层接口 里面定义从容器获取bean对象的基本方法
 */
public interface BeanFactory {

    /**
     * 根据ID获取bean对象
     * @param name
     * @return
     */
    Object getBean(String name);

    /**
     * 根据类型获取bean
     * @param classType
     * @param <T>
     */
    <T> T getBean(Class<T> classType);
}
创建ApplicationContext接口继承BeanFactory
public interface ApplicationContext extends BeanFactory{
}
创建ClassPathXmlApplicationCintext实现ApplicationContext接口
public class ClassPathXmlApplicationCintext implements ApplicationContext{

    /**
     *  存储对象的容器
     */
    private static Map<String,Object> map = new HashMap<String, Object>();

    /**
     * 用来存储文件路径的
     */
    private List<String> path  = new ArrayList<String>();


    /**
     * 通过构造方法传递过来配置文件名称
     * @param config
     */
    public ClassPathXmlApplicationCintext(String config) {

        readConfig(config);
    }

    private void readConfig(String config){

        SAXReader readeer = new SAXReader();
        try {
            String path2 = ClassPathXmlApplicationCintext.class.getResource("/").getPath();
            Document read =readeer.read(path2+config);
            getPath(read);
        }catch (DocumentException e){
            e.printStackTrace();
        }
    }

    private void getPath(Document read){
        /**
         * 先获得配置文件最外层标签
         */
        Element element = read.getRootElement();

        /**
         * 获得context-scan 标签
         */
        Element el = element.element("context-scan");

        /**
         * 获得context-sccan标签中base-package属性的值
         */
        String base = el.attributeValue("base-package");
        String path2 = ClassPathXmlApplicationCintext.class.getResource("/").getPath();
        base = base.replace(".","/");
        String path = path2 + base;

        doFile(new File(path));

        //将上边的路径换成 包名+类名
        for (int i = 0; i < this.path.size(); i++) {
            String s = this.path.get(i).replace(path2.replace("/","\\").replaceFirst("\\\\",""),"").replace("\\",".").replace(".class","");
            this.path.set(i,s);
        }

        //迭代 .xml 文件中的 bean 标签
        Iterator<Element> ite = element.elementIterator("bean");
        while (ite.hasNext()){
            Element next = ite.next();  //获得bean标签对象
            String cValue = next.attributeValue("class");
            try {
                map.put(next.attributeValue("id"),Class.forName(cValue).newInstance());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        //初始化工厂
        initFactory();
        xmlDi(element.elementIterator("bean"));
        annDi();
    }

    /**
     * xml手动装配
     */
    public void xmlDi(Iterator<Element> ite){
        while (ite.hasNext()){
            Element next = ite.next();
            Iterator<Element> iterator = next.elementIterator();
            String id = next.attributeValue("id");
            while (iterator.hasNext()){
                Element next2 = iterator.next();//获得bean标签里的property标签
                String name = next2.attributeValue("name");//获得name属性的值
                String value = next2.attributeValue("value");//获得value属性的值


                Object obj = map.get(id);//获得IOC容器中的对象
                Class class1 = obj.getClass(); //获得了对象的反射对象
                Field[] fields = class1.getDeclaredFields();
                for (Field field : fields) {
                    if (field.getName().equals(name)) {
                        field.setAccessible(true);
                        try {
                            if (value == null || value.equals("")) {
                                Object object = map.get(next2.attributeValue("ref"));

                                if (object==null){
                                    throw  new RuntimeException("没有ID是"+next2.attributeValue("ref")+"的bean对象,请检查配置文件");
                                }else {
                                    field.set(obj,object);
                                }

                            } else {
                                if (field.getType().getName().equals("java.lang.Integer")||field.getType().getName().equals("int")){
                                    field.set(obj,Integer.valueOf(value));
                                }
                                if (field.getType().getName().equals("java.lang.String")){
                                    field.set(obj, value);
                                }
                            }
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }

    /**
     * 注解自动装配
     */
    public void annDi(){
        Collection<Object> values = map.values();//获得IOC容器中的所有对象
        Iterator<Object> iterator = values.iterator();
        while (iterator.hasNext()){
            Object next = iterator.next(); //取出IOC容器中的对象
            Class class1 = next.getClass(); //获得对象的反射
            Field[] fields = class1.getDeclaredFields(); //获得对象的所有属性
            for (Field field : fields) {
                Autowrited annotation = field.getAnnotation(Autowrited.class);
                if (annotation!=null){
                    field.setAccessible(true);
                    String value = annotation.value();
                    try {
                        if (value.equals("")){
                            field.set(next,getBean(field.getType()));
                        }else {
                            field.set(next,map.get(value));
                        }
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }
            }
        }
    }



    /**
     * 递归
     * @param file
     */
    private void  doFile(File file){
        if (file.isDirectory()){ //判断是否是文件夹
            File[] files = file.listFiles(); //取出文件夹中所有的文件📂
            for (File file2 : files) {
                doFile(file2);
            }
        }else { //递归出口
            if (file.getName().endsWith(".class")){
                path.add(file.getPath()); //将文件添加到集合中
            }
        }
    }

    public void initFactory(){
        for (String string : path) {
            try {

                //首先判断我们的类是否使用了IOC注解
                boolean b = Class.forName(string).isAnnotationPresent(Component.class);
                boolean c = Class.forName(string).isAnnotationPresent(Repository.class);
                boolean d = Class.forName(string).isAnnotationPresent(Service.class);
                boolean e = Class.forName(string).isAnnotationPresent(Controller.class);

                String value = "abc";


                if (b){
                    //获得到注解对象
                    Component an = Class.forName(string).getAnnotation(Component.class);
                     value = an.value();
                }

                if (c){
                    //获得到注解对象
                    Repository an = Class.forName(string).getAnnotation(Repository.class);
                    value = an.value();
                }

                if (d){
                    //获得到注解对象
                    Service an = Class.forName(string).getAnnotation(Service.class);
                    value = an.value();
                }

                if (e){
                    //获得到注解对象
                    Controller an = Class.forName(string).getAnnotation(Controller.class);
                    value = an.value();

                }

                if (value.equals("")){
                    map.put(string,Class.forName(string).newInstance());
                }else if (value.equals("abc")){
                    //fsajkfhjkdsahfjj
                } else {
                    map.put(value,Class.forName(string).newInstance());
                }


            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

    public Object getBean(String name) {
        return map.get(name);
    }

    public <T> T getBean(Class<T> classType) {
        Iterator<Object> iterator = map.values().iterator();
        while (iterator.hasNext()){
            Object next = iterator.next();
            if (next.getClass().getName().equals(classType.getName())||classType.isAssignableFrom(next.getClass())){
                return (T)next;
            }
        }
        return null;
    }
}

写一个XML文件进行测试

<?xml version="1.0" encoding="UTF-8" ?>
<bases>

    <!--定义一个扫描路径 哪些包下的类可以被IOC容器管理-->
    <context-scan base-package="com.zhiyou">
    </context-scan>
    <bean id="aa" class="com.zhiyou.APP">
        <property name="name" value="憨憨"/>
        <property name="in" value="123"/>
        <property name="a" ref="hanhan"/>
    </bean>
</bases>
public static void main(String[] args) {
        ClassPathXmlApplicationCintext app =
                new ClassPathXmlApplicationCintext("application.xml");
        System.out.println(app.getBean("hanhan"));
}
测试没问题的话 可以通过maven命令对项目内进行打包

在别的项目进行导入使用

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-k5csJIxz-1623854078596)(E:\文件\SQLimg\image-20210616223001930.png)]

主要目的
1: 提高思维能力,扩展能力
2: 知道框架(注解)为什么能实现这些功能
``

public static void main(String[] args) {
        ClassPathXmlApplicationCintext app =
                new ClassPathXmlApplicationCintext("application.xml");
        System.out.println(app.getBean("hanhan"));
}
测试没问题的话 可以通过maven命令对项目内进行打包

在别的项目进行导入使用
在这里插入图片描述

主要目的
1: 提高思维能力,扩展能力
2: 知道框架(注解)为什么能实现这些功能
3: 综合技术练习,反射使用场景练习,还是提升思维能力

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值