Spring中Autowired注解,Resource注解和xml default-autowire工作方式异同

2012/11/07 17:25:28 1 Comment

前面说到了关于在xml中有提供default-autowire的配置信息,从spring 2.5开始,spring又提供了一个Autowired以及javaEE中标准的Resource注释,都好像可以实现类似的自动注入。那么是不是每个都实现同样的方式呢,这里面的几个配置到底有哪些异同点。哪个更全,哪个更优先,这些都需要对spring的内部原理有详细的了解才可以进行了解。
在以下文章时,首先有几个概念需要列出:
字段名称:即fieldName,这个即propertyDescriper的getPropertyName返回信息。
setter名称:即方法setter除set之外的名称,如setAbc,则名称为abc,这里的abc不一定和fieldName相同。
参数名称:即在参数中所定义的参数的名称,如setAbc(Abc a123)。这里的参数名称就是a123。
本文所使用spring版本为spring3.0.2。

处理类和处理顺序异同

default-autowire是在xml中进行配置的,而这个配置从spring初始就提供了。而Autowired注解,则是从2.5自支持以java1.5之后才出现的,这就必然导致对相应的处理以及逻辑是不同的。那么每个方式的处理顺序是怎样的呢,从我写的文章:Spring中获取一个bean的流程-2.也可以由下面的代码得出:

		if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
				mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
			MutablePropertyValues newPvs = new MutablePropertyValues(pvs);

			// Add property values based on autowire by name if applicable.
			if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
				autowireByName(beanName, mbd, bw, newPvs);
			}

			// Add property values based on autowire by type if applicable.
			if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
				autowireByType(beanName, mbd, bw, newPvs);
			}

			pvs = newPvs;
		}
......
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof InstantiationAwareBeanPostProcessor) {
					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
					pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);

以上代码来源于类AbstractAutowireCapableBeanFactory的populateBean方法。从上可以看出,spring首先处理在bean定义上的autowire属性,然后再处理后面的InstantiationAwareBeanPostProcessor类。首先bean定义上的autowire属性,可以来自于<bean>定义时autowire属性,也可以来自于整个xml定义中<beans>节点中的default-autowire属性。

那么@Autowired注解和@Resource注解在哪儿处理呢,看上面的代码,有个InstantiationAwareBeanPostProcessor类,如果你仔细查看里面的实现,你可以发现里面即为处理相应注解类的实现。而这些注解类,只要在xml中启用了<context:annotation-config/>,即可以开启这些类了。而我们的Autowired注解,由AutowiredAnnotationBeanPostProcessor来进行处理,而Resource类,则由CommonAnnotationBeanPostProcessor进行处理。

(more…)

再谈notify和notifyAll的区别和相同

2012/08/19 18:06:16 No Comments

经常在往上逛,关于在java中notify和notifyAll,经常有人有以下的说法:

notify只会通知一个在等待的对象,而notifyAll会通知所有在等待的对象,并且所有对象都会继续运行

并且,好像都有例子可以证明。上面的说法,可以说对,也可以说不对。究其原因,在于其中有一点很关键,官方的说法如下所示:

wait,notify,notifyAll:
此方法只应由作为此对象监视器的所有者的线程来调用。通过以下三种方法之一,线程可以成为此对象监视器的所有者
: 
通过执行此对象的同步实例方法。 
通过执行在此对象上进行同步的 synchronized 语句的正文。 
对于 Class 类型的对象,可以通过执行该类的同步静态方法。 

 一次只能有一个线程拥有对象的监视器。

以上说法,摘自javadoc。意思即,在调用中,必须持有对象监视器(即锁),我们可以理解为需要在synchronized方法内运行。那么由此话的隐含意思,即如果要继续由同步块包含的代码块,需要重新获取锁才可以。这句话,在javadoc中这样描述:

wait
此方法导致当前线程(称之为 T)将其自身放置在对象的等待集中,然后放弃此对象上的所有同步要求。出于线程调度
目的,在发生以下四种情况之一前,线程 T 被禁用,且处于休眠状态: 
其他某个线程调用此对象的 notify 方法,并且线程 T 碰巧被任选为被唤醒的线程。 
其他某个线程调用此对象的 notifyAll 方法。 
其他某个线程中断线程 T。 
大约已经到达指定的实际时间。但是,如果 timeout 为零,则不考虑实际时间,在获得通知前该线程将一直等待。 
 然后,从对象的等待集中删除线程 T,并重新进行线程调度。然后,该线程以常规方式与其他线程竞争,以获得在该对
象上同步的权利;一旦获得对该对象的控制权,该对象上的所有其同步声明都将被恢复到以前的状态,这就是调用 wait
 方法时的情况。然后,线程 T 从 wait 方法的调用中返回。所以,从 wait 方法返回时,该对象和线程 T 的同步状态与调
用 wait 方法时的情况完全相同。

即必须重新进行获取锁,这样对于notifyAll来说,虽然所有的线程都被通知了。但是这些线程都会进行竞争,且只会有一个线程成功获取到锁,在这个线程没有执行完毕之前,其他的线程就必须等待了(只是这里不需要再notifyAll通知了,因为已经notifyAll了,只差获取锁了)有如下一个代码,可以重现这个现象。

(more…)

如何使用git从主仓库(main)更新数据到分支(fork)中-转

2012/08/12 21:16:40 No Comments

本文转自 http://my.oschina.net/luffyke/blog/70336 原文为 Github update fork 作者:kxt

Github上经典的fork+pull request模式可以很容易的让你参加到github上的开源项目,但是,如果主项目有更新,这个时候怎么把主项目的更新合并到自己Fork的版本中呢?到目前为止,github没提供一个按钮来完成这个功能。
下面我以druid(https://github.com/AlibabaTech/druid)来做一个git update fork的示范。
首先先fork druid到自己的github中。

克隆到自己本地的计算机。(read only)
用git clone git@github.com:luffyke/druid.git for write and read access

(more…)

读取指定jar所在的系统目录(windows系统中)

2012/08/08 10:34:08 No Comments

在做有关jna的项目开发时,我们经常碰到的问题就是如何去加载我们所写的dll文件。一般来说,这个dll会被放到windows/system32目录下,但这个方法需要手动地将这个dll复制到相应的目录中。但如果这个操作要由用户来做的话,过程就复杂了,不能期望用户总是能按指定的步骤去进行。所以,我们需要一个更方便的方法,比如直接将dll放到与jar相同的目录中,直接放到一起,避免了再重新复制dll的步骤。

使用这个方法,我们就可以使用以下方法来加载这个dll。

System.load(filePath);

这个filePath就是dll的文件路径了。那么问题就剩下如何来找到这个dll了。再简单一点,我们只需要找到这个相绑定的jar的目录就可以了。那么问题就简单了,使用以下方法就可以做到了(这个方法引自JRegistry,一个访问windows注册表的jar工具):  

                String resourceName = X.class.getSimpleName() + ".class";//这里的X就是与dll相绑定的jar中任意一个类
		URL url = X.class.getResource(resourceName);//取得这个class文件的URL
		String urlStr = url.toString();//返回格式为jar:file:/x:/x/xx/xx.jar!/xx/xx/X.class,要求class是存放在jar文件中,如果是文件目录中,则是file:/x:/xx/x.jar!/xx/xx/X.class的格式
		int start = "jar:file:/".length();
		int end = urlStr.indexOf("!/");
		String fileName = urlStr.substring(start, end);将jar:file:/和后面的!/截取掉,就只剩下x:/x/xx/x.jar,就是jar文件的路径名
		File file = new File(fileName);
		System.out.println(file.getParentFile().getCanonicalPath());//直接返回jar文件所在的目录,这个目录就是我们所需要找的目录

在windows x64系统下读取sata硬盘序列号

2012/03/08 14:32:38 No Comments

上一篇文章中我们提到如何使用jni在windows环境中读取硬盘序列号。然而,原有的代码,并不能有效地读取sata硬盘信息,并且在x64环境下也不能工作。所以,我们需要一种新的读取硬盘序列号的方法。

最终,经过笔者寻找,发现终于有一个有效地同时能够读取sata硬盘的c++代码,该代码的源地址为:


http://www.winsim.com/diskid32/diskid32.cpp

此代码能够在x86以及x64位平台下很好地工作。当然,仅是一段读取硬盘信息的代码,此处有详细的使用代码。可以下载以使用。

那么,在java中, 我们可以使用这段代码,分别编译出两个版本的dll文件,一个定义为acx86.dll,另一个定义为acx64.dll。这样在项目启动时,我们就可以根据当前jvm的版本(为什么不是windows版本,而是jvm版本,自己想),来选择加载不同的dll。那么,如何判断当前jvm版本呢,以下代码可以达到:

	public static boolean isJvm32() {
		return System.getProperty("sun.arch.data.model").contains("32");
	}

属性值sun.arch.data.model,当在32位jvm时,将返回32; 而在64位jvm时,返回64。这样就可以分别加载不同的dll了。

以上代码(包括c++和java)均已在本机测试通过(windows xp x64版本,jdk32位和64位)。

使用scribe开发微博类oauth调用

2012/01/03 20:33:21 No Comments

DefaultApi20前篇文章说了如何使用基本的http api来调用新浪微博的应用,而在登陆这方面,新浪使用的是基本oauth2.0的授权应用,而其它如网易,腾讯则是使用基本1.0的调用,那么这两种应用都是基本oauth授权的应用,肯定有相应统一的开发技术了,那就是scribe。

关于scribe,可以访问其官方网站:https://github.com/fernandezpablo85/scribe-java,当然使用maven的话,可以使用以下的引用将其引用到项目中来:

		<dependency>
			<groupId>org.scribe</groupId>
			<artifactId>scribe</artifactId>
			<version>1.3.0</version>
		</dependency>

scribe支持oauth1.0a以及oauth2.0两个版本的授权应用。关于1.0和2.0的区别可以google进行查看,总的来说2.0是要比1.0要好些,应用也简单些。但每个提供商所支持的版本也不尽相同,所以本文分别演示两个版本的应用。

由于腾讯和网易所支持的版本均为1.0a,而新浪为2.0,所以本文仅给出参考代码,具体的代码,都差不多,无非就是根据不同的提供商的请求地址和参数进行修改的变化而已,主要的代码还是不变的。
备注:由于腾讯和网易在不给call_back参数的时候,需要设置为null,而不是标准中的oob,此处特地注明。
在scribe应用中,已经提供了国内主要微博和社区的oauth service api,其中有人人,新浪(仅为1.0a),腾讯和网易,所以本文也不需要额外再写了(当然要写的话还是很简单的)。这里要感谢Artorius,他的文章为:http://artori.us/java-oauth-lib-scribe-java-start-supporting-weibo

(more…)