一小段时间没有使用spring,对spring一些基础要点都开始遗忘了,所以趁着现在比较有时间,来模拟一个spring的一小块功能:ioc,毕竟,好记性不如烂笔头,这样能够加深自己对spring的理解。
在此先附上一份demo,作为环境。
项目结构
package entity;
public class Product {
private int pId;
private String pName;
private String Paddress;
public int getpId() {
return pId;
}
public void setpId(int pId) {
this.pId = pId;
}
public String getpName() {
return pName;
}
public void setpName(String pName) {
this.pName = pName;
}
public String getPaddress() {
return Paddress;
}
public void setPaddress(String paddress) {
Paddress = paddress;
}
}
package Dao;
import entity.Product;
public class ProductDaoImpl implements ProductDao {
@Override
public void add(Product p) {
System.out.println("sava success");
System.out.println(p.getpName());
}
}
package Service;
import Dao.ProductDao;
import Dao.ProductDaoImpl;
import entity.Product;
public class ProductServiceImpl implements ProductService {
ProductDao pd=new ProductDaoImpl();
@Override
public void add(Product p) {
pd.add(p);
}
}
package test;
import org.junit.Before;
import org.junit.Test;
import Service.ProductService;
import Service.ProductServiceImpl;
import entity.Product;
public class ProductTest {
Product product = null;
@Before
public void bef() {
product = new Product();
product.setpId(1);
product.setPaddress("school");
product.setpName("phone");
}
@Test
public void testProduct() {
ProductService ps = new ProductServiceImpl();
ps.add(product);
}
}
运行junit单元测试,控制台打印如下所示:
sava success
phone
以上是,我们是手动new对象,手动管理这些对象。
现在,我们来设计一个能够实现类似spring的iop的类,让它为我们创建对象,当程序中需要使用到这个对象,则自动住入到需要该对象的地方。
设计思路:让它创建什么类的对象? 它如何将对象注入到我们引用该对象的地方?
主要技术支持:java的反射机制,xml 的dom操作。
在这里我使用的是dom4j-1.6.1.jar这个包的SAXReader类。就是用来创建解析器对象的,解析的方法很多,目前,我就用过了这种,所以呢,在这我就使用的是这种方法。
bean.xml
<beans>
<bean id="productDao" class="Dao.ProductDaoImpl" />
<bean id="productService" class="Service.ProductServiceImpl">
<property name="productDao" bean="productDao" />
</bean>
</beans>
ClassPathXmlApplicationContext.java
package Factory;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
public class ClassPathXmlApplicationContext implements Beanfactory {
private Map<String, Object> beans = new HashMap<String, Object>();
// 构造函数
public ClassPathXmlApplicationContext() {
try {
// 1创建解析器对象
SAXReader saxReader = new SAXReader();
// 使用解析器加载bean.xml文件得到document对象
Document document = saxReader.read("src/bean.xml");
// 获得根元素的节点
Element root = document.getRootElement();
// 根据元素获取所有bean元素
List beanElements = root.elements("bean");
//遍历所有的bean元素
for (int i = 0; i < beanElements.size(); i++) {
//获取第i个bean
Element beanElement = (Element) beanElements.get(i);
//获取bean对象的id属性的值
String id = beanElement.attributeValue("id");
//获取class属性的值
String classPath = beanElement.attributeValue("class");
//输出便于分析调试
System.out.println(id);
System.out.println(classPath);
//使用反射创建(classPath这个字符串对应值的类)的对象
Object o = Class.forName(classPath).newInstance();
//将这个对象添加到这个map中
beans.put(id, o);
//获得这个bean依赖的对象,接下来的方法一样,不注释了
List propertyElements = beanElement.elements("property");
for (Element propertyElement : (List<Element>) propertyElements) {
String name = propertyElement.attributeValue("name");
String bean = propertyElement.attributeValue("bean");
System.out.println(name);
System.out.println(bean);
Object beanObject = beans.get(bean);
//下面就是构造出ProductServiceImpl类中方法的方法名,此例子为setProductDao
String methodName = "set" + name.substring(0, 1).toUpperCase() + name.substring(1);
System.out.println("method name = " + methodName);
//获得ProductServiceImpl类中的setProductDao()方法的方法对象
Method m = o.getClass().getMethod(methodName, beanObject.getClass().getInterfaces()[0]);
//使用反射执行该方法,也就是注入依赖的对象,此例子为productDao
m.invoke(o, beanObject);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 对外开放一个方法,使得外界能够根据需要直接拿到这个beans这个map中bean。
*/
@Override
public Object getBean(String id) {
return beans.get(id);
}
}
ProductServiceImpl.java
package Service;
import Dao.ProductDao;
import entity.Product;
public class ProductServiceImpl implements ProductService {
private ProductDao productDao;
@Override
public void add(Product p) {
productDao.add(p);
}
public void setProductDao(ProductDao pd) {
this.productDao = pd;
}
}
ProductDaoImpl.java
package Dao;
import entity.Product;
public class ProductDaoImpl implements ProductDao {
@Override
public void add(Product p) {
System.out.println("sava success");
System.out.println(p.getpName());
}
}
testSpring.java
package test;
import org.junit.Test;
import Factory.ClassPathXmlApplicationContext;
import Service.ProductService;
import entity.Product;
public class testSpring {
@Test
public void Test(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext();
ProductService ps =(ProductService) context.getBean("productService");
Product product = new Product();
product.setpId(1);
product.setPaddress("school");
product.setpName("phone");
ps.add(product);
}
}
控制台输出:
productDao
Dao.ProductDaoImpl
productService
Service.ProductServiceImpl
productDao
productDao
method name = setProductDao
sava success
phone
输出结果与预计一致,在这只是模拟spring的ioc,依赖注入,所以灵活性还是不好,但是基本理念是体现出来了。
麻雀虽小,五腑俱全
接下来有相关的东西继续更新中,喜欢的朋友可以关注下。