作为一个学习JAVA只有4个月的同学,我能深切的理解初次接触Spring框架产生的困惑,也同样有探索SpringIOC容器的实现方式的冲动。我觉得IOC的那种将控制转交给容器的方式,配合上java接口,简直是太完美了,能有效的实现对象之间的解耦。于是,我经过自己的努力,自己写了一个IOC容器。
这个容器是模仿SpringIOC容器写的,操作什么的都非常的相似。同样是通过读取配置文件中的内容来实现注入的。解析配置的XML文件是采用SAX方式,实现注入是采用反射技术。以下是所有的代码:
首先,我建立3个接口,分别控制容器,bean元素,property元素
容器:
import java.util.List;
/**
* IOC容器接口
* */
public interface IocContainer {
/**
* 用于启动IOC容器,根据配置文件完成对容器中所有bean的注册
* */
public void startIocContainer(String config);
/**
* 用于根据bean对象的id获得IOC容器中的bean的class属性所指向的对象
* */
public Object beanToObject(String id);
}
Bean:
import org.dom4j.Element;
public interface IocBean {
/**
* 根据配置文件的bean元素为当前bean对象赋值
* */
public void configToBean(Element bean);
}
Property:
import org.dom4j.Element;
public interface IocProperty {
/**
* 根据配置文件的bean元素下的property元素为当前property对象赋值
* */
public void configToProperty(Element property);
}
然后,根据这三个接口写出对应的三个实现类,其中容器的实现类较为复杂,Object beanToObject方法用到了反射。
容器:
import interfaceIOC.IocContainer;
import java.io.File;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import testEntity.Dao;
public class WizardIocContainer implements IocContainer {
private Map<String,WizardIocBean> beanMap;
/**
* @param config 需要传入配置文件的绝对路径
* */
public void startIocContainer(String config) {
//访问配置文件
File file=new File(config);
//用SAX方式解析XML配置文件
SAXReader reader=new SAXReader();
try {
Document doc=reader.read(file);
Element root=doc.getRootElement();
List<Element> eles=root.elements("bean");
//对所有bean元素进行遍历,保存其id属性值到beanMap中
//System.out.println(eles.size());
Map<String,WizardIocBean> bMap=new HashMap<String,WizardIocBean>();
for(Element ele:eles){
WizardIocBean bean=new WizardIocBean();
bean.configToBean(ele);
bMap.put(bean.getId(),bean);
}
beanMap=bMap;
} catch (DocumentException e) {
e.printStackTrace();
}
}
public Object beanToObject(String id){
if(beanMap==null){
System.out.println("请先启动Ioc容器");
return null;
}else{
//根据id获得bean对象
WizardIocBean bean=beanMap.get(id);
//获得class属性中类名
String className=bean.getClassName();
//利用反射动态生成对象
try{
Class cls=Class.forName(className);
Object obj=cls.newInstance();
//为对象注入property中的值
//获取该bean中的说有property内容
Map<String,WizardIocProperty> propertyMap=bean.getPropertyMap();
//若没有property内容,直接返回obj
if(propertyMap==null){
return obj;
}
//对其进行遍历
Set<String> propertyNames=propertyMap.keySet();
for(String propertyName:propertyNames){
//获取对应的property
WizardIocProperty property=propertyMap.get(propertyName);
//若ref为空,直接执行对应的set方法就可以完成对obj对象的注入
if(property.getRef()==null){
//获得要注入的值
String value=property.getValue();
//拼凑出对应set方法的方法名
String setName="set"+property.getName().toLowerCase()
.substring(0, 1).toUpperCase()+
property.getName()
.toLowerCase().substring(1);
//System.out.println(setName);
//执行set方法,为对象赋值
try{
Method methodSet=cls.getMethod(setName, String.class);
methodSet.invoke(obj, property.getValue());
}catch(Exception e){
e.printStackTrace();
}
}else{
//获得ref中的值,这个值对应某一bean的id
String ref=property.getRef();
Class cls1=Class.forName(beanMap.get(ref).getClassName());
String setName1="set"+property.getName().toLowerCase()
.substring(0, 1).toUpperCase()+
property.getName()
.toLowerCase().substring(1);
try{
Class paramType=null;
Method[] methods=cls.getMethods();
for(Method m:methods){
//System.out.println(m.getName());
if(setName1.equals(m.getName())){
Class<?>[] paramTypes=m.getParameterTypes();
paramType=paramTypes[0];
Method methodSet=cls.getMethod(setName1,paramType);
Object obj1=cls1.newInstance();
methodSet.invoke(obj, obj1);
}
}
}catch(Exception e){
e.printStackTrace();
}
}
}
return obj;
}catch(Exception e){
e.printStackTrace();
return null;
}
}
}
Bean:
import interfaceIOC.IocBean;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.dom4j.Element;
public class WizardIocBean implements IocBean{
private String id;
private String className;
private Map<String,WizardIocProperty> propertyMap;
public void configToBean(Element bean) {
id=bean.attributeValue("id");
className=bean.attributeValue("class");
List<Element> eles=bean.elements("property");
Map<String,WizardIocProperty> pMap=new HashMap<String,WizardIocProperty>();
for(Element ele:eles){
WizardIocProperty property=new WizardIocProperty();
property.configToProperty(ele);
pMap.put(property.getName(), property);
}
propertyMap=pMap;
}
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 Map<String, WizardIocProperty> getPropertyMap() {
return propertyMap;
}
public void setPropertyMap(Map<String, WizardIocProperty> propertyMap) {
this.propertyMap = propertyMap;
}
}
Property:
import org.dom4j.Element;
import interfaceIOC.IocProperty;
public class WizardIocProperty implements IocProperty {
private String name;
private String value;
private String ref;
public void configToProperty(Element property) {
name=property.attributeValue("name");
value=property.attributeValue("value");
ref=property.attributeValue("ref");
}
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;
}
public String getRef() {
return ref;
}
public void setRef(String ref) {
this.ref = ref;
}
}
下面写配置文件,做一个测试
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<bean id="jdbcdao" class="testEntity.JdbcDao"></bean>
<bean id="myBatisdao" class="testEntity.MyBatisDao"></bean>
<bean id="testDao" class="testEntity.TestController">
<property name="where" value="这里"></property>
<property name="dao" ref="myBatisdao"></property>
</bean>
</beans>
测试类:
Dao接口:
public interface Dao {
public void excute();
}
JDBCDao实现类
public class JdbcDao implements Dao {
public void excute(){
System.out.println("JdbcDao方式");
}
}
MyBatisDao实现类
public class MyBatisDao implements Dao {
public void excute(){
System.out.println("MyBatisDao方式");
}
}
TestController(为其分别注入dao 和 where)
public class TestController {
private Dao dao;
private String where;
public Dao getDao() {
return dao;
}
public void setDao(Dao dao) {
this.dao = dao;
}
public String getWhere() {
return where;
}
public void setWhere(String where) {
this.where = where;
}
public void excute(){
System.out.println(where);
dao.excute();
}
}
最后测试:
public class TestWizardSet {
public static void main(String[] args) {
String config="src/WizardIocContainerConfig.xml";
WizardIocContainer wic=new WizardIocContainer();
wic.startIocContainer(config);
TestValue tv=(TestValue)wic.beanToObject("testValue");
tv.excute();
}
}
当在配置中为dao注入不同的类是,如注入jdbcDao则执行jdbcDao中的excute方法,注入mybatisDao这执行mybatisDao中的excute方法,这样就可以实现dao的解耦,在代码不变的情况下,执行不同的逻辑。