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");
}
}
写到这里,我们的测试用例便可以通过了。
生活要多点不自量力