当一个Bean需要访问另一个Bean时,可以显示指定引用装配它。但是,如果你的容器能够自动装配Bean,就可以免去手工配置装配的麻烦。
Spring IoC容器能够帮助你自动装配Bean。只要在<bean>的autowire属性中指定自动装配模式就可以了。以下是Spring 3.X支持的自动装配模式。
no:不执行自动装配。必须显示装配依赖
byName:对于每个Bean属性,装配一个同名的Bean。
byType:对于每个Bean属性,装配类型与之兼容的一个Bean。如果找到超过一个Bean,将抛出UnsatisfiedDependencyException异常
constructor:对于每个构造函数参数,首先寻找与参数兼容的Bean。然后选择具有最多匹配参数的构造函数。对于存在歧义的情况,将抛出UnsatisfiedDependencyException异常。
默认模式是no,但可以设置<beans>根元素的default-autowire属性修改。这个默认模式将被Bean自己指定的模式覆盖。
注:Spring 3.X不支持autodetect自动装配模式,使用@Autowired注解代替。
尽管自动装配功能非常强大,但代价是降低了Bean配置的可读性。因为自动装配由Spring在运行时执行,你无法从Bean配置文件中得到Bean装配的方式。建议仅将自动装配应用到组件依赖不复杂的应用程序中。
(1)按照类型自动装配
可以将sequenceGenerator这个Bean的autowire属性设置为byType并且不设置prefixGenerator属性。然后Spring将试图装配类型与PrefixGenerator兼容的Bean。在这个例子中,将自动装配datePrefixGenerator。
<bean id="sequenceGenerator" class="com.jackie.codeproject.springrecipesnote.springioc.SequenceGenerator" autowire="byType"> <property name="initial" value="100000" /> <property name="suffix" value="A" /> </bean> <bean id="datePrefixGenerator" class="com.jackie.codeproject.springrecipesnote.springioc.DatePrefixGenerator"> <property name="pattern" value="yyyyMMdd" /> </bean>
按照类型装配的主要问题是有时候在IoC容器中有超过一个与目标类型兼容的Bean。在这种情况下,Spring将无法确定哪个Bean最适合于该属性,因此会抛出异常.
<bean id="sequenceGenerator" class="com.codeproject.jackie.springrecipesnote.springioc.SequenceGenerator" autowire="byType"> <property name="initial" value="100000" /> <property name="suffix" value="A" /> </bean> <bean id="datePrefixGenerator" class="com.codeproject.jackie.springrecipesnote.springioc.DatePrefixGenerator"> <property name="pattern" value="yyyyMMdd" /> </bean> <bean id="yearPrefixGenerator" class="com.codeproject.jackie.springrecipesnote.springioc.YearPrefixGenerator"> <property name="pattern" value="yyyy" /> </bean>运行程序,抛出UnsatisfiedDependencyException异常:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'sequenceGenerator' defined in class path resource [applicationContext.xml]: Unsatisfied dependency expressed through bean property 'prefixGenerator': : No qualifying bean of type [com.codeproject.jackie.springrecipesnote.springioc.PrefixGenerator] is defined: expected single matching bean but found 2: datePrefixGenerator,yearPrefixGenerator; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.codeproject.jackie.springrecipesnote.springioc.PrefixGenerator] is defined: expected single matching bean but found 2: datePrefixGenerator,yearPrefixGenerator(2)按照名称自动装配
byName是另一种自动装配模式。Spring将试图装配一个与属性名相同的Bean,而不是兼容的类型,这样能解决按照类型的自动装配的问题。
<bean id="sequenceGenerator" class="com.codeproject.jackie.springrecipesnote.springioc.SequenceGenerator" autowire="byName"> <property name="initial" value="100000" /> <property name="suffix" value="A" /> </bean> <bean id="prefixGenerator" class="com.codeproject.jackie.springrecipesnote.springioc.DatePrefixGenerator"> <property name="pattern" value="yyyyMMdd" /> </bean>按照名称的自动装配并不能工作于任何情况。有时候不可能使目标Bean的名称与属性相同。在实践中,往往需要在保持其他依赖自动装配的同时明确指定歧义的依赖。这意味着混合了显示装配和自动装配。
(3)按照构造程序自动装配
constructor自动装配模式相对byType模式更复杂一些。对于具有单个构造程序的Bean,Spring将试图为每个构造程序参数装配一个类型兼容的Bean。但对于具有多个构造函数的Bean,Spring首先试图为每个构造函数的每个参数找到一个类型兼容的Bean,然后将选择具有最多匹配参数的构造函数。
假定SequenceGenerator有一个默认的构造函数和一个具有PrefixGenerator参数的构造函数
public SequenceGenerator() { } public SequenceGenerator(PrefixGenerator prefixGenerator) { this.prefixGenerator = prefixGenerator; }在这种情况下,第二个构造函数匹配并被选中,因为Spring可以找到一个类型与PrefixGenerator兼容的Bean。
<bean id="sequenceGenerator" class="com.codeproject.jackie.springrecipesnote.springioc.SequenceGenerator" autowire="constructor"> <property name="initial" value="100000" /> <property name="suffix" value="A" /> </bean> <bean id="datePrefixGenerator" class="com.codeproject.jackie.springrecipesnote.springioc.DatePrefixGenerator"> <property name="pattern" value="yyyyMMdd" /> </bean>如果使用这种装配模式,需要避免构造函数歧义。
#define _LINE_LENGTH 300 int get_path_total(const char *path, long long* total) { int err=-1; FILE *file; char line[_LINE_LENGTH]; char *p; char tmp[100]; char *token; sprintf(tmp, "df %s", path); file = popen(tmp, "r"); if (file != NULL) { if (fgets(line, _LINE_LENGTH, file) != NULL) { if (fgets(line, _LINE_LENGTH, file) != NULL) { token = strtok(line, " "); if (token != NULL) { // printf("token=%s\n", token); } token = strtok(NULL, " "); if (token != NULL) { // printf("token=%s\n", token); *total=atoll(token)/1024;//k/1024 err=0; } } } pclose(file); } return err; }
popen() 函数 用 创建管道 的 方式启动一个 进程, 并调用 shell. 因为 管道是被定义成单向的, 所以 type 参数 只能定义成 只读或者 只写, 不能是 两者同时, 结果流也相应的 是只读 或者 只写.
command 参数 是 一个 字符串指针, 指向的是一个 以 null 结束符 结尾的字符串, 这个字符串包含 一个 shell 命令. 这个命令 被送到 /b
ZMQ被称为史上最快消息队列,它处于会话层之上,应用层之下,使用后台异步线程完成消息的接受和发送,完美的封装了Socket API,
大大简化了编程人员的复杂度,被称为史上最强大的消息中间件。ZMQ是用C语言编写的,30s内完成消息的传输,能够兼容多个平台,多种语言,
可以使用多种方式实现N对N的Socket连接。
/****************************window平台下JAVA开发jzmq的配置*************************************/
1. 将 Jzmq.dll 与 Libzmq.dll 放入 %JAVA_HOME%/bin 目录下
2. 将 Zmq.jar 包导入自己所创的项目中
即可运行。(前提是电脑中已配置好了java所需的环境变量JAVAHOME)
完成1和2之后如果程序仍然不能运行,试着打印一下,确认 Jzmq.dll 与 Libzmq.dll放到了正在使用的JDK/bin目录下
System.out.println(System.getProperty("java.library.path"));
/***************************************出现问题*****************************************************/
如果一直提示C:\Program Files\Java\jre6\bin\jzmq.dll: Can't find dependent ...说明你的系统缺少相应的DLL文件。千万不要一个一个在网上下载。
因为Jzmq.dll依赖的库文件实在太多了。可直接安装Microsoft .NET Framework v2.0 和Microsoft .NET Framework v3.5也可安装下vs2008 或VS2010,
安装完后,需重起电脑,再运行程序。
/*************************************使用方法-使用REQ模式进行主机间通信*********************************/
请看例子程序jzmq.war里的Hwserver.java 和Hwclient.java
服务器端(Hwserver.java)
1. 创建上下文, 初始化一个ZMQ.Context
2. 创建一个socket,通过context.socket(ZMQ.REP);//相应的zermq的socket, 比如req, rep, pair, push, pull...等等,本例创建REP类型
3. 绑定到端口
4. 无限循环,等待接受客户端请求
客户端(Hwclient.java)
1. 创建上下文, 初始化一个ZMQ.Context
2. 创建一个socket,通过context.socket(ZMQ.REQ);;//相应的zermq的socket, 比如req, rep, pair, push, pull...等等,本例创建REQ类型
3. 绑定到端口
4. 发送报文和接收应答
REP/REQ模式介绍
REP/REQ这种模式是双向的,应答模式。也就是说是一个请求一个响应,不能发送多个消息,显然这种应答模式的效率很低!
这种模式的通信过程是:
1. 创建ctx上下文对象,该对象会创建io_thread并启动它们,采用reactor模型作为poller不断轮询。线程间的通信使用mailbox来通信,而mailbox其实本质上就是一个双向的socketpair。
2. 创建zmq_socket对象,如果是client就使用connector去连接,如果是server就使用listener去监听。
3. connetor或者listener会创建除zmq_init_t对象,后者作为identity交换。
4. 结束上述的初始化之后会创建相应的session_t对象,并且关联相应的读/写管道,plugin zmq_engine, 进行真正的消息数据的读写。
5. 消息数据的读写是异步的,即调用zmq::zmq_send()和zmq::zmq_recv()只是将消息数据写到相应的管道中去。而session_t会在poller轮询到相应的读写事件的时候从管道里面读写消息数据。