模拟Spring属性的注入

1、 创建场景代码,配置spring 属性注入

新建包dao ,创建接口 IPersonDao

/**

 * Huisou.com Inc.

 * Copyright (c) 2011-2012 All Rights Reserved.

 */

package com.chenzehe.spring.dao;

/**

 * @description

 * 

 * @author chenzehe

 * @email hljuczh@163.com

 * @create 2012-4-17 下午08:56:39

 */

public interface IPersonDao {

    void save();

}
 

创建IPersonDao 的实现类:

/**

 * Huisou.com Inc.

 * Copyright (c) 2011-2012 All Rights Reserved.

 */

package com.chenzehe.spring.dao.impl;

import com.chenzehe.spring.dao.IPersonDao;

/**

 * @description

 * 

 * @author chenzehe

 * @email hljuczh@163.com

 * @create 2012-4-17 下午08:57:33

 */

public class PersonDao implements IPersonDao {

    public void save() {

        System.out.println("PersonDao save()...");

    }

}
 

创建 Service包,新建接口 IHelloWorld

package com.chenzehe.spring.service;

public interface IHelloWorld {

    void sayHelloWorld();

    void save();

}
 

创建新接口的实现类Helloworld ,该类中有属性 IPerson 类型:

package com.chenzehe.spring.service.impl;

import com.chenzehe.spring.dao.IPersonDao;

import com.chenzehe.spring.service.IHelloWorld;

public class HelloWorldImpl implements IHelloWorld {

    private IPersonDao personDao;

    public void save() {

        personDao.save();

    }

    public HelloWorldImpl() {

        System.out.println("实例化!");

    }

    public void sayHelloWorld() {

        System.out.println("Hello World!");

    }

    public IPersonDao getPersonDao() {

        return this.personDao;

    }

    public void setPersonDao(IPersonDao personDao) {

        this.personDao = personDao;

    }

}
 

spring 配置文件 applicationContext.xml 中配置 benan

 

<bean id="personDao" class="com.chenzehe.spring.dao.impl.PersonDao" />

<bean id="helloWorld" class="com.chenzehe.spring.service.impl.HelloWorldImpl">

<property name="personDao" ref="personDao" />

</bean>
 

创建单元测试类HelloWorldTest

 

package com.chenzehe.spring.test.junit;

import org.junit.Test;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.chenzehe.spring.service.IHelloWorld;

public class HelloWorldTest {

    @Test
    public void instanceApplicationContext() {

        ApplicationContext cxt = new ClassPathXmlApplicationContext("applicationContext.xml");

        IHelloWorld helloWorld = (IHelloWorld) cxt.getBean("helloWorld");

        helloWorld.sayHelloWorld();

        helloWorld.save();

    }

}
 

2、定义 Bean 属性描述类 PropertyDefinition

/**

 * Huisou.com Inc.

 * Copyright (c) 2011-2012 All Rights Reserved.

 */

package com.chenzehe.spring.myspring;

/**

 * @description

 * 

 * @author chenzehe

 * @email hljuczh@163.com

 * @create 2012-4-17 下午08:39:22

 */

public class PropertyDefinition {

    private String name;

    private String ref;

    public PropertyDefinition() {
 
    }

    public PropertyDefinition(String name, String ref) {

        this.name = name;

        this.ref = ref;

    }

    public String getName() {

        return this.name;

    }

    public void setName(String name) {

        this.name = name;

    }

    public String getRef() {

        return this.ref;

    }

    public void setRef(String ref) {

        this.ref = ref;

    }

}
 

3 把该属性描述对象添加到 Bean 对象描述定义类 BeanDefinition 中,一个 Bean 可以有多个属性,所以对象属性为集合类型。

package com.chenzehe.spring.myspring;

import java.util.ArrayList;

import java.util.List;

public class BeanDefinition {

    private String id;

    private String className;

    private List<PropertyDefinition> propertys = new ArrayList<PropertyDefinition>();

    public BeanDefinition() {

    }

    public BeanDefinition(String id, String classPath) {

    this.id = id;

    this.className = classPath;

    }

    public String getId() {

        return id;

    }

    public void setId(String id) {

        this.id = id;

    }

    public String getClassName() {

        return className;

    }

    public void setClassName(String className) {

        this.className = className;

    }

    public List<PropertyDefinition> getPropertys() {

        return this.propertys;

    }

    public void setPropertys(List<PropertyDefinition> propertys) {

        this.propertys = propertys;

    }

}
 

4、 在原先代码 模拟spring 生成 bean 基础上增加注入功能

在解析xml 文件生成 bean 描述对象时解析描述描述对象,并添加到 bean 对象的 properys 属性中。然后再添加注入方法 injectObject()


package  com.chenzehe.spring.myspring;

import  java.beans.Introspector;

import  java.beans.PropertyDescriptor;

import  java.io.File;

import  java.lang.reflect.Method;

import  java.util.ArrayList;

import  java.util.HashMap;

import  java.util.List;

import  java.util.Map;

import  org.apache.commons.lang.StringUtils;

import  org.jsoup.Jsoup;

import  org.jsoup.nodes.Document;

import  org.jsoup.nodes.Element;

import  org.jsoup.select.Elements;

public   class  ClassPathXmlApplicationContext  {

    // 保存从配置文件中解析出来的bean属性

    private  List<BeanDefinition> beans =  new  ArrayList<BeanDefinition> () ;

    // 保存实例化好的bean

    private  Map<String, Object> beansClass =  new  HashMap<String, Object> () ;

    /**

     * 根据Bean名称取得Bean实例

    */

    public  Object getBean ( String name )   {

        return   beansClass .get ( name ) ;

    }

    /**

     * 传入配置文件初始化

     */

    public  ClassPathXmlApplicationContext ( String xmlFilePath )   {

        initBeansFromXML ( xmlFilePath ) ;

        initBeansClass () ;

        injectObject () ;

    }

    /**

     * 为Bean对象的属性注入值

     */

    private   void  injectObject ()   {

        // 循环所有bean

        for   ( BeanDefinition beanDefinition :  beans )   {

            Object bean =  beansClass .get ( beanDefinition.getId ()) ;

                if   ( bean !=  null )   {

        try   {

            PropertyDescriptor []  ps = Introspector. getBeanInfo ( bean.getClass ()) .getPropertyDescriptors () ;

           for   ( PropertyDefinition propertyDefinition : beanDefinition.getPropertys ())   {

            for   ( PropertyDescriptor propertyDescriptor : ps )   {

            if   ( propertyDefinition.getName () .equals (  propertyDescriptor.getName ()))   {

        Method setterMethod = propertyDescriptor.getWriteMethod () ; // 获取setter方法

        if   ( setterMethod !=  null )   {

            setterMethod.setAccessible ( true ) ;

            Object value =  beansClass .get ( propertyDefinition.getRef ()) ;

            setterMethod.invoke ( bean, value ) ; // 把引用对象注入到属性中

        }

        break ;

    }

}

}

}

catch   ( Exception e )   {

//  TODO : handle exception

}

}

}

}

/**

 * 从beans中读取Bean属性,使用反射实例化Bean对象

 */

private   void  initBeansClass ()   {

for   ( BeanDefinition bean :  beans )   {

if   ( StringUtils. isNotBlank ( bean.getClassName ()))   {

try   {

beansClass .put ( bean.getId () , Class. forName ( bean.getClassName ()) .newInstance ()) ;

}

catch   ( Exception e )   {

e.printStackTrace () ;

}

}

}

}

/**

 * 使用 Jsoup 解析配置文件,把bean属性存到beans

 */

private   void  initBeansFromXML ( String xmlFilePath )   {

try   {

Document  doc  = Jsoup. parse ( new  File ( xmlFilePath ) ,  "UTF-8" ) ;

Elements beanElements =  doc .getElementsByTag ( "bean" ) ;

for   ( Element element : beanElements )   {

String id = element.attr ( "id" ) ;

String classPath = element.attr ( "class" ) ;

BeanDefinition bean =  new  BeanDefinition ( id, classPath ) ;

// 取得所有属性元素

Elements propertyElements = element.getElementsByTag ( "property" ) ;

for   ( Element propertyElement : propertyElements )   {

String propertyName = propertyElement.attr ( "name" ) ;

String propertyRef = propertyElement.attr ( "ref" ) ;

PropertyDefinition propertyDefinition =  new  PropertyDefinition ( propertyName, propertyRef ) ;

// 把属性元素定义添加到bean定义中

bean.getPropertys () .add ( propertyDefinition ) ;

}

beans .add ( bean ) ;

}

}

catch   ( Exception e )   {

e.printStackTrace () ;

}

}

} 
 

 

在单元测试中使用该注入器:


package com.chenzehe.spring.test.junit;

import org.junit.Test;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.chenzehe.spring.service.IHelloWorld;

public class HelloWorldTest {

    @Test

    public void instanceApplicationContext() {

        ApplicationContext cxt = new ClassPathXmlApplicationContext("applicationContext.xml");

        IHelloWorld helloWorld = (IHelloWorld) cxt.getBean("helloWorld");

        helloWorld.sayHelloWorld();

        helloWorld.save();

        com.chenzehe.spring.myspring.ClassPathXmlApplicationContext mycxt = new com.chenzehe.spring.myspring.ClassPathXmlApplicationContext(

"E:\\chenzehe\\study\\Spring\\eclipse\\workspace\\com.chenzehe.spring\\src\\main\\resources\\applicationContext.xml");

        IHelloWorld myHelloWorld = (IHelloWorld) mycxt.getBean("helloWorld");

        myHelloWorld.sayHelloWorld();

        myHelloWorld.save();

    }

} 
 

 

5、 内部Bean 注入

以上模拟注入对于内部Bean 的注入依然生效,即 Bean 的配置文件改成下面格式:


< bean   id = "helloWorld"   class = "com.chenzehe.spring.service.impl.HelloWorldImpl" >

< property   name = "personDao" >

< bean   class = "com.chenzehe.spring.dao.impl.PersonDao"   />

</ property >

</ bean > 
 

 

6、 一般属性的注入

    给bean 对象 HelloWorldImpl 添加一个 String 类型的属性 name ,一个 Integer 类型的属性 id ,添加 setget 方法,添加一个三个属性的构造函数。

修改spring 配置文件为:


< bean   id = "personDao"   class = "com.chenzehe.spring.dao.impl.PersonDao"   />

< bean   id = "helloWorld"   class = "com.chenzehe.spring.service.impl.HelloWorldImpl" >

< property   name = "personDao"   ref = "personDao"   />

< property   name = "name"   value = "chenzehe"   />

< property   name = "id"   value = "25"   />

</ bean > 
 

修改属性描述类PropertyDefinition ,添加一个描述属性 value ,设置 getset 方法。

修改注入实现核心代码ClassPathXmlApplicationContext ,先加入 commons-beanutils 包的依赖,用其取得一般类型的属性。

<dependency>

<groupId>commons-beanutils</groupId>

<artifactId>commons-beanutils</artifactId>

<version>1.8.3</version>

</dependency>

修改解析xml 文件类,把一般类型的属性信息也加进去:


        private void initBeansFromXML(String xmlFilePath) {
		try {
			Document doc = Jsoup.parse(new File(xmlFilePath), "UTF-8");
			Elements beanElements = doc.getElementsByTag("bean");
			for (Element element : beanElements) {
				String id = element.attr("id");
				String classPath = element.attr("class");
				BeanDefinition bean = new BeanDefinition(id, classPath);
				// 取得所有属性元素
				Elements propertyElements = element.getElementsByTag("property");
				for (Element propertyElement : propertyElements) {
					String propertyName = propertyElement.attr("name");
					String propertyRef = propertyElement.attr("ref");
					String propertyValue = propertyElement.attr("value");
					PropertyDefinition propertyDefinition = new PropertyDefinition(propertyName, propertyRef, propertyValue);
					// 把属性元素定义添加到bean定义中
					bean.getPropertys().add(propertyDefinition);
				}
				beans.add(bean);
			}
		}
		catch (Exception e) {
			e.printStackTrace();
		}
	}
 

 

修改注入方法:


    private void injectObject() {
		// 循环所有bean
		for (BeanDefinition beanDefinition : beans) {
			Object bean = beansClass.get(beanDefinition.getId());
			if (bean != null) {
				try {
					PropertyDescriptor[] ps = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();
					for (PropertyDefinition propertyDefinition : beanDefinition.getPropertys()) {
						for (PropertyDescriptor propertyDescriptor : ps) {
							if (propertyDefinition.getName().equals(propertyDescriptor.getName())) {
								Method setterMethod = propertyDescriptor.getWriteMethod();// 获取setter方法
								if (setterMethod != null) {
									Object value = null;
									if (StringUtils.isBlank(propertyDefinition.getValue())) {
										value = beansClass.get(propertyDefinition.getRef());
									}
									else {
										value = ConvertUtils.convert(propertyDefinition.getValue(), propertyDescriptor.getPropertyType());
									}
									setterMethod.setAccessible(true);
									setterMethod.invoke(bean, value);// 把引用对象注入到属性中
								}
								break;
							}
						}
					}
				}
				catch (Exception e) {
					// TODO: handle exception
				}
			}
		}
	}
	
 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值