码迷,mamicode.com
首页 > 编程语言 > 详细

Spring源码解析

时间:2021-05-25 18:09:55      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:而且   one   hashmap   获取   try   alac   完成   with   interface   

效仿原生AapplicationContext  简单的源码分为构造方法和getBean方法所以我们需要冲着些方法考虑

基本完成的代码如下

AapplicationContext 类如下

技术图片
package cn.jiedada.spring;

import java.io.File;
import java.lang.annotation.Annotation;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

public class JieDaDaApplicationContext {

    private Class configClass;

    //在getBean中通过名字找到对象
    private Map<String,BeanDefinition> beanDefinitionMap = new HashMap<>();

    //单列池,里面的是currenthashmap
    private Map<String,Object> singletonObjects = new HashMap<>();

    public JieDaDaApplicationContext(Class configClass) {
        this.configClass = configClass;
        //解析配置类
        scopCompenent(configClass);
        //实力化创建单列bean并且保存
        preInstantiateSingleton();
    }

    private void preInstantiateSingleton() {
        for (Map.Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet()) {
            BeanDefinition beanDefinition = entry.getValue();
            String beanName = entry.getKey();
            //我们这里只保留单列的bean,因为多列的创建为使用时候在创建,而且不知道多列能够创建多少
            if ("singleton".equals(beanDefinition.getScope())){
                //如果为单列就创建bean
                Object bean = createBean(beanName, beanDefinition);
                singletonObjects.put(beanName,bean);
            }
        }
    }

    //创建bean的方法
    public Object createBean(String beanName,BeanDefinition beanDefinition){
        Class clazz = beanDefinition.getClazz();
        Object instance = null;
        try {
            instance = clazz.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return instance;
    }

    private void scopCompenent(Class configClass) {
        ComponentScan annotation = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
        //扫秒路径
        String path = annotation.value();//cn.jiedada
        String replace = path.replace(".", "/");

        //扫描component类 1.单列 2.多列
        //通过类加载器获得文件路径
        ClassLoader classLoader = JieDaDaApplicationContext.class.getClassLoader();
        URL resource = classLoader.getResource(replace);
        File file = new File(resource.getFile());
        File[] files = file.listFiles();
        //遍历文件判断是否包含component注解
        for (File f : files) {
            //文件路径
            String filePath = f.getAbsolutePath();
            //判断是否是含有.class
            if (filePath.endsWith(".class")){
                //获得真实路径
                String realPath1 = filePath.substring(filePath.indexOf("cn"), filePath.indexOf(".class"));
                //通过类加载器获得对象应为类加载器需要使用的路径不为cn/jiedada/test/Main需要转化
                String fileRealPath = realPath1.replace("/", ".");
                try {
                    Class clazz = classLoader.loadClass(fileRealPath);
                    //获得component类对象
                    //获得类对象需要判断多列和单列所以需要添加一个注解
                    //因为是通过getBean获得对象,所以不可能再去getBean中在遍历一次,所以我们需要把对象保存BeanDefinition
                    //又因为通过名字获得对象所以需要通过先存入Map对象的方式实现
                    if(clazz.isAnnotationPresent(Component.class)){
                        Component component = (Component) clazz.getAnnotation(Component.class);
                        //保存beanDefinitionMap
                        BeanDefinition beanDefinition = new BeanDefinition();
                        beanDefinition.setClazz(clazz);
                        if (clazz.isAnnotationPresent(Scope.class)){
                            //设置类的scope
                            Scope scope = (Scope) clazz.getAnnotation(Scope.class);
                            String value = scope.value();
                            beanDefinition.setScope(value);
                        }else {
                            beanDefinition.setScope("singleton");
                        }
                        beanDefinitionMap.put(component.value(),beanDefinition);
                    }
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }

        }
    }

    public Object getBean(String beanName){
        //获得beanDefinition
        if (beanDefinitionMap.containsKey(beanName)){
            BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
            if (beanDefinition.getScope().equals("singleton")){
                //单列
                Object o = singletonObjects.get(beanName);
                return o;
            }else {
                //多列
                Object bean = createBean(beanName, beanDefinition);
                return bean;
            }
        }else {
            throw new RuntimeException();
        }
    }
}
View Code

里面分为构造方法和getBean方法

1.构造方法里面需要

JieDaDaApplicationContext context = new JieDaDaApplicationContext(AppConfig.class);

扫描路径获得我们需要生成对象的范围所以需要一个注解

CompenentScan

package cn.jiedada.spring;

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

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

 以及AppConfig类

package cn.jiedada.test;


import cn.jiedada.spring.ComponentScan;

@ComponentScan("cn.jiedada.test")
public class AppConfig {
}

 

这样我们才知道我们需要把什么包下面的对象交给Spring管理

ComponentScan annotation = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
        //扫秒路径
        String path = annotation.value();//cn.jiedada

 

通过类加载器获得.class文件

//通过类加载器获得文件路径
        ClassLoader classLoader = JieDaDaApplicationContext.class.getClassLoader();
        URL resource = classLoader.getResource(replace);
        File file = new File(resource.getFile());
        File[] files = file.listFiles();

 

遍历文件判断是否含有Component注解,这个注解表示生成的对象名称

Component注解

技术图片
package cn.jiedada.spring;

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

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

 

这里就需要把对象的beanName,class对象和是否为单列保存到一个map对象中去,因为如果不在构造方法中保存的话,在getBean方法中就需要在便利

    private Map<String,BeanDefinition> beanDefinitionMap = new HashMap<>();

 

技术图片
for (File f : files) {
            //文件路径
            String filePath = f.getAbsolutePath();
            //判断是否是含有.class
            if (filePath.endsWith(".class")){
                //获得真实路径
                String realPath1 = filePath.substring(filePath.indexOf("cn"), filePath.indexOf(".class"));
                //通过类加载器获得对象应为类加载器需要使用的路径不为cn/jiedada/test/Main需要转化
                String fileRealPath = realPath1.replace("/", ".");
                try {
                    Class clazz = classLoader.loadClass(fileRealPath);
                    //获得component类对象
                    //获得类对象需要判断多列和单列所以需要添加一个注解
                    //因为是通过getBean获得对象,所以不可能再去getBean中在遍历一次,所以我们需要把对象保存BeanDefinition
                    //又因为通过名字获得对象所以需要通过先存入Map对象的方式实现
                    if(clazz.isAnnotationPresent(Component.class)){
                        Component component = (Component) clazz.getAnnotation(Component.class);
                        //保存beanDefinitionMap
                        BeanDefinition beanDefinition = new BeanDefinition();
                        beanDefinition.setClazz(clazz);
                        if (clazz.isAnnotationPresent(Scope.class)){
                            //设置类的scope
                            Scope scope = (Scope) clazz.getAnnotation(Scope.class);
                            String value = scope.value();
                            beanDefinition.setScope(value);
                        }else {
                            beanDefinition.setScope("singleton");
                        }
                        beanDefinitionMap.put(component.value(),beanDefinition);
                    }
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }

        }
View Code

 

所以需要一个存放class对象和是否为单列的一个新对象为beanDeefinition

BeanDeefinition类为

技术图片
package cn.jiedada.spring;

public class BeanDefinition {
    private Class clazz;
    private String scope;

    public Class getClazz() {
        return clazz;
    }

    public void setClazz(Class clazz) {
        this.clazz = clazz;
    }

    public String getScope() {
        return scope;
    }

    public void setScope(String scope) {
        this.scope = scope;
    }
}
View Code

 

和一个注解Scope

package cn.jiedada.spring;

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

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

 

上面整个步骤为解析配置类方法

 

 

 

2.保存对象到单列池

解析过后就需要实力化对象因为涉及多列和单列所以当为单列的时候需要一个单列池保存对象

//单列池,里面的是currenthashmap
    private Map<String,Object> singletonObjects = new HashMap<>();

 

多列的时候就通过反射创建对象所以把创建对象的方法抽为一个方法

//创建bean的方法
    public Object createBean(String beanName,BeanDefinition beanDefinition){
        Class clazz = beanDefinition.getClazz();
        Object instance = null;
        try {
            instance = clazz.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return instance;
    }

 

通过初始化我们把所以的对象保存到了beanDeefinitionMap中??map获得对象并且存放单列池

private void preInstantiateSingleton() {
        for (Map.Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet()) {
            BeanDefinition beanDefinition = entry.getValue();
            String beanName = entry.getKey();
            //我们这里只保留单列的bean,因为多列的创建为使用时候在创建,而且不知道多列能够创建多少
            if ("singleton".equals(beanDefinition.getScope())){
                //如果为单列就创建bean
                Object bean = createBean(beanName, beanDefinition);
                singletonObjects.put(beanName,bean);
            }
        }
    }

 

 

3.获得对象

如果为单列就去单列池中获取如果不是就直接创建对象

public Object getBean(String beanName){
        //获得beanDefinition
        if (beanDefinitionMap.containsKey(beanName)){
            BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
            if (beanDefinition.getScope().equals("singleton")){
                //单列
                Object o = singletonObjects.get(beanName);
                return o;
            }else {
                //多列
                Object bean = createBean(beanName, beanDefinition);
                return bean;
            }
        }else {
            throw new RuntimeException();
        }
    }

 

这就是非常简单的Spring

 

Spring源码解析

标签:而且   one   hashmap   获取   try   alac   完成   with   interface   

原文地址:https://www.cnblogs.com/xiaoruirui/p/14807165.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!