一、准备类
public interface UserDao {
public void findName();
}
public class UserDaoImpl implements UserDao{
@Override
public void findName() {
System.out.println("我是dao实现类1");
}
}
public class UserDaoImpl2 implements UserDao{
@Override
public void findName() {
System.out.println("我是dao实现类2");
}
}
public interface UserService {
public void findAge();
}
public class UserServiceImpl implements UserService {
UserDao dao;
@Override
public void findAge() {
System.out.println("我是service的实现类");
dao.findName();
}
public void setDao(UserDao dao) {
this.dao = dao;
}
}
二、实现方法
public class BeanFactory {
Map<String,Object> map = new HashMap<String,Object>();
public BeanFactory(String xml){
parseXml(xml);
}
public void parseXml(String xml) throws CjxSpringException{
File file = new File(this.getClass().getResource("/").getPath()+"//"+xml);
SAXReader reader = new SAXReader();
try {
Document document = reader.read(file);
Element elementRoot = document.getRootElement();
Attribute attribute = elementRoot.attribute("default");
boolean flag=false;
if (attribute!=null){
flag=true;
}
for (Iterator<Element> itFirlst = elementRoot.elementIterator(); itFirlst.hasNext();) {
/**
* setup1、实例化对象
*/
Element elementFirstChil = itFirlst.next();
Attribute attributeId = elementFirstChil.attribute("id");
String beanName = attributeId.getValue();
Attribute attributeClass = elementFirstChil.attribute("class");
String clazzName = attributeClass.getValue();
Class clazz = Class.forName(clazzName);
/**
* 维护依赖关系
* 看这个对象有没有依赖(判断是否有property。或者判断类是否有属性)
* 如果有则注入
*/
Object object = null;
for (Iterator<Element> itSecond = elementFirstChil.elementIterator(); itSecond.hasNext();){
// 得到ref的value,通过value得到对象(map)
// 得到name的值,然后根据值获取一个Filed的对象
//通过field的set方法set那个对象
//<property name="dao" ref="dao"></property>
Element elementSecondChil = itSecond.next();
if(elementSecondChil.getName().equals("property")){
//由于是setter,沒有特殊的构造方法
object= clazz.newInstance();
String refVlaue = elementSecondChil.attribute("ref").getValue();
Object injetObject= map.get(refVlaue) ;
String nameVlaue = elementSecondChil.attribute("name").getValue();
Field field = clazz.getDeclaredField(nameVlaue);
field.setAccessible(true);
field.set(object,injetObject);
}else{
//證明有特殊構造
String refVlaue = elementSecondChil.attribute("ref").getValue();
Object injetObject= map.get(refVlaue) ;
Class injectObjectClazz = injetObject.getClass();
Constructor constructor = clazz.getConstructor(injectObjectClazz.getInterfaces()[0]);
object = constructor.newInstance(injetObject);
}
}
if(object==null) {
if (flag) {
if (attribute.getValue().equals("byType")) {
//判斷是否有依賴
Field fields[] = clazz.getDeclaredFields();
for (Field field : fields) {
//得到屬性的類型,比如String aa那麽這裏的field.getType()=String.class
Class injectObjectClazz = field.getType();
/**
* 由于是bytype 所以需要遍历map当中的所有对象
* 判断对象的类型是不是和这个injectObjectClazz相同
*/
int count = 0;
Object injectObject = null;
for (String key : map.keySet()) {
Class temp = map.get(key).getClass().getInterfaces()[0];
if (temp.getName().equals(injectObjectClazz.getName())) {
injectObject = map.get(key);
//记录找到一个,因为可能找到多个count
count++;
}
}
if (count > 1) {
throw new CjxSpringException("需要一个对象,但是找到了两个对象");
} else {
object = clazz.newInstance();
field.setAccessible(true);
field.set(object, injectObject);
}
}
}
}
}
if(object==null){//沒有子标签
object = clazz.newInstance();
}
map.put(beanName,object);
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(map);
}
public Object getBean(String beanName){
return map.get(beanName);
}
}
三、配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<beans default="byType">
<bean id="dao" class="com.cjx.spring.dao.UserDaoImpl"></bean>
<bean id="service" class="com.cjx.spring.service.UserServiceImpl">
</bean>
</beans>
四、总结
代码的逻辑是,获取根节点并判断是否配置的byType,如果配置了byType,开启byType自动注入。遍历根节点下的所有二级标签,这里的二级标签为bean,下面就用bean标签来替换二级标签,比较容易理解。拿到第一个bean标签,就可以拿到标签配置的id和class的属性值,紧接着判断是否配置的property或者constructor标签,如果配置了就获取标签的name和ref属性,实例化该bean对象,并通过ref属性从ioc容器中获取要注入的对象,并通过反射的形式将对象注入。如果这个bean没有配置property或者constructor标签,但是开启了byType,就获取该bean中所有的属性,遍历判断容器中有多少个该属性的实现类,如果有多个抛出一样,如果为1个,就自动注入。(代码没有判断为0的情况,如果为0,可以提示该属性的实现类找不到)。整套逻辑也是和spring一样,手动配置优先于自动配置,如果在bean标签配置了property或者构造注入的,优先于自动配置的。