美文网首页
spring(三): 可配置的Spring

spring(三): 可配置的Spring

作者: 一个_人鸭 | 来源:发表于2019-10-09 11:07 被阅读0次

    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);
                // 获取<beans>
                Element root = doc.getRootElement();
                Iterator<Element> iterator = root.elementIterator();
                //遍历所有<bean>,并把信息注册到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<String,Object> singletonObjects = new ConcurrentHashMap<String,Object>(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

          本文链接:https://www.haomeiwen.com/subject/sutyyctx.html