读书人

模拟Spring属性的流入

发布时间: 2012-08-25 10:06:20 作者: rapoo

模拟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" /><bean id="helloWorld" 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() {// 循环所有beanfor (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}}}}
?

?

读书人网 >编程

热点推荐