您的位置:首页 > 编程语言 > Java开发

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

2015-02-03 18:57 393 查看
本文实现了对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();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: