模拟Spring中Bean的加载

最近看了一些关于Spring的书籍,结合网上的相关案列,模拟一下Spring的Bean加载的过程

1 模拟Spring的加载环境

1 添加自定义的相关注解

Component注解

在类上使用, 将类注册到中,并且可以指定名称,默认为类名小写.

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

    String value();

}

ComponentScan注解

扫描指定路径, 得到路径下所有的class文件

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

    String value() default "";

}

Scope注解

Bean对象的作用域,默认是单例的

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

    String value() default "singleton";

}

BeanDefinition类

Bean对象的定义类,用来定义对象和作用范围的.

public class BeanDefinition {
    
    

    private Class aClass;
    private String scope;

    public Class getaClass() {
    
    
        return aClass;
    }

    public void setaClass(Class aClass) {
    
    
        this.aClass = aClass;
    }

    public String getScope() {
    
    
        return scope;
    }

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

ApplicationContext类

环境上下文对象,负责添加和获取Bean对象到容器.

public class ApplicationContext {
    
    

    private ConcurrentHashMap<String, Object> singletonMap = new ConcurrentHashMap<>();
    private ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();

    public ApplicationContext(Class aClass) {
    
    

        // 1 获取componentScan注解上的扫描路径
        ComponentScan componentScan = (ComponentScan) aClass.getDeclaredAnnotation(ComponentScan.class);
        String value = componentScan.value().replace(".", "/");
        String path = aClass.getClassLoader().getResource(value).getPath();
        // 2 获取路径下所有class文件
        List<File> fileList = FileUtils.getFileList(path);

        // 3 将注入的Bean对象放到beanDefinitionMap容器中
        fileList.forEach(file -> {
    
    
                    // 得到每个文件的路径
                    String filePath = file.getPath();
                    // 得到类路径  (indexOf方法包头不包尾)
                    String classPath = filePath.substring(filePath.indexOf("classes") + 8, filePath.indexOf(".class")).replace("\\", ".");

                    try {
    
    
                        // 4 将每个Class对象添加到容器中
                        BeanDefinition beanDefinition = new BeanDefinition();
                        BeanDefinition beanDefinition = new BeanDefinition();
                        Class cla = Class.forName(classPath);
                        if (cla.isAnnotationPresent(Component.class)) {
    
    
                            Component component = (Component) cla.getDeclaredAnnotation(Component.class);
                            String className = component.value();
                            beanDefinition.setaClass(cla);
                            if (cla.isAnnotationPresent(Scope.class)) {
    
    
                                Scope scope = (Scope) cla.getDeclaredAnnotation(Scope.class);
                                beanDefinition.setScope(scope.value());
                            } else {
    
    
                                beanDefinition.setScope("singleton");
                            }
                            beanDefinitionMap.put(className, beanDefinition);
                        }
                    } catch (ClassNotFoundException e) {
    
    
                        e.printStackTrace();
                    }
                }
        );

    }

    /**
     * 根据Bean名称获取对象
     *
     * @param beanName
     * @return
     */
    public Object getBean(String beanName) {
    
    

        Object o = null;
        try {
    
    
            if (beanDefinitionMap.containsKey(beanName)) {
    
    
                BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
                // 多例
                if ("prototype".equals(beanDefinition.getScope())) {
    
    
                    o = beanDefinition.getaClass().newInstance();
                } else if (singletonMap.containsKey(beanName)) {
    
    
                    // 单例 且容器中已存在
                    o = singletonMap.get(beanName);
                } else {
    
    
                    // 单例 且容器中不存在
                    o = beanDefinition.getaClass().newInstance();
                    singletonMap.put(beanName, o);
                }
            }
        } catch (Exception e) {
    
    
            throw new RuntimeException("找不到相应的 Bean 对象");
        }

        return o;
    }
    
}

2 添加相关的测试类

ConfigDemo类

给上下文对象使用,获取其注解路径,扫描路径,并注册相关的Bean对象

@ComponentScan("com.cf.service")
public class ConfigDemo {
    
    
}

UserService类

用户类接口,供测试使用

package com.cf.service;
public interface UserService {
    
    

    Integer getUserSum();

}

OrgService类

组织类接口,供测试使用

package com.cf.service;
public interface OrgService {
    
    

    Integer getOrgSum();

}

UserServiceImpl类

用户接口的实现类,供测试使用

@Component("user")
public class UserServiceImpl implements UserService {
    
    
    @Override
    public Integer getUserSum() {
    
    
        Integer count = 100;
        System.out.println("总共有 " + count + " 个用户");
        return count;
    }
}

OrgServiceImpl类

组织接口的实现类,供测试使用

@Component("org")
@Scope("prototype")
public class OrgServiceImpl implements OrgService {
    
    
    @Override
    public Integer getOrgSum() {
    
    
        Integer count = 50;
        System.out.println("总共有 " + count + " 个组织");
        return count;
    }
}

SpringTest类

测试类

public class SpringTest {
    
    

    public static void main(String[] args) {
    
    

        ApplicationContext applicationContext = new ApplicationContext(ConfigDemo.class);

        Object user = applicationContext.getBean("user");
        Object user2 = applicationContext.getBean("user");
        Object org = applicationContext.getBean("org");
        Object org2 = applicationContext.getBean("org");

        System.out.println(user);
        System.out.println(user2);
        System.out.println(org);
        System.out.println(org2);
    }
}

执行结果

/*
    com.cf.service.impl.UserServiceImpl@2d98a335
    com.cf.service.impl.UserServiceImpl@2d98a335
    com.cf.service.impl.OrgServiceImpl@16b98e56
    com.cf.service.impl.OrgServiceImpl@7ef20235
*/

Guess you like

Origin blog.csdn.net/ABestRookie/article/details/121457722