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 ,添加 set 和 get 方法,添加一个三个属性的构造函数。
修改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 ,设置 get 、 set 方法。
修改注入实现核心代码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
}
}
}
}