Spring源码分析 手写IOC容器

Spring的两大特性就是IOC和AOP。
IOC Container,控制反转容器,通过读取配置文件或注解,将对象封装成Bean存入IOC容器待用,程序需要时再从容器中取,实现控制权由程序员向程序的转变。

一、代码结构

Spring源码分析 手写IOC容器

二、注解扫描

1、新建OrderService、UserService、Test类用于模拟实际开发
@Component("orderService")
@Scope("prototype")
public class OrderService implements BeanNameAware {
  
    @Autowired
    private UserService userService;

    public void test() {
        System.out.println(userService);
    }

    public void setBeanName(String name) {
        this.beanName = beanName;
    }
}
@Component("userService")
public class UserService {
}
public class Test {
    public static void main(String[] args) {
        //对应AnnotationConfigApplicationContext
        //扫描 (判断是否存在Component) + 实例化(Bean的生命周期:1、实例化 2、依赖注入)
        CustomApplicationContext customApplicationContext = new CustomApplicationContext(AppConfig.class);

        Object userService1 = customApplicationContext.getBean("orderService");
        System.out.println(userService);
        System.out.println(userService1);



    }
}
2、新建注解Component、ComponentScan、Autowired、Scope
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Component {  // 用于将类注册成Bean
    String value() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ComponentScan { //用于配置类扫描的包
    String value() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD})
public @interface Autowired { //属性注入
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Scope { //bean的范围
    String value() default "singleton";
}
3、定义CustomApplicationContext实现注解扫描
  • 对应Spring的AnnotationConfigApplicationContext,通过传入配置文件对象,读取ComponentScan的Value进行包扫描,扫描后获取带@Component注解的类
public class CustomApplicationContext {

    private Class configClass;

    public CustomApplicationContext(Class configClass) {

        this.configClass = configClass;

        //扫描(判断类上是否存在Component)(class文件) --> 形成beanDefinition
        List<Class> classList = scan(configClass);
    }
  
  	private List<Class> scan(Class configClass) {
        List<Class> list = new ArrayList<Class>();
      
      	//存在注解,通过value获取要扫描包路径
        if (configClass.isAnnotationPresent(ComponentScan.class)){
            ComponentScan componentScan = (ComponentScan)configClass.getAnnotation(ComponentScan.class);
            String path = componentScan.value();
            path = path.replace(".","/"); //包转化为包路径(com.gg.service)

            //扫描path路径下到类
            ClassLoader classLoader = CustomApplicationContext.class.getClassLoader();
          			// 利用类加载器,根据包路径获取URL/target/classes/com/gg/service
            URL resource = classLoader.getResource(path);
            File file = new File(resource.getFile());
          	
            if (file.isDirectory()) {
                for (File f: file.listFiles()){
                    String absolutePath = f.getAbsolutePath(); //类的完整路径
                    absolutePath = absolutePath.substring(absolutePath.indexOf("com"),absolutePath.indexOf(".class"));
                    absolutePath = absolutePath.replace("/","."); 
                    //com.gg.service.userService

                    Class clazz = null;
                    try {
                        clazz = classLoader.loadClass(absolutePath);
                        // 存在注解,将类加入数组
                        if (clazz.isAnnotationPresent(Component.class)) {
                            list.add(clazz);
                        }
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return list;
    }

}
4、将扫描获得的类封装成beanDefinition
  • 扫描得到的类,将beanName、类型、类的范围封装成beanDefinition
  • getBean时不用重新扫描,直接冲beanDefinitionMap获取
    private Map<String,BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();

public CustomApplicationContext(Class configClass) {

    this.configClass = configClass;

    List<Class> classList = scan(configClass); //扫描得到class

    for (Class clazz: classList){
            Component component = (Component) clazz.getAnnotation(Component.class);
            String beanName = component.value();

            BeanDefinition beanDefinition = new BeanDefinition();
            if (clazz.isAnnotationPresent(Scope.class)){
                Scope scope = (Scope) clazz.getAnnotation(Scope.class);
                beanDefinition.setScope(scope.value());
            }else{
                beanDefinition.setScope("singleton");//默认为单例
            }
            beanDefinition.setBeanClass(clazz);
            beanDefinitionMap.put(beanName,beanDefinition);
    }
public class BeanDefinition { //bean的定义

    private String scope;
    private Class beanClass;

    public String getScope() {
        return scope;
    }

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

    public Class getBeanClass() {
        return beanClass;
    }

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

}
  • 至此,我们通过新建CustomApplicationContext,将添加注解的类加入到beanDefinitionMap。

三、实例化Bean

1、单例类先实例化,存入单例池
  • 从beanDefinitionMap取出BeanDefinition,对单例类调用createBean()实例化,添加到单例池
private Map<String,Object> singletonPool = new ConcurrentHashMap<String, Object>();
public CustomApplicationContext(Class configClass) {

    this.configClass = configClass;

    //扫描将注解的类存入beanDefinitionMap
    List<Class> classList = scan(configClass);
    for (Class clazz: classList){
            Component component = (Component) clazz.getAnnotation(Component.class);
            String beanName = component.value();
            BeanDefinition beanDefinition = new BeanDefinition();
            if (clazz.isAnnotationPresent(Scope.class)){
                Scope scope = (Scope) clazz.getAnnotation(Scope.class);
                beanDefinition.setScope(scope.value());
            }else{
                beanDefinition.setScope("singleton");
            }
            beanDefinition.setBeanClass(clazz);
            beanDefinitionMap.put(beanName,beanDefinition);
    }
		//将单例类添加到单例池singletonPool
    for (String beanName : beanDefinitionMap.keySet()){
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if (beanDefinition.getScope().equals("singleton")){
            //实例化bean
            Object bean = createBean(beanName,beanDefinition);
            singletonPool.put(beanName,bean);
        }
    }

}
private Object createBean(String beanName,BeanDefinition beanDefinition) {
    //实例化、填充属性、Aware、初始化
    Class beanClass = beanDefinition.getBeanClass();
    try {
        // 从beanDefinition中获取类型,并实例化
        Object bean = beanClass.getDeclaredConstructor().newInstance();
        //属性填充
        Field[] fields = beanClass.getDeclaredFields(); //DeclaredFields 所有属性
        for(Field field: fields){
            if (field.isAnnotationPresent(Autowired.class)){
                Object annotationField = getBean(field.getName());
                field.setAccessible(true); //反射产生对象要打开权限
                field.set(bean,annotationField);
            }
        }
        // Aware
        if (bean instanceof BeanNameAware){
            ((BeanNameAware)bean).setBeanName(beanName); //实现该端口就调用此方法
        }
        // 初始化
        if (bean instanceof InitializingBean){
            ((InitializingBean)bean).afterPropertiesSet(); //实现该端口就调用此方法
        }
        return bean;

    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    }
    return null;
}

  • 新建BeanNameAware、InitializingBean接口,实例类时,通过判断是否实现该接口,在实例初始化时
public interface BeanNameAware {
    public void setBeanName(String name);
}
public interface InitializingBean {
    public void afterPropertiesSet();
}
  • 通过调用createBean()实例化beanDefinition中的类,单例在启动时实例,原型在调用getBean()再实例
2、getBean()
public Object getBean(String beanName){
    BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
    if (beanDefinition.getScope().equals("prototype")){
        return createBean(beanName,beanDefinition);
    }else{
        Object bean = singletonPool.get(beanName);
        if (bean == null){
            Object newBean = createBean(beanName,beanDefinition);
            singletonPool.put(beanName,newBean);
            return newBean;
        }
        return bean;
    }
}
上一篇:解读SpringBoot和SpringMVC中配置类的@Impot等导入是如何解析的


下一篇:SVN删除tags旧版本失败