spring 依赖注入xml配置原理解析

3 篇文章 0 订阅
3 篇文章 0 订阅

本文实现了对spring的xml配置依赖注入的功能,也许并不是跟spring的实现一模一样,但是原理大致相同,本文旨在提供一种思路.....

1.添加相应的依赖包:

        <dependency>
  		<groupId>dom4j</groupId>
		<artifactId>dom4j</artifactId>
		<version>1.6.1</version>
  	</dependency>
  	<dependency>
  		<groupId>jaxen</groupId>
		<artifactId>jaxen</artifactId>
		<version>1.1.1</version>
  	</dependency><dependency>
	  	<groupId>log4j</groupId>
		<artifactId>log4j</artifactId>
		<version>1.2.16</version>
  	</dependency>
  	<dependency>
  		<groupId>junit</groupId>
  		<artifactId>junit</artifactId>
  		<version>4.11</version>
  	</dependency>


2.使用dom4j解析xml文档,通过反射获取相应的实例

public class Dom4jUtil {
	
	//单例
	private static final Dom4jUtil util = new Dom4jUtil();
	
	private SAXReader reader;
	
	private Document document;
	
	
	
	private Dom4jUtil(){
		reader = new SAXReader();
	}
	
	public static Dom4jUtil getInstance(){
		return util;
	}
	
	
	//保存bean的id和class,id为key,value为反射获得的实例
	private Map<String,Object> beans = new HashMap<String,Object>();
	
	//保存bean的id和其需要注入的property的name和ref,id为外层map的key,name和ref分别为内层map的key,value
	private Map<String,Map<String,String>> propertys = new HashMap<String,Map<String,String>>();
	
	/**
	 * 根据路径获取document对象
	 * @param xmlPath
	 * @return
	 * @throws DocumentException
	 */
	public Map<String,Object> parseXml(String xmlPath) throws DocumentException{
		document = reader.read(new File(xmlPath));
		this.parseBean(document);
		return this.getBeansMap(document);
	}
	
	/**
	 * 解析xml文档中的bean节点
	 * @param document
	 */
	@SuppressWarnings("unchecked")
	public void parseBean(Document document){
		if(document==null){
			return;
		}
		//获取根元素beans
		Element ele = document.getRootElement();
		//使用xpath表达式查找所有的bean节点
		List<Element> beanElements = ele.selectNodes("//beans/bean");
		//保存bean里面的property节点
		List<Element> propElements = null;
		//保存property的name和ref,name为key,ref为value
		Map<String,String> props = null;
		//保存bean的id属性
		String id = null;
		//保存bean的class属性
		String classpath = null;
		//获取的class
		Class<?> clz = null;
		for(Element beanElement:beanElements){
			id = beanElement.attributeValue("id");
			classpath = beanElement.attributeValue("class");
			if(classpath==null||"".equals(classpath)){
				throw new RuntimeException("The class attribute must be not null or ''");
			}
			//如果没写id属性,默认id就是类名小写
			if(id==null||"".equals(id)){
				//截取类名
				id = classpath.substring(classpath.lastIndexOf(".")+1);
				//类名首字母小写
				id = id.replace(id.charAt(0), Character.toLowerCase(id.charAt(0)));
			}
			try {
				clz = Class.forName(classpath);
			} catch (ClassNotFoundException e) {
				throw new RuntimeException("The class "+classpath+ " is not found");
			}
				id = classpath.substring(classpath.lastIndexOf(".")+1);
				//类名首字母小写
				id = id.replace(id.charAt(0), Character.toLowerCase(id.charAt(0)));
			}
			try {
				clz = Class.forName(classpath);
			} catch (ClassNotFoundException e) {
				throw new RuntimeException("The class "+classpath+ " is not found");
			}
			//判断该类是否已经被实例化
			if(beans.containsKey(id)){
				throw new RuntimeException("The class "+classpath+ " has already been instantiated");
			};
			try {
				//将bean进行保存
				beans.put(id, clz.newInstance());
			} catch (InstantiationException e) {
				throw new RuntimeException("The class "+classpath+" must be have default constructor");
			} catch (IllegalAccessException e) {
				throw new RuntimeException("The class "+classpath+" must be have default constructor");
			}
			//查找某个bean节点下的所有property节点
			propElements = beanElement.selectNodes("property");
			props = new HashMap<String,String>();
			for(Element propElement:propElements){
				props.put(propElement.attributeValue("name"), propElement.attributeValue("ref"));
			}
			//判断某个bean下是否有property,有就加到propertys里面
			if(!props.isEmpty()){				
				propertys.put(id, props);
			}
		}
	}
	
	//注入bean,在调用改方法前需调用上面parseBean方法完成文档的解析
	public Map<String,Object> getBeansMap(Document document){
		if(beans==null){
			return null;
		}
		//如果propertys为空,说明没有属性要注入,直接返回beans
		if(propertys.isEmpty()){
			return beans;
		}
		//迭代解析好的bean(这些bean还没有完成属性注入)
		Set<String>  idSet = propertys.keySet();
		for(String id:idSet){
			Object obj = this.injectProperty(id);
			//将注入好的bean重新放到beans里面
			beans.put(id, obj);
		} 
		return beans;
	} 
	
	//注入bean的属性
	private Object injectProperty(String id){
		Map<String,String> props = null;
		Set<String> names = null;
		props = propertys.get(id);
		//迭代某个bean的property节点
		names = props.keySet();
		Object obj = beans.get(id);
		try {
			//name为property节点的name属性,props.get(name)为property节点的ref属性
			for(String name:names){
				//获取bean的所有属性描述
				PropertyDescriptor[] pds = Introspector.getBeanInfo(obj.getClass()).getPropertyDescriptors();
				for(PropertyDescriptor pd:pds){
					Method method = pd.getWriteMethod();
					if(method!=null){
						//判断变量名称是否和bean需要注入的name属性值是否一样
						if(!pd.getName().equals(name)){
							throw new RuntimeException("the class "+obj.getClass().getName()+" does not have such property '"+name+"'");
						}
						//判断变量的类型和注入的类型是否有父子关系
						if(!pd.getPropertyType().isAssignableFrom(beans.get(props.get(name)).getClass())){
							throw new RuntimeException("the class "+obj.getClass().getName()+" can not be cast to "+pd.getPropertyType().getName()+"");
						};
						method.invoke(obj, beans.get(props.get(name)));
					}
				}
			}
		} catch (IntrospectionException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
		return obj;
	} 
}
3.需注入的dao,service

public interface IUserDao {
	void addUser();
}

public class UserDao implements IUserDao{

	@Override
	public void addUser() {
		System.out.println("进行了新增操作");
	}

}


public interface IUserService {
	void addUser();
}

public class UserService implements IUserService{
	
	private IUserDao userDao;
	
    //添加set方法进行注入
	public void setUserDao(IUserDao userDao) {
		this.userDao = userDao;
	}

	@Override
	public void addUser() {
		userDao.addUser();
	}
}


4.配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans>
	<bean class="cn.edu.hbut.zw.spring.dao.impl.UserDao"></bean>
	<bean class="cn.edu.hbut.zw.spring.service.impl.UserService">
		<property name="userDao" ref="userDao"/>
	</bean>
</beans>


5.测试

public class SpringTest {
	@Test
	public void testXml(){
		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
		IUserService us = (IUserService) context.getBean("userService");
		us.addUser();
	}
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值