1、读取配置文件中的bean标签,此时IOC工厂会根据id返回对应的对象,但是此时对象里面的参数没有被进行赋值。
<beans>
<bean id="stu" name="com.etoak.entity.Student"></bean>
</beans>
//BeanUtil类存放bean标签中的信息
public class BeanUtil {
private String id;//表示配置文件中bean中的id,是为了表示用户根据传入的id值来得到对用的对象
private String classname;//表示配置文件中bean中的name,为了工厂根据反射的原理来加载此类
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getClassname() {
return classname;
}
public void setClassname(String classname) {
this.classname = classname;
}
}
public class IOCFactory {
//配置文件中可能又多个bean标签,所以用List集合来装这些属性
private List<BeanUtil> beanUtils=new ArrayList<>();
//创建该对象时,就把配置文件的内容读取到beanUtils列表中
public IOCFactory(){
//解析Xml文件,需要第三方插件
SAXReader reader=new SAXReader();
InputStream url=BeanUtil.class.getClassLoader().getResourceAsStream("conf.xml");
try {
Document doc=reader.read(url);
//得到根元素也就是beans
Element rootElement = doc.getRootElement();
//根据bean找到配置文件中根标签底下标签为bean的所有元素
List<Element> beans = rootElement.elements("bean");
for(Element bean:beans){
BeanUtil beanUtil=new BeanUtil();
//根据bean标签中属性id拿到id所对应的值
beanUtil.setId(bean.attributeValue("id"));
//根据bean标签中属性name拿到对应的值
beanUtil.setClassname(bean.attributeValue("name"));
//把此时根据bean标签中的内容读取到的值拿到集合中
beanUtils.add(beanUtil);
}
} catch (Exception e) {
e.printStackTrace();
}
}
//根据id拿到对应的实例对象
public Object getBean(String id){
Object target=null;
//判断beanUtils是否包含bean标签
if(beanUtils.size()>0){
for (BeanUtil bean:beanUtils){
//判断是否存在该id
if(bean.getId().equals(id)){
try {
//根据name获得class对象
Class cla=Class.forName(bean.getClassname());
//根据cla创建一个无参实例
target=cla.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
return target;
}
}
2、在bean标签中添加一些对应的属性名和属性值
<beans>
<bean id="stu" name="com.etoak.entity.Student">
<property name="user" value="et2201"></property>
<property name="pwd" value="gt"></property>
</bean>
</beans>
此时要在BeanUtil类中添加一个新的属性,用来存放property标签的内容,并创建一个PropertyUtil
//此列表代表该bean标签内的property中的标签,可能不唯一,所有用列表存
private List<PropertyUtil> propertyUtils;
public List<PropertyUtil> getPropertyUtils() {
return propertyUtils;
}
public void setPropertyUtils(List<PropertyUtil> propertyUtils) {
this.propertyUtils = propertyUtils;
}
//存放property标签中的信息
public class PropertyUtil {
private String name;
private String value;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
构造方法中为了获取property值的代码改动
注释是******之间是改动的内容
public IOCFactory(){
//解析Xml文件,需要第三方插件
SAXReader reader=new SAXReader();
InputStream url=BeanUtil.class.getClassLoader().getResourceAsStream("conf.xml");
try {
Document doc=reader.read(url);
//得到根元素也就是beans
Element rootElement = doc.getRootElement();
//根据bean找到配置文件中根标签底下标签为bean的所有元素
List<Element> beans = rootElement.elements("bean");
for(Element bean:beans){
BeanUtil beanUtil=new BeanUtil();
//根据bean标签中属性id拿到id所对应的值
beanUtil.setId(bean.attributeValue("id"));
//根据bean标签中属性name拿到对应的值
beanUtil.setClassname(bean.attributeValue("name"));
//******************************************
//创建一个List集合来存放property标签中的属性,并把这些属性放到bean中
List<PropertyUtil> propertyUtils=new ArrayList<>();
//得到elements为property的所有信息
List<Element> pros=bean.elements("property");
for (Element pro:pros){
PropertyUtil propertyUtil=new PropertyUtil();
//根据property标签中name,value属性获取所对应的值
propertyUtil.setName(pro.attributeValue("name"));
propertyUtil.setValue(pro.attributeValue("value"));
propertyUtils.add(propertyUtil);
}
beanUtil.setPropertyUtils(propertyUtils);
//******************************************
//把此时根据bean标签中的内容读取到的值拿到集合中
beanUtils.add(beanUtil);
}
} catch (Exception e) {
e.printStackTrace();
}
}
此时要改变getBean方法中获得对象+对象的方法赋值,首先我们要知道对于private私有属性赋值取值用getter和setter方法,jdk中有一个PropertyDescription类可以根据get,set方法来进行字段取值赋值。
知道这个之后就可以继续往下探究
public Object getBean(String id){
Object target=null;
//判断beanUtils是否包含bean标签
if(beanUtils.size()>0){
for (BeanUtil bean:beanUtils){
//判断是否存在该id
if(bean.getId().equals(id)){
try {
//根据name获得class对象
Class cla=Class.forName(bean.getClassname());
//根据cla创建一个无参实例,本案例中代表Student对象
target=cla.newInstance();
//****************************************
//获得对象要给此对象的属性进行赋值
List<PropertyUtil> propertyUtils = bean.getPropertyUtils();
for (PropertyUtil propertyUtil:propertyUtils){
//获得PropertyUtil类中的name属性,也就是标签property中的name的值
String name=propertyUtil.getName();
//获得标签中value值
String value=propertyUtil.getValue();
//构造方法两个参数,第一个代表属性名,第二个表示Class对象,此案例表示Student的class对象
PropertyDescriptor propertyDescriptor=new PropertyDescriptor(name,cla);
//这句话表示给target对象调用了关于属性名为name的set方法,并把此时的value值传进去
propertyDescriptor.getWriteMethod().invoke(target,value);
//*************************************
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
return target;
}
我们测试一下看看书否能Student类可以获取到配置文件中的参数
public static void main(String[] args) {
IOCFactory iocFactory=new IOCFactory();
Student stu=(Student)iocFactory.getBean("stu");
System.out.println(stu);//Student{user='et2201', pwd='gt'}
}
此时我们就获得了配置文件中Student类中的属性和值。
3、我们此时的Student类中的参数只有user和pwd两个属性,并且这两个属性的类型是基本数据类型,但是问题是如果在此类中添加另一个对象应该如何做呢?如图在Student类中添加一个School学校类。
我们既然需要一个School类那我们就可以在配置文件添加一个新的标签ref,此标签中的name值则表示getBean(id)方法中的id值
<beans>
<bean id="stu" name="com.etoak.entity.Student">
<property name="user" value="et2201"></property>
<property name="pwd" value="gt"></property>
<ref name="school"></ref>
</bean>
<bean id="school" name="com.etoak.entity.School">
<property name="name" value="etoak"></property>
</bean>
</beans>
所以我们要在BeanUtil中添加一个集合关于存放其他复杂数据类型的对象,无参构造对象改造
//BeanUtil类中添加的代码
//用来存放复杂数据类型变量的集合
private List<RefUtil> refUtils;
public List<RefUtil> getRefUtils() {
return refUtils;
}
public void setRefUtils(List<RefUtil> refUtils) {
this.refUtils = refUtils;
}
//RefUtil类中
public class RefUtil {
//此name表示想要创建其他对象实例中bean标签的id
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public IOCFactory(){
//解析Xml文件,需要第三方插件
SAXReader reader=new SAXReader();
InputStream url=BeanUtil.class.getClassLoader().getResourceAsStream("conf.xml");
try {
Document doc=reader.read(url);
//得到根元素也就是beans
Element rootElement = doc.getRootElement();
//根据bean找到配置文件中根标签底下标签为bean的所有元素
List<Element> beans = rootElement.elements("bean");
for(Element bean:beans){
BeanUtil beanUtil=new BeanUtil();
//根据bean标签中属性id拿到id所对应的值
beanUtil.setId(bean.attributeValue("id"));
//根据bean标签中属性name拿到对应的值
beanUtil.setClassname(bean.attributeValue("name"));
//******************************
//在bean标签中找到所有的ref标签
List<Element> refs = bean.elements("ref");
List<RefUtil> refUtils=new ArrayList<>();
//存在其他类对象,则进入for循环
for (Element ref:refs){
RefUtil refUtil=new RefUtil();
//把ref标签中name属性值放在RefUtil的属性name中
refUtil.setName(ref.attributeValue("name"));
refUtils.add(refUtil);
}
//把refUtils添加完集合放在BeanUtil中属性refUtils中
beanUtil.setRefUtils(refUtils);
//*******************************
//创建一个List集合来存放property标签中的属性,并把这些属性放到bean中
List<PropertyUtil> propertyUtils=new ArrayList<>();
//得到elements为property的所有信息
List<Element> pros=bean.elements("property");
for (Element pro:pros){
PropertyUtil propertyUtil=new PropertyUtil();
//根据property标签中name,value属性获取所对应的值
propertyUtil.setName(pro.attributeValue("name"));
propertyUtil.setValue(pro.attributeValue("value"));
propertyUtils.add(propertyUtil);
}
beanUtil.setPropertyUtils(propertyUtils);
//把此时根据bean标签中的内容读取到的值拿到集合中
beanUtils.add(beanUtil);
}
} catch (Exception e) {
e.printStackTrace();
}
}
接下来要对getBean()方法中代码进行修改
public Object getBean(String id){
Object target=null;
//判断beanUtils是否包含bean标签
if(beanUtils.size()>0){
for (BeanUtil bean:beanUtils){
//判断是否存在该id
if(bean.getId().equals(id)){
try {
//根据name获得class对象
Class cla=Class.forName(bean.getClassname());
//根据cla创建一个无参实例,本案例中代表Student对象
target=cla.newInstance();
//获得对象要给此对象的属性进行赋值
List<PropertyUtil> propertyUtils = bean.getPropertyUtils();
for (PropertyUtil propertyUtil:propertyUtils){
//获得PropertyUtil类中的name属性,也就是标签property中的name的值
String name=propertyUtil.getName();
//获得标签中value值
String value=propertyUtil.getValue();
//构造方法两个参数,第一个代表属性名,第二个表示Class对象,此案例表示Student的class对象
PropertyDescriptor propertyDescriptor=new PropertyDescriptor(name,cla);
//这句话表示给target对象调用了关于属性名为name的set方法,并把此时的value值传进去
propertyDescriptor.getWriteMethod().invoke(target,value);
}
//********************************
//获得RefUtil集合中的name属性
List<RefUtil> refUtils=bean.getRefUtils();
//表示此时没有引用数据类型
if(refUtils!=null){
//表示集合中有数据
for(RefUtil refUtil:refUtils){
String name=refUtil.getName();
//此时采用递归的办法调用getBean(),返回该类的实例对象,并把该实例对象添加到target对象中
Object obj=this.getBean(name);
//构造方法两个参数,第一个代表属性名,第二个表示Class对象,此案例表示Student的class对象
PropertyDescriptor propertyDescriptor=new PropertyDescriptor(name,cla);
//这句话表示给target对象调用了关于属性名为name的set方法,并把此时的value值传进去
propertyDescriptor.getWriteMethod().invoke(target,obj);
//********************************
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
return target;
}
测试
public static void main(String[] args) {
IOCFactory iocFactory=new IOCFactory();
Student stu=(Student)iocFactory.getBean("stu");
System.out.println(stu);//Student{user='et2201', pwd='gt', school=School{name='etoak'}}
}
这样我们就可以根据配置文件,来创建对象,而不用自己手动new