`
ldd600
  • 浏览: 103778 次
  • 性别: Icon_minigender_1
  • 来自: 上海
博客专栏
47bb354f-8b5f-3ea6-a206-c7ead38c741c
Hyperic插件开发不完...
浏览量:11271
社区版块
存档分类
最新评论

利用Commons-BeanUtils实现简易的依赖注入框架

阅读更多

最近在完成一个小小的framework项目,由于项目中不使用spring,juice,自己实现了一个简易的依赖注入框架。


  1. 写一个xml文件作为配置的实际例子

 

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.ldd600.com/beanIoc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.ldd600.com/beanIoc beanIoc.xsd">
	<bean id="ftpSend" class="com.ldd600.bean.ioc.beans.impl.FTPTransporter">
		<params>
			<param value="/ldd600" key="uploadFolder"></param>
			<param value="com.ldd600.bean.ioc.beans.impl.JugUUIDGenerator" key="generator" converter="com.ldd600.bean.ioc.converters.UUIDGeneratorConverter"></param>
		</params>
	</bean>
		<bean id="jmsSend" class="com.ldd600.bean.ioc.beans.impl.JMSTransporter">
		<params>
			<param value="Ldd600Queue" key="destName"></param>
		</params>
	</bean>
</beans>

 

 

 

 

 2. 根据这个xml文件,定义一个schema文件,验证配置文件

 

 

 

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:sample="http://www.ldd600.com/beanIoc" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.ldd600.com/beanIoc" elementFormDefault="qualified" attributeFormDefault="unqualified">
	<xsd:complexType name="paramsType">
		<xsd:annotation>
			<xsd:documentation> of java class</xsd:documentation>
		</xsd:annotation>
		<xsd:sequence maxOccurs="unbounded">
			<xsd:element name="param">
				<xsd:complexType>
					<xsd:annotation>
						<xsd:documentation>key is property name, value is property value</xsd:documentation>
					</xsd:annotation>
					<xsd:simpleContent>
						<xsd:extension base="sample:leafType">
							<xsd:attribute name="key" type="sample:notEmptyToken" use="required"/>
							<xsd:attribute name="value" type="sample:notEmptyToken" use="required"/>
							<xsd:attribute name="converter" type="sample:classAttributeType" use="optional"/>
						</xsd:extension>
					</xsd:simpleContent>
				</xsd:complexType>
			</xsd:element>
		</xsd:sequence>
	</xsd:complexType>
		<xsd:complexType name="idClassType">
		<xsd:all minOccurs="0">
			<xsd:element name="params" type="sample:paramsType">
				<xsd:key name="outerParamsKey">
					<xsd:selector xpath="sample:param"/>
					<xsd:field xpath="@key"/>
				</xsd:key>
			</xsd:element>
		</xsd:all>
		<xsd:attribute name="id" type="sample:notEmptyToken" use="required"/>
		<xsd:attribute name="class" type="sample:classAttributeType">
			<xsd:annotation>
				<xsd:documentation>class name</xsd:documentation>
			</xsd:annotation>
		</xsd:attribute>
	</xsd:complexType>
	<xsd:simpleType name="leafType">
		<xsd:restriction base="xsd:string">
			<xsd:pattern value="(\s)*"/>
		</xsd:restriction>
	</xsd:simpleType>
	<xsd:simpleType name="classAttributeType">
		<xsd:restriction base="sample:notEmptyToken">
			<xsd:pattern value="([a-z|0-9|_]+\.)*[A-Z]([A-Z|a-z|0-9|_])*"/>
		</xsd:restriction>
	</xsd:simpleType>
	<xsd:simpleType name="notEmptyToken">
		<xsd:restriction base="xsd:token">
			<xsd:pattern value="(\S+\s*)+"/>
		</xsd:restriction>
	</xsd:simpleType>
	<xsd:element name="beans">
		<xsd:complexType>
			<xsd:sequence maxOccurs="unbounded">
				<xsd:element name="bean" type="sample:idClassType"/>
			</xsd:sequence>
		</xsd:complexType>
		<xsd:key name="beanIdkey">
			<xsd:selector xpath="./sample:bean"></xsd:selector>
			<xsd:field xpath="@id"></xsd:field>
		</xsd:key>
	</xsd:element>
</xsd:schema>

 

·         创建xsdConfig文件,内容主要是生成的java类的package名,类simple name的前缀和后缀

 

<xb:config
 xmlns:xb=
 "http://xml.apache.org/xmlbeans/2004/02/xbean/config">
 <xb:namespace uri="http://www.ldd600.com/beanIoc">
  <xb:package>com.ldd600.bean.ioc</xb:package>
</xb:namespace>
  <xb:namespace uriprefix="http://www.ldd600.com/beanIoc">
    <xb:prefix>Xml</xb:prefix>
  </xb:namespace>
  <xb:namespace uriprefix="http://www.ldd600.com/beanIoc">
    <xb:suffix>Bean</xb:suffix>
    </xb:namespace>
</xb:config>

 

 

 

 

·         创建一个bat可执行文件,不用每次跑都去cmd下敲一堆命令,累啊。bat文件的内容:

scomp -d classes\beanIoc -src src\beanIoc -out beanIoc.jar beanIoc.xsd beanIoc.xsdconfig

 

·         双击bat,所需要的java类的.java文件,class文件和xmlbeans jaxb需要的元数据都横空出世了,这些元数据xmlbeans会用来对xml文件进行验证,检查是否符合schema定义的语义规则。

·         java文件和元数据信息都拷贝到eclipse中吧,或者直接把生成的jar包发布到maven repository中,然后再pomdependency它。

 

 

 

4. 解析的过程中,需要生成被依赖注入的对象,并完成属性的动态设定。

4.1   生成依赖注入的对象

生成依赖注入的对象是通过反射直接生成类的实例,在这里要求有public的参数为空的构造函数。

  

 

Class clazz = Class.forName(sNamclassNamee);
return clazz.newInstance();

 

 

4.2  属性的动态设定

Commons-BeanUtils就是专门免费做这件事的好同志,我们可以利用它来完成,基本类型和一些经常使用的类型,Commons-BeanUtils责无旁贷的提供了自动转换的功能,beanutils不需要我们提供参数的类型,它可以自动完成转换,它是根据getset方法的类型来决定类型的,可参见PropertyDescriptor.getPropertyType()方法。使用方法如下:

 

 

 

 

 

 

 

 

 

 

 

 

 

if (!PropertyUtils.isWriteable(object, key)) {
						throw new ConfigParseException(object.getClass()
								+ " doesn't have the property " + key
								+ "'s setter method!");
					}
			String paramVal = paramBean.getValue();
			BeanUtils.setProperty(object, key, paramVal);

 

 

isWriteable方法判断是否有可用的set方法,如果有就完成属性的动态设置。paramBean就是xml文件中定义的那个param

 

 

但是Beanutils默认帮我们转换的类型为基本类型和所有它已经提供了Converterclass类型,如果我们有特殊的类需要进行动态设定,必须自己提供converter,注册到它的converters map中。这样beanutils兄弟在动态设定属性值的时候,就会根据属性的类型去converter map中把取出该属性类型对应的自定义converter来转换。因为在这里配置文件中配置的都是String 所以我们对Converter接口做了修改:

 

public abstract class BeanConverter implements Converter {
	public abstract Object convert(Class type, String value) throws ConfigParseException;

	public Object convert(Class type, Object value) {
		return this.convert(type, (String)value);
	}
}

 

 

 

 

我们强制规定了convert方法的参数必须是String,自己提供的converter必须继承BeanConverter抽象类。

 

String key = paramBean.getKey();
					String converterClsName = paramBean.getConverter();
					if (StringUtils.isNotEmpty(converterClsName)) {
						Class converterClazz = Class.forName(converterClsName);
						if (!BeanConverter.class
								.isAssignableFrom(converterClazz)) {
							throw new ConfigParseException(
									"converter must extend BeanConverter!");
						}
						
						if(!this.converters.containsKey(converterClsName)) {
							this.converters.put(converterClsName, converterClazz);
							// get property type
							Class propertyClazz = PropertyUtils.getPropertyType(
									object, key);
							// register converter
							ConvertUtils.register((Converter) converterClazz
									.newInstance(), propertyClazz);

 

4.3 属性逻辑规则的检查

在设置好属性以后,这个属性的值并不一定配置的正确,也不一定满足逻辑规则,比如希望int值在35之间,比如希望String 不要为空等等。为了在动态设定完属性后进行逻辑规则的校验,提供了InitializingBean接口

 

public interface InitializingBean {
	void afterPropertiesSet() throws Exception;
}

 

 

实现该接口的类,它们的逻辑规则需要在afterProperties提供,不符合规则的请抛异常,并会在属性设定完后检查。

 

public void afterPropertiesSet() throws Exception {
		if (StringUtils.isEmpty(uploadFolder)) {
			throw new IllegalArgumentException(
					"upload folder is an empty string!");
		}
		if (null == generator) {
			throw new IllegalArgumentException("generator is null!");
		}
	}

 

 

 

 

if (object instanceof InitializingBean) {
			((InitializingBean) object).afterPropertiesSet();
		}

 

 

 

4.4  bean注册到BeanContext

 

String id = idClassTypeBean.getId();
BeanContextFactory.getBeanContext().setBean(id, object);

  

 

4.5清理环境

完成属性的动态注入后,还需要清理环境

 

	private void cleanConfig() {
		ConvertUtils.deregister();
		this.converters = null;
	}

 

 

5.如何做到基于接口设计

·         Converter提供了基于接口设计的功能:我们可以动态的设置不同的实现。

·         用了该框架,本身就基于接口,我们可以在配置文件中修改bean的实现类。应用程序代码它不关心具体的实现类,它只关心id

 

Transporter transporter =  (Transporter) BeanContextFactory.getBeanContext().getBean(TransporterParser.getTransportName());

  

不过,这里没有象springjuice那么强大的bean factory功能。因为这个东东只是一个小项目的一小部分,所以功能上满足小项目的需求就足够了。

 

6. Test

 就简单的测了一下,可以看源代码。

 

7.总结

主要是项目是基于接口设计的,所以一些类的实现需要在配置文件里设定,实现类的实例属性也要是可以扩展的,并且提供属性值的逻辑校验,所以就有了这么一个东东。

 

 

源代码:

  • beanIoc.rar (82.3 KB)
  • 描述: beanIoc源代码
  • 下载次数: 73
分享到:
评论
2 楼 ldd600 2008-09-27  
commons-beanutils就用了java.reflect,您应该说的是dynamic proxy吧,用dynamic proxy和cglib虽然有很强的灵活性,但是也增加了复杂性。其实我本身项目中使用commons-beanutils已经足够了,只是为了指定一个实现类,没有必要用到它们,个人认为。您说的动态的可配置是指,不重新restart server的情况下动态load?
1 楼 sdh5724 2008-09-26  
鼓励下, 能自己做类似别人的东西本身是种进步. 尽管可能整个实现办法值得推敲.
   给你几个提示:
   1. Commons-BeanUtils是不是合适的.
   2. 如果说, 你的DI的实现要求是动态的可配置的实现办法又如何做?
   3. 除了Commons-BeanUtils, 有想过cglib. java reflection等等么. 毕竟性能有时候是非常要求高的.
 

相关推荐

    commons-beanutils-1.9.4-API文档-中文版.zip

    赠送Maven依赖信息文件:commons-beanutils-1.9.4.pom; 包含翻译后的API文档:commons-beanutils-1.9.4-javadoc-API文档-中文(简体)版.zip; Maven坐标:commons-beanutils:commons-beanutils:1.9.4; 标签:...

    commons-beanutils-1.9.4-API文档-中英对照版.zip

    赠送Maven依赖信息文件:commons-beanutils-1.9.4.pom; 包含翻译后的API文档:commons-beanutils-1.9.4-javadoc-API文档-中文(简体)-英语-对照版.zip; Maven坐标:commons-beanutils:commons-beanutils:1.9.4; ...

    commons-beanutils-1.8.0 jar包下载

    commons-beanutils-1.8.0 jar包: 1.commons-beanutils-1.8.0.jar 2.commons-beanutils-1.8.0-javadoc.jar 3.commons-beanutils-1.8.0-sources.jar 4.commons-beanutils-bean-collections-1.8.0.jar 5.commons-...

    commons-beanutils-1.8.3和commons-beanutils-1.8.0

    在给定的压缩包文件中,包含了两个版本的Apache Commons BeanUtils库:`commons-beanutils-1.8.0`和`commons-beanutils-1.8.3`。 Apache Commons BeanUtils的核心功能包括: 1. **属性访问**:BeanUtils提供了一...

    commons-beanutils-1.7.0.jar-解决commons-beanutils和commons-collections重复类

    解决办法是把commons-beanutils中的org/apache/commons/collections删除,这里上传一个改好可以直接使用的。

    commons-beanutils-1.9.4

    在本文中,我们将深入探讨`commons-beanutils-1.9.4`这个版本,了解其核心功能、使用场景以及如何在项目中集成和应用。 Apache Commons BeanUtils库的主要目标是简化JavaBean对象的属性访问。它通过提供一系列静态...

    commons-beanutils-1.7.0-API文档-中文版.zip

    赠送Maven依赖信息文件:commons-beanutils-1.7.0.pom; 包含翻译后的API文档:commons-beanutils-1.7.0-javadoc-API文档-中文(简体)版.zip; Maven坐标:commons-beanutils:commons-beanutils:1.7.0; 标签:...

    commons-beanutils-1.9.3-API文档-中文版.zip

    赠送jar包:commons-beanutils-1.9.3.jar; 赠送原API文档:commons-beanutils-1.9.3-javadoc.jar; 赠送源代码:commons-beanutils-1.9.3-sources.jar; 包含翻译后的API文档:commons-beanutils-1.9.3-javadoc-...

    commons-beanutils-1.7.0-API文档-中英对照版.zip

    赠送Maven依赖信息文件:commons-beanutils-1.7.0.pom; 包含翻译后的API文档:commons-beanutils-1.7.0-javadoc-API文档-中文(简体)-英语-对照版.zip; Maven坐标:commons-beanutils:commons-beanutils:1.7.0; ...

    commons-beanutils-1.9.1.jar<---&gt;commons-logging-1.1.3.jar

    `commons-beanutils-1.9.1.jar`与`commons-logging-1.1.3.jar`的组合,反映了Java开发中一种常见的模式:依赖于抽象而非具体实现。这样做的好处在于,当需要改变某个组件(如日志系统)的实现时,只需更改配置,而不...

    commons-beanutils-1.9.3-API文档-中英对照版.zip

    赠送jar包:commons-beanutils-1.9.3.jar; 赠送原API文档:commons-beanutils-1.9.3-javadoc.jar; 赠送源代码:commons-beanutils-1.9.3-sources.jar; 包含翻译后的API文档:commons-beanutils-1.9.3-javadoc-...

    commons-beanutils-1.9.1-API文档-中文版.zip

    赠送Maven依赖信息文件:commons-beanutils-1.9.1.pom; 包含翻译后的API文档:commons-beanutils-1.9.1-javadoc-API文档-中文(简体)版.zip; Maven坐标:commons-beanutils:commons-beanutils:1.9.1; 标签:...

    commons-beanutils-1.8.3.jar.zip

    在实际应用中,`commons-beanutils-1.8.3.jar`常与其他Apache Commons库(如Collections、Lang等)结合使用,以实现更强大的功能。例如,结合Commons Collections,可以方便地处理复杂的数据结构;结合Commons Lang...

    commons-beanutils (1.7.0 -1.9.2)6个

    - **框架集成**:许多Java框架如Struts、Spring等,都可能依赖`commons-beanutils`来简化对象操作。 5. **注意事项**: - **类型安全**:虽然BeanUtils提供了自动类型转换,但并非所有类型转换都是安全的,可能会...

    commons-beanutils-1.9.3jar包source包及相关jar包

    `commons-beanutils-1.9.3.jar`是这个库的核心组件,包含了BeanUtils的所有功能。 `commons-beanutils-1.9.3-sources.jar`则是源代码包,它包含了BeanUtils库的完整源代码,这对于开发者进行调试、学习和自定义扩展...

    commons-beanutils-1.8.2.jar,commons-codec-1.4.jar

    commons-beanutils-1.8.2.jar,commons-codec-1.4.jar,commons-collections-3.2.1.jar,commons-dbcp-1.2.2.jar,commons-digester-2.0.jar,commons-fileupload-1.2.1.jar,commons-httpclient.jar,commons-io-...

    commons-beanutils.jar、commons-logging.jar两个包

    beanUtils 方便访问javaBean 附带支持框架 logging jar包,Apache提供的这个beanutils包极大方便了javabean的 操作。包含了最新的commons-beanutils-1.9.3.jar,以及其依赖的commons-logging-1.2.jar包

    commons-beanutils-core-1.8.3.jar

    commons-beanutils-core-1.8.3.jar

    commons-beanutils-1.8.3 jar文件包.zip

    commons-beanutils-1.8.3是配置服务端打开工程所需要的一些相关的jar文件包,分别是:commons-beanutils-1.8.3.jarcommons-collections-3.2.1.jarcommons-lang-2.6.jarcommons-logging-1.2.jarezmorph-1.0.6.jarjson...

    commons-beanutils、commons-collections、commons-collections等常用jar 包下载

    1. **Apache Commons BeanUtils** - `commons-beanutils-1.9.3.jar` Apache Commons BeanUtils库是用于处理JavaBeans的工具类库。它提供了一种简单的方式来操纵JavaBean属性,无需直接调用getter和setter方法。这个...

Global site tag (gtag.js) - Google Analytics