spring(三): 可配置的Spring

ConfigurableBeanFactory

具体代码请查看:litespring_04
我们为了让spring变得可配置,增加了一个ConfigurableBeanFactory接口:

public interface ConfigurableBeanFactory extends BeanFactory {
    //设置classLoader
    void setBeanClassLoader(ClassLoader classLoader);
    //获取classLoader
    ClassLoader getBeanClassLoader();

}

此时ApplicationContext继承ConfigurableBeanFactory,DefaultBeanFactory实现ConfigurableBeanFactory。并实现ConfigurableBeanFactory中的两个方法:

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        this.beanClassLoader = classLoader;
    }

    @Override
    public ClassLoader getBeanClassLoader() {
        return (this.beanClassLoader != null ? this.beanClassLoader : ClassUtils.getDefaultClassLoader());
    }

同时把之前需要用到classLoader的地方也相应做一些变更。例如ClassPathXmlApplicationContext的getReourceByPath方法等。
做完这些,我们就可以配置spring的classLoader了,此时我们再运行一下测试用例也是可以通过的,证明此时并没有破坏我们的功能。

SingletonBean

实现创建的bean为单例的。首先我们来写一个测试用例:

    @Test
    public void testGetBean(){
        //开始解析xml,并把解析结果存入bean的注册类中
        reader.loadBeanDefinitions( resource );
        //通过beanId获取bean的定义
        BeanDefinition bd = factory.getBeanDefinition("petStore");

        Assert.assertTrue(bd.isSingleton());
        Assert.assertFalse(bd.isPrototype());
        Assert.assertEquals(BeanDefinition.SCOPE_DEFAULT,bd.getScope());

        //断言bean的ClassName正确
        Assert.assertEquals("org.litespring.service.v1.PetStoreService",bd.getBeanClassName());
        //根据bean的id获取Bean
        PetStoreService petStore = (PetStoreService) factory.getBean("petStore");
        //断言获取到bean了。
        Assert.assertNotNull(petStore);

        PetStoreService petStore1 = (PetStoreService) factory.getBean("petStore");
        Assert.assertTrue(petStore.equals(petStore1));
    }

首先为们先消除一下编译错误,把相关方法以及属性加在bean的定义类中。

public interface BeanDefinition {

    public static final String SCOPE_SINGLETON = "singleton";
    public static final String SCOPE_PROTOTYPE = "prototype";
    public static final String SCOPE_DEFAULT = "";

    /**
     * 获取bean定义中的className
     * @return
     */
    String getBeanClassName();

    /**
     * 单例
     * @return
     */
    public boolean isSingleton();

    /**
     * 总是创建一个新的bean
     * @return
     */
    public boolean isPrototype();

    /**
     * 获取scope
     * @return
     */
    String getScope();

    /**
     * 设置scope
     * @param scope
     */
    void setScope(String scope);
}

接下来我们实现这些方法。

public class GenericBeanDefinition implements BeanDefinition{

    private String id;

    private Class beanClass;

    private boolean singleton = true;
    private boolean prototype = false;
    private String scope = SCOPE_DEFAULT;

    @Override
    public boolean isSingleton() {
        return this.singleton;
    }

    @Override
    public boolean isPrototype() {
        return this.prototype;
    }

    @Override
    public String getScope() {
        return this.scope;
    }

    @Override
    public void setScope(String scope) {
        this.scope = scope;
        this.singleton = SCOPE_SINGLETON.equals(scope) || SCOPE_DEFAULT.equals(scope);
        this.prototype = SCOPE_PROTOTYPE.equals(scope);
    }

    private String beanClassName;

    public GenericBeanDefinition(String id,String beanClassName) {
        this.id = id;
        this.beanClassName = beanClassName;
    }

    /**
     * 获取bean定义中的className
     * @return className
     */
    public String getBeanClassName() {
        return this.beanClassName;
    }

}

现在我们完成了BeanDefintion的代码。接下来我们需要把xml的scope解析到BeanDefintion中,而xml的解析是在XmlBeanDefintionReader中进行的,所以我们稍微修改一下loadBeanDefintions方法:

public static final String SCOPE_ATTRIBUTE = "scope";

public void loadBeanDefinitions(Resource resource ){
        InputStream is = null;
        try {
            is = resource.getInputStream();
/*            //获取默认类加载器
            ClassLoader cl = ClassUtils.getDefaultClassLoader();
            //读取文件
            is = cl.getResourceAsStream(configFile);*/
            SAXReader reader = new SAXReader();
            Document doc = null;
            doc = reader.read(is);
            // 获取
            Element root = doc.getRootElement();
            Iterator iterator = root.elementIterator();
            //遍历所有,并把信息注册到registry中
            while (iterator.hasNext()){
                Element element = (Element)iterator.next();
                String id = element.attributeValue(ID_ATTRIBUTE);
                String beanClassName = element.attributeValue(CLASS_ATTRIBUTE);
                BeanDefinition bd = new GenericBeanDefinition(id,beanClassName);
                if (null != element.attribute( SCOPE_ATTRIBUTE )){
                    bd.setScope( element.attributeValue( SCOPE_ATTRIBUTE ) );
                }

                this.registry.registerBeanDefinition(id,bd);
            }
        } catch (DocumentException | IOException e) {
            throw new BeanDefinitionStoreException("IOException parsing XML document",e);
        } finally {
            if (is != null){
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

现在我们就完成从xml解析到BeanDefintion的过程。接下来我们就要真正的实现创建SingleBean了。
这里我们提供一个SingletonBeanRegistry接口让它来实现singleton功能,创建DefaultSingletonBeanRegistry去实现接口,并让DefaultBeanFactory继承DefaultSingletonBeanRegistry。
SingletonBeanRegistry如下:

public interface SingletonBeanRegistry {

    /**
     * 注册单例
     * @param beanName
     * @param singletonObject
     */
    void registerSingleton(String beanName,Object singletonObject);

    /**
     * 获取单例的bean
     * @param beanName
     */
    Object getSingleton(String beanName);
}

DefaultSingletonBeanRegistry如下:

public class DefaultSingletonBeanRegistry implements SingletonBeanRegistry {

    private final Map singletonObjects = new ConcurrentHashMap(64);

    /**
     * 注册单例
     * @param beanName
     * @param singletonObject
     */
    @Override
    public void registerSingleton(String beanName, Object singletonObject) {
        Assert.notNull(beanName," 'beanName' must not be null ");
        Object oldObject = this.singletonObjects.get(beanName);
        if (oldObject != null){
            throw new IllegalStateException("Could not register object [" + singletonObject +
                    "] under bean name '" + beanName + "': there is already object [" + oldObject);
        }
        this.singletonObjects.put(beanName,singletonObject);
    }

    @Override
    public Object getSingleton(String beanName) {
        return this.singletonObjects.get(beanName);
    }
}

DefaultSingletonBeanRegistry完成了单例bean的保存和获取。接下来我们需要稍微改动一下DefaultBeanFactory中的getBean方法,让其当beanDefintion中的scope是single时调用DefaultSingletonBeanRegistry这个类中的方法进行约束。
下面就是变更的代码:

    public Object getBean(String beanId) {
        //获取bean的定义
        BeanDefinition bd = this.getBeanDefinition(beanId);
        if (bd == null){
            return null;
        }
/*        //获取默认类加载器
        ClassLoader cl = this.getBeanClassLoader();
        //获取bean的name
        String beanClassName = bd.getBeanClassName();
        try {
            Class clazz = cl.loadClass(beanClassName);
            //反射出类的实体
            return clazz.newInstance();
        } catch (Exception e) {
            throw new BeanCreationException("create bean for " + beanClassName + " fail");
        }*/
        //判断要创建的bean是不是单例的。
        if (bd.isSingleton()){
            //先从singletonObjects这个map中获取
            Object bean = this.getSingleton( beanId );
            //如果没有获取到则创建一个,同时放进singletonObjects中
            if (null == bean){
                bean = createBean(bd);
                this.registerSingleton( beanId , bean );
            }
            return bean;
        }
        //直接创建一个bean
        return createBean(bd);
    }

    /**
     * 通过BeanDefintion创建bean
     * @param bd
     * @return
     */
    private Object createBean(BeanDefinition bd) {
        //获取默认类加载器
        ClassLoader cl = this.getBeanClassLoader();
        //获取bean的name
        String beanClassName = bd.getBeanClassName();
        try {
            Class clazz = cl.loadClass(beanClassName);
            //反射出类的实体
            return clazz.newInstance();
        } catch (Exception e) {
            throw new BeanCreationException("create bean for " + beanClassName + " fail");
        }
    }

写到这里,我们的测试用例便可以通过了。


                                                                                                生活要多点不自量力

你可能感兴趣的:(spring(三): 可配置的Spring)