参看资料:《Spring揭秘》
DefaultListableBeanFactory看的糊里糊涂的,这篇博客写一下我对Spring ioc的理解,肯定有错误的地方,希望各位指点,不要喷我哈(o.o)。如果你是小白,你可能需要看一下java的反射机制
首先,如果你想要通过配置文件的方法来给bean配置,
你可以就需要四个类,
第一个是BeanDefinition,这个类中保存有配置文件中的每一个配置的bean的信息,最终会通过BeanDefinition提供的信息来生产bean.
第二个是BeanReader,这个类读取配置文件,并把相应的信息转换成BeanDefinition。
第三个是BeanRegist,这个类的作用,就是保存BeanDefinition,BeanDefinition保存bean的信息,BeanRegist保存所有的BeanDefinition(配置文件的每个bean都会有一个相对应的BeanDefinition)。
第四才是我们的BeanFactory,所有的类最后都是通过BeanFactory跟程序员打交道的。
现在我们可以试着来实现一个简单的ioc容器:我们用.properties来所配置文件,用java的Properties类来读取我们的配置文件。
首先是配置文件:
bean_name=com.myioc.Book
book_name=ceshi
book_author=ceshizhe
/*然后是我们的实体类*/
package com.myioc;
public class Book {
private String book_name;
private String book_author;
public String getBook_name() {
return book_name;
}
public void setBook_name(String book_name) {
this.book_name = book_name;
}
public String getBook_author() {
return book_author;
}
public void setBook_author(String book_author) {
this.book_author = book_author;
}
@Override
public String toString() {
return "Book [book_name=" + book_name + ", book_author=" + book_author
+ "]";
}
}
现在需要我们的BeanDefinition
import java.util.Properties;
public class BeanDefinition {
/*我用一个String来保存bean的名字*/
private String beanName;
/*用Properties来保存配置的信息*/
private Properties propertieslist;
/*setter,getter方法,用来设置属性,不然怎么保存*/
/*为了测试,把toString方法重写*/
@Override
public String toString() {
return "BeanDefinition [beanName=" + beanName + ", propertieslist="
+ propertieslist + "]";
}
}
BeanReader
import java.io.File;
import java.io.FileInputStream;
import java.util.Properties;
public class MyReader {
public void loadfile(String classpath,MyRegister myRegister) {
/*这个地方有点绕,reader不但要读取文件,还要将从文件读取到的BeanDefinition注册到Register中,这样Register才能管理Bean*/
Properties properties = new Properties();
/*给定classpath将配置文件读入*/
try {
File file = new File(classpath);
FileInputStream inStream = new FileInputStream(file);
/*读取配置文件*/
properties.load(inStream);
} catch(Exception e) {
System.out.println("配置文件没找到");
}
/*生成一个BeanDefinition*/
BeanDefinition beanDefinition = new BeanDefinition();
/*设置Bean的名字*/
beanDefinition.setBeanName(properties.getProperty("bean_name"));
/*properties中保存了属性名字和对应的名字,直接保存就行了*/
beanDefinition.setPropertieslist(properties);
/*向传入的myRegister注册Beandefinition*/
myRegister.registerBeanDefinition(beanDefinition);
}
}
然后是BeanRegister
import java.util.HashMap;
import java.util.Map;
public class MyRegister {
private Map<String, BeanDefinition> beanDefinitions = new HashMap<>();
/*将beanDefinition放入自己的Map中管理*/
public void registerBeanDefinition(BeanDefinition beanDefinition) {
beanDefinitions.put(beanDefinition.getBeanName(), beanDefinition);
}
/*方便测试*/
public Map<String, BeanDefinition> getBeanDefinitions() {
return beanDefinitions;
}
public void setBeanDefinitions(Map<String, BeanDefinition> beanDefinitions) {
this.beanDefinitions = beanDefinitions;
}
/*这个方式是方便BeanFactory从Regist中取得BeanDefinition然后生成实例的*/
public Object getBeanDefinition(String beanName) {
return beanDefinitions.get(beanName);
}
}
/*Register和BeanFactory的关系,Spring揭秘一书中讲的很好,就好比图书馆与图书馆里面的书架的关系,借书虽然是跟图书馆打交道,但是书本是放在书架上的,这里我们的BeanFactory充当图书馆的角色,Register充当书架的角色。*/
接下来就是我们的BeanFactory
package com.myioc;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.Properties;
import java.util.Set;
public class MyBeanFactory {
/*图书馆里面肯定有书架放书,Reader也可以有其他的写法,但是这里为了测试方便就放在BeanFactory中了*/
private MyRegister myRegister = new MyRegister();
private MyReader myReader = new MyReader();
public MyBeanFactory(String classpath) {
myReader.loadfile(classpath,myRegister);
/*将配置文件的路径和Rrgister给Reader,Reader就会找到配置文件,并且将读取到的信息注册给Register*/
}
public Object getBean(String beanName) {
BeanDefinition beanDefinition = (BeanDefinition)myRegister.getBeanDefinition(beanName);
if(beanDefinition != null) {
try {
/*得到beanName的Class对象*/
Class cl = Class.forName(beanDefinition.getBeanName());
/*得到beanDefinition中保存所有的属性值*/
Properties properties = beanDefinition.getPropertieslist();
/*得到properties的key值*/
Set<Object> keySet = properties.keySet();
Iterator<Object> si = keySet.iterator();
/*生成实例*/
Object newObject = cl.newInstance();
String field;
/*遍历,通过setter方法给 beanName的属性赋值*/
while(si.hasNext()) {
/*遍历keyset中的值*/
field = (String)si.next();
if( !"bean_name".equals(field) && field != null) {
try {
Method m = cl.getMethod(makeMethod(field), String.class);
m.invoke(newObject, properties.getProperty(field));
} catch(Exception e) {
System.out.println("没有"+field+"的set方法");
}
}
}
return newObject;
} catch(Exception e){
System.out.println("forname错误");
}
}
return null;
}
/*得到field的set方法*/
private String makeMethod(String field) {
if(field!=null) {
field = field.substring(0, 1).toUpperCase() + field.substring(1);
return "set"+field;
}
return null;
}
}
就这样 看起来很简单,那是因为我们实现的是简单的ioc更本不能在实际中使用,Sping在实现DefaultListableBeanFactory的时候考虑了很多东西。
现在我们可以测试了
package com.myioc;
public class Test {
public static void main(String ar[]) {
MyBeanFactory bf = new MyBeanFactory("src/Myioc.properties");
Book b = (Book)bf.getBean("com.myioc.Book");
System.out.println(b);
}
}
文件结构:
运行结果: