`
喻红叶
  • 浏览: 41100 次
  • 性别: Icon_minigender_1
  • 来自: 哈尔滨
社区版块
存档分类
最新评论

Spring模拟(仅供个人参考)

 
阅读更多

      通过一个小例子还模拟Spring的执行过程,由于还没有接触过Spring,所以仅仅是模拟,不敢说是原理,也仅仅是供自己理解。这是第一版,等接触过Spring之后,会对这篇文章进行修改,我还会回来的!

 一 添加用户

     假设有这样的一个需求,在系统中添加一个用户。首先我们需要创建一个用户类:

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;
	}
}

 

添加操作由UserService类来完成:

public class UserService {
    public void add(User user) {
        将user保存到数据库;
    }
}

 

为了代码的灵活,应该将数据库操作由一个单独的类来完成;为了代码的灵活性,以适应不同的数据库类型(如mysql,oracle),所以数据库操作写成接口:

public interface UserDAO {
      public void save(User user);
}
public class SubUserDAO implements UserDAO {
      public void save(User user) {
            将user保存到数据库中;
      }
}

 
这个时候,UserService就应该是调用UserDAO的save()方法,所以UserService改写成:

public class UserService {
	private UserDAO userDAO = new SubUserDAO();
	public void add(User user) {
		userDAO.save(user);
	}

	public UserDAO getUseDAO() {
		return userDAO;
	}

	public void setUserDAO(UserDAO userDAO) {
		this.userDAO = userDAO;
	}
}

 
    至此,添加用户的功能就完成了,我们使用了分层的思想,保证了代码的灵活性。


二  模拟Spring操作

但是在上面的代码中,如果用调用UserService去添加user,需要构造出UserDAO的一个实例,这样就把代码写死了。 如果我们能把生成UserService类交由一个工厂类去实现,工厂类在构造UserDAO的实例时,不是把代码写死,而是通过去读配置文件。那么这将极大的提高程序的灵活性!当我们的需求发生改变时,只需要修改配置文件中的内容。配置文件的内容如下:

<beans>
	<bean id="user" class="com.cxy.dao.SubUserDAO" />
	<bean id="userService" class="com.cxy.service.UserService" >
		<property name="userDAO" bean="user"/>
	</bean>
	
</beans>

 
在Spring中,这是通过IOC来完成的,我还不是很确切的了解IOC。我首先概要性的阐述模拟Spring的思想:


先说如果要构造一个UserSerice对象需要完成的工作:

1)构造出UserDAO的具体实例,UserDAO dao = new SubUserDAO();

2)  构造UserService的对象,service = new UserService();

3) 调用service.setUserDAO(dao);


通过配置文件来如何完成呢:

1)通过jdom或dom4j去读配置文件中的内容,获得每个的id和class属性;

2)class属性是一个类的全额限定名,通过反射机制,可以构造出对应类的实例object;

3)将该类放到一个map中,map.put(id,object);对应上面的配置文件,第一个生成一个SubUserDAO的对象,dao;第二个生成UserService的对象service;

4) 如果下面还有,获得其name和bean属性;通过name可以拼凑出setUserDAO(),bean对应的是要传递过去的参数dao-map.get(&quot;user&quot;);

5)通过反射机制获得setUserDAO()对应的Method对象method,method.invoke(service,dao);

搞定!!!

下面是代码的实现:

//定义工厂接口
public interface BeanFactory {
     public Object getBean(String id);
}

具体的实现类:

public class ClassPathXmlApplicationContext implements BeanFactory {

private Map beans = new HashMap();


//IOC Inverse of Control DI Dependency Injection
public ClassPathXmlApplicationContext() throws Exception {
/*       
这段程序的执行过程是这样的:
1)获得包含的list,应该包含两个元素;
2)遍历list,分别取出id和class,通过反射机制生成class对应的实体类的对象,bean.put(id,object)
3)在上面遍历list,生成对象,放进map之后,遍历该下面的,取出name和bean,
  其中name表示要执行的方法名称,bean该方法的参数
4)拼凑出该方法的名称,通过反射获得该方法对应的Method对象,执行之
*/

    List list = 获得每个;
    //遍历
    for(int i=0;i对应SubUserDAO,第二个对应UserService;

       //把New出来的类放进beans中
       beans.put(id, object);
       
       //如果下面有property属性的话
       for(Element propertyElement : (List)element.getChildren(&quot;property&quot;)) {
       获得name;
       获得bean;
   //SubUserDAO instance
       Object beanObject = beans.get(bean);
       
       //拼凑出setUserDAO()
       String methodName = &quot;set&quot; + name.substring(0, 1).toUpperCase() + name.substring(1);
       
       //通过反射获得该方法对应的Method对象
       Method m = object.getClass().getMethod(methodName, beanObject.getClass().getInterfaces()[0]);
       m.invoke(object, beanObject);
       }
       
       
    }  
  
}

public Object getBean(String id) {
return beans.get(id);
}
}

 
在客户端通过如下代码就可以获得UserService的实例:

BeanFactory factory = new ClassPathXmlApplicationContext();
UserService service = (UserService) factory.getBean("userService");
service.add(new User());

这就是传说中的依赖注入:依赖配置文件;通过反射机制构造出对象,注入到容器(map)中。


第一版就此结束,感觉小有收获吧。期待第二版急需完善。

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics