`
chenzehe
  • 浏览: 532691 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

模拟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 ,添加 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
				}
			}
		}
	}
	
 

 

分享到:
评论

相关推荐

    Spring的学习笔记

    第三课:模拟Spring功能 5 第四课:搭建sping的运行环境 8 一、 建立一个新的项目 8 二、 建立spring的配置文件 8 三、 引入spring的jar包 8 四、 测试代码: 8 五、 注意接口的使用: 8 第五课:IOC(DI)配置及应用 ...

    Spring.3.x企业应用开发实战(完整版).part2

    4.3.1 属性注入 4.3.2 构造函数注入 4.3.3 工厂方法注入 4.3.4 选择注入方式的考量 4.4 注入参数详解 4.4.1 字面值 4.4.2 引用其他Bean 4.4.3 内部Bean 4.4.4 null值 4.4.5 级联属性 4.4.6 集合类型属性 4.4.7 简化...

    Spring.net框架

    t.InvokeMember(prop.propertyName, ........BindingFlags.SetProperty, null, o, new Object[] {p})利用反射机制对创建出来的对象设置属性值。 我们的Factory就是利用这种方式根据配置文件动态加载程序集,动态创建...

    spring2.5 学习笔记

    第三课:模拟Spring功能 5 第四课:搭建sping的运行环境 8 一、 建立一个新的项目 8 二、 建立spring的配置文件 8 三、 引入spring的jar包 8 四、 测试代码: 8 五、 注意接口的使用: 8 第五课:IOC(DI)配置及应用 ...

    Spring in Action(第2版)中文版

    2.3注入bean属性 2.3.1注入简单的数值 2.3.2使用其他的bean 2.3.3装配集合 2.3.4装配空值 2.4自动装配 2.4.1四种自动装配类型 2.4.2混合使用自动和手动装配 2.4.3何时采用自动装配 2.5控制bean创建 2.5.1...

    Spring in Action(第二版 中文高清版).part2

    2.3 注入Bean属性 2.3.1 注入简单的数值 2.3.2 使用其他的Bean 2.3.3 装配集合 2.3.4 装配空值 2.4 自动装配 2.4.1 四种自动装配类型 2.4.2 混合使用自动和手动装配 2.4.3 何时采用自动装配 2.5 控制Bean...

    Spring in Action(第二版 中文高清版).part1

    2.3 注入Bean属性 2.3.1 注入简单的数值 2.3.2 使用其他的Bean 2.3.3 装配集合 2.3.4 装配空值 2.4 自动装配 2.4.1 四种自动装配类型 2.4.2 混合使用自动和手动装配 2.4.3 何时采用自动装配 2.5 控制Bean...

    spring 个人笔记

    //* 以下for循环是实现模拟spring自动装配(注入)功能 //一开始列出此bean的所有property子元素 for (Element propertyElement : (List)element.getChildren("property")){ //获取property子元素中 属性为...

    Spring3.x企业应用开发实战(完整版) part1

    4.3.1 属性注入 4.3.2 构造函数注入 4.3.3 工厂方法注入 4.3.4 选择注入方式的考量 4.4 注入参数详解 4.4.1 字面值 4.4.2 引用其他Bean 4.4.3 内部Bean 4.4.4 null值 4.4.5 级联属性 4.4.6 集合类型属性 4.4.7 简化...

    基于SSH模拟当当网项目(电子商务平台)

    采用Spring的IoC注入方式使用DAO 3.Action改造工作 采用整合插件注入方式使用Spring容器中的Service或DAO. (默认按名称匹配规则) 4.配置信息的改造 Service和DAO需要交给Spring容器. struts.xml不需要改变,因为...

    基于maven项目的SSM框架与layu前端框架的代码

    利用了工厂模式将对象交给容器管理,你只需要在spring配置文件总配置相应的bean,以及设置相关的属性,让spring容器来生成类的实例对象以及管理对象。在spring容器启动的时候,spring会把你在配置文件中配置的bean都...

    低清版 大型门户网站是这样炼成的.pdf

    6.1.3 spring 2.5拿手戏——控制反转与依赖注入 353 6.1.4 何为“面向切面编程aop” 356 6.1.5 spring 2.5圣经——面向接口编程 358 6.1.6 开始spring 2.5旅程—hello world 359 6.2 spring 2.5核心技术 364 ...

    mockitobeans

    这是一个巨大的痛苦,尤其是当您只想在测试的12个依赖项中注入2个时解决方案将模拟物添加为Bean @Configuration@MockedBeans ( mockClasses = { PersonDao . class}, spyClasses = { PersonService . class}, scope...

    Java学习笔记-个人整理的

    {2.10.1}类的属性}{60}{subsection.2.10.1} {2.10.2}类的方法}{61}{subsection.2.10.2} {2.10.3}静态代码块}{62}{subsection.2.10.3} {2.11}\ttfamily final}{63}{section.2.11} {2.12}\ttfamily abstract}{63}...

    Sosoo 1.0网络爬虫程序.doc

    通过上述对功能的定制,我们可以看到在应用中我们对sosoo的编程接口并不多,而且目前系统都是基于set的方式注入aop注入对象,这样很容易和spring等基于set方式的依赖注入(IOC)框架集成。 1.Roboter类,spider...

    JAVA上百实例源码以及开源项目

    6个目标文件,EJB来模拟银行ATM机的流程及操作:获取系统属性,初始化JNDI,取得Home对象的引用,创建EJB对象,并将当前的计数器初始化,调用每一个EJB对象的count()方法,保证Bean正常被激活和钝化,EJB对象是用...

    JAVA上百实例源码以及开源项目源代码

    6个目标文件,EJB来模拟银行ATM机的流程及操作:获取系统属性,初始化JNDI,取得Home对象的引用,创建EJB对象,并将当前的计数器初始化,调用每一个EJB对象的count()方法,保证Bean正常被激活和钝化,EJB对象是用...

    工程硕士学位论文 基于Android+HTML5的移动Web项目高效开发探究

    Chrome Frame 会把最新版的Chrome Webkit 内核和JavaScript 引擎注入到IE中, IE浏览器将获得Chrome的性能和功能 目录 摘要 I ABSTRACT II 专业名词清单 III 第一章 绪论 1 1.1 研究背景与意义 1 1.2国内外相关...

Global site tag (gtag.js) - Google Analytics