【Spring系列】- 手写模拟Spring框架( 三 )


定义Scope注解通过Scope这个注解来标明是单例bean还是多例bean 。
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)public @interface Scope {    String value() default "";}定义BeanDefinition在spring中,不会在获取bean的时候再去解析是否为单例,而是通过BeanDefinition类来操作 。对bean的定义,记录了bean类和作用域 。
public class BeanDefinition {    private Class type;    private String scope; // 单例多例    public Class getType() {        return type;    }    public void setType(Class type) {        this.type = type;    }    public String getScope() {        return scope;    }    public void setScope(String scope) {        this.scope = scope;    }}因为我们注入spring的bean对象是有Component注解,因此在扫描的时候,我们会通过这个获得到bean,在这时候去创建BeanDefinition对象 。通过判断注解上的值来赋值其作用域,如果没有设置,就默认是单例模式 。创建好的bean对象,我们还需要将他进行保存起来,这个就需要定义ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();存储beanDefinition 。key是component的值,如果component没有传入beanName的值,那就使用spring的命名规则,采用类名首字母小写 。
// 1.7 在通过这个clazz(类)来判断是否有component注解,有则是beanif (clazz.isAnnotationPresent(Component.class)) { Component annotation = clazz.getAnnotation(Component.class); String beanName = annotation.value();    // * 默认生成bean,如果只使用Component注解,没有写上beanName的值,那么就需要自动生成    if (beanName.equals("")) {        // 默认开头小字母        beanName = Introspector.decapitalize(clazz.getSimpleName());    } /**  * 這就是一个bean了  * 然而在这里并不是直接就创建bean了,bean分为了单例bean和多例bean  */ BeanDefinition beanDefinition = new BeanDefinition(); beanDefinition.setType(clazz); if (clazz.isAnnotationPresent(Scope.class)) { // 判断是单例还是多例Scope scope = clazz.getAnnotation(Scope.class);beanDefinition.setScope(scope.value()); } else {beanDefinition.setScope("singleton"); }    beanDefinitionMap.put(beanName, beanDefinition);}getBean底层通过传来一个beanName,通过beanDefinitionMap中获取key为beanName的BeanDefinition对象,进行判空处理 。这样我们可以通过这个BeanDefinition对象去获取作用域,判断是否为单例 。
获取bean在此,我们创建单例的时候,是需要将单例保存起来的,需要定义ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>();单例池来保存单例bean 。然后在getBean的时候,如果是单例bean,就可以先去单例池中寻找,如果没找到,再去创建对象 。而多例模式就需要每次都去创建 。
// 获取bean对象public Object getBean(String beanName) {    BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);    if (beanDefinition == null) {        throw new NullPointerException("找不到bean名字为[" + beanName + "]的bean对象");    } else { // 找到就做相应的操作        String scope = beanDefinition.getScope();        if (scope.equals("singleton")) {            // 通过单例池获取            Object bean = singletonObjects.get(beanName);            if (bean == null) {                // 单例池中如果没有bean,就需要去创建                bean = createBean(beanName, beanDefinition);                singletonObjects.put(beanName, bean);            }            return bean;        } else {            // 多例的就不需要记录,每次都是通过创建            return createBean(beanName, beanDefinition);        }    }}

经验总结扩展阅读