欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring模拟——BeanFactory 博客分类: JavaEE springBeanFactoryIOC 

程序员文章站 2024-02-06 19:30:16
...

续上篇,在解决完配置文件的解析之后,写了一个简单addUser模块准备测试

model代码:

package com.l.model;

public class User {
	
	private String name;
	private String password;
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
}

 DAO(接口代码未贴出)

package com.l.impl;

import com.l.dao.UserDAO;
import com.l.model.User;

public class UserDAOImpl implements UserDAO {

	@Override
	public void save(User u) {
		System.out.println("Success!");
	}

}

UserService代码:

 

package com.l.service;

import com.l.dao.UserDAO;
import com.l.model.User;

public class UserService {
	        private UserDAO dao;//标红
		public UserDAO getUserDAO() {
			return dao;
		}
		public void setUserDAO(UserDAO dao) {
			this.dao = dao;
		}
		public void add(User user) {
			dao.save(user);
		}

}
 

 

 下面进行测试:

package com.l.service;

import java.io.IOException;

import org.junit.Test;

import com.l.impl.UserDAOImpl;
import com.l.model.User;

public class UserServiceTset {
	@Test
	public void addTest() throws IOException, Exception{	
		UserService service = new UserService();
		User u = new User();
		service.add(u);
	}
}

 当你测试完,会报一个空指针错误,这是因为UserService中没有new一个UserDAO对象,这就是spring的好处,不用自己进行手动创建对象。是怎么实现的呢?

在spring中有这样一个配置文件,叫beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans>
	<bean id="u" class="com.l.impl.UserDAO">
        </bean>
</beans>

 使用上篇的方法对其进行解析

package com.l.spring;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.input.SAXBuilder;

public class ClassPathXMLApplicationContext implements BeanFactory{
	
	private Map<String, Object> beans = new HashMap<String, Object>();
	
	
	public ClassPathXMLApplicationContext() throws Exception, IOException{
		SAXBuilder builder = new SAXBuilder();
		Document doc = builder.build(this.getClass()
				.getClassLoader().getResourceAsStream("beans.xml"));
		Element root = doc.getRootElement();
		List<Element> elements = root.getChildren("bean");
		
		for (int i = 0; i < elements.size(); i++) {
			Element element = elements.get(i);
			
			String id = element.getAttributeValue("id");
			String clazz = element.getAttributeValue("class");//获取UserDAO的类名
			System.out.println(id + " : " + clazz);
			
			Object o = Class.forName(clazz).newInstance();//为UserDAO创建一个对象
			
			beans.put(id, o);
		}
		
	}
	@Override
        //通过getBean获取为UserDAO创建的对象
	public Object getBean(String id) {
		return beans.get(id);
	}
	
}

通过解析beans.xml中的类名,为其创建对象,实现BeanFactory中的getBea()方法,让外界获取该对象

BeanFactory接口:

package com.l.spring;

public interface BeanFactory {
	public Object getBean(String name);
}

  再次对其进行测试:

package com.l.service;

import java.io.IOException;

import org.junit.Test;

import com.l.impl.UserDAOImpl;
import com.l.model.User;
import com.l.spring.BeanFactory;
import com.l.spring.ClassPathXMLApplicationContext;

public class UserServiceTset {
	@Test
	public void addTest() throws IOException, Exception{
		BeanFactory factory = new ClassPathXMLApplicationContext();
		
		UserService service = new UserService();
		UserDAO userDAO = (UserDAO) factory.getBean("u");

		service.setUserDao(userDAO);
		User u = new User();
		u.setName("nimA");
		u.setPassword("heh");
		service.add(u);
	}
}

 通过测试

 

通过BeanFactory来实例化,管理对象,使用它的实现类ClassPathXmlApplicationContext来新建对象,将配置文件中对应的id和对象放入Map中。

 

再想一下,既然UserDAO可以这样来实现,那么UserService也是可以的:

在beans.xml中加入再添加一个bean标签<bean id="userService" class="com.l.service.UserService">

测试代码:

 

package com.l.service;

import java.io.IOException;

import org.junit.Test;

import com.l.impl.UserDAOImpl;
import com.l.model.User;
import com.l.spring.BeanFactory;
import com.l.spring.ClassPathXMLApplicationContext;

public class UserServiceTset {
	@Test
	public void addTest() throws IOException, Exception{
		BeanFactory factory = new ClassPathXMLApplicationContext();
		
                UserDAO userDAO = (UserDAO) factory.getBean("u");
		UserService service = (UserService)factory.getBean("userService");//标红
		service.setUserDao(userDAO);
		User u = new User();

		service.add(u);
	}
}
代码中标红部分, 分两次调用了getBean方法,然而却是没有这个必要的。在bean.xml中<bean>下添加一个子标签<property>

 

 

<?xml version="1.0" encoding="UTF-8"?>
<beans>
	<bean id="u" class="com.l.impl.UserDAOImpl"/>
	<bean id="userService" class="com.l.service.UserService">
		<property name="userDAO" bean="u"/>
	</bean>
</beans>
 property是告诉你,“userService”中有一个setUserDAO的方法,当调用该方法时,将后面指定的bean传进去,这种方法叫做注入:

 

注入代码:

 

List<Element> property = element.getChildren("property");
			for(Element propertyElement : property) {
		    	   String name = propertyElement.getAttributeValue("name"); //userDAO
		    	   String bean = propertyElement.getAttributeValue("bean"); //u
		    	   Object beanObject = beans.get(bean);//UserDAOImpl instance
		    	   
		    	   String methodName = "set" + name.substring(0, 1).toUpperCase() + name.substring(1);
		
		    	   Method m = o.getClass().getMethod(methodName, beanObject.getClass().getInterfaces()[0]);
		    	  // System.out.println(m.getName());
		    	   m.invoke(o, beanObject);
		       }
 将这段代码加到解析bean.xml的java文件的for循环中,此处用到的是反射机制,通过解析配置文件,Map中存有<"u", 相应对象><"userService", 相应对象>,配置文件中第一个<bean>标签下没有<property>,循环至第二个,即"userService" 取出”userService“中的setUserDAO方法,最后通过invoke(obj,args)实现注入,参数obj为调用该方法的对象(此处为o),参数args为取出方法的参数setUserDAO的参数为为一个UserDAO对象,而beanObject就是该类型。

 

test代码:

 

package com.l.service;

import java.io.IOException;

import org.junit.Test;

import com.l.impl.UserDAOImpl;
import com.l.model.User;
import com.l.spring.BeanFactory;
import com.l.spring.ClassPathXMLApplicationContext;

public class UserServiceTset {
	@Test
	public void addTest() throws IOException, Exception{
		BeanFactory factory = new ClassPathXMLApplicationContext();
		
		UserService service = (UserService)factory.getBean("userService");

		User u = new User();
		service.add(u);
	}
}
 

 测试通过,从原理上了解IOC更好的开始学习spring