指定Bean 引用
组成应用程序的 Bean 往往需要相互协作才能完成应用任务。为了Bean 之间的相互访问,你必须在 Bean 配置文件中指定Bean 引用。为此,Spring 提供了 <ref>标签为 Bean 属性或者构造方法参数指定 Bean 引用。
回忆一下之前的序列生成器示例,其前缀只接受字符串值,这样的灵活性不足以满足将来的要求。如果前缀的生成可以由某种编程逻辑来定义将会更好。为此,我们把“sesametech.springrecipes.s001”包复制为名叫“sesametech.springrecipes.s007”的包,然后在该包下创建“PrefixGenerator”接口来定义前缀生成操作,代码如下:
public interface PrefixGenerator {
public String getPrefix();
}
接下来,我们假定一种生成前缀的策略,即使用特殊的模式格式化系统当前日期。为此,我们创建“DatePrefixGenerator”实现类,代码如下:
public class DatePrefixGenerator implements PrefixGenerator {
private DateFormat formatter;
public void setPattern(String pattern) {
this.formatter = new SimpleDateFormat(pattern);
}
@Override
public String getPrefix() {
return formatter.format(System.currentTimeMillis());
}
}
这个实现类将通过设值方法 setPattern() 注入模式字符串,然后用于创建 java.text.DateFormat 对象以便格式化日期。
现在,我们可以用任意模式字符串来声明类型为DatePrefixGenerator 的 Bean,为此,我们在包下的beans.xml 配置文件中先配置一个 DatePrefixGenerator 的 Bean,如下所示:
<bean
id="datePrefixGenerator"
class="sesametech.springrecipes.s007.DatePrefixGenerator">
<property name="pattern" value="yyyyMMdd"/>
</bean>
为了应用这个前缀生成器,序列生成器 SequenceGenerator类应该接受 PrefixGenerator 类型的对象,而不是简单的前缀字符串。为此,我们可以选择通过设值方法以注入这个前缀生成器,修改后的SequenceGenerator 类代码片段如下所示:
public class SequenceGenerator {
private PrefixGenerator prefixGenerator;
……
publicSequenceGenerator(PrefixGenerator prefixGenerator, String suffix, int initial) {
this.prefixGenerator = prefixGenerator;
this.suffix = suffix;
this.initial = initial;
}
public voidsetPrefixGenerator(PrefixGenerator prefix) {
this.prefixGenerator = prefix;
}
public synchronized String getSequence(){
StringBufferbuffer = new StringBuffer();
buffer.append(prefixGenerator.getPrefix());
buffer.append(initial + counter++);
buffer.append(suffix);
return buffer.toString();
}
getter & setter…
}
然后,在 SequenceGenerator Bean 的配置中,可以包含一个 <ref> 标签来引用 ID 为 datePrefixGenerator 的 Bean 作为其 prefixGenerator 属性,代码片段如下所示:
<bean
id="sequenceGenerator"
class="sesametech.springrecipes.s007.SequenceGenerator">
<property name="initial"value="100000" />
<property name="suffix"value="A" />
<property name="prefixGenerator"ref="datePrefixGenerator" />
</bean>
最后,我们修改一下测试类“SequenceGeneratorTest”的代码,如下所示:
public class SequenceGeneratorTest{
@SuppressWarnings("resource")
public static void main(String[] args) {
ApplicationContextcontext = newClassPathXmlApplicationContext("sesametech/springrecipes/s007/beans.xml");
SequenceGeneratorgenerator = (SequenceGenerator)context.getBean("sequenceGenerator");
System.out.println(generator.getSequence());
System.out.println(generator.getSequence());
}
}
此时,运行一下,如果无意外,结果看起来应该如下所示:
20160608100000A
20160608100001A
同样,你也可以通过构造方法来注入 Bean 引用,对于本示例,读者可以参考以下配置,亲自试验一下:
<bean
id="sequenceGenerator"
class="sesametech.springrecipes.s007.SequenceGenerator">
<constructor-arg ref="datePrefixGenerator"/>
<constructor-arg value="B"/>
<constructor-arg value="200000"/>
</bean>
声明内部 Bean
如果 Bean 实例只用于一个特殊的属性,可以声明为内部Bean。内部 Bean 声明直接包含在<property> 或者 <constructor-arg> 中,不设置任何 id 或者 name 属性。这样的话,这个Bean 将是匿名的,不能用于其他地方,即使你为这个内部 Bean 设置了id 或者 name 属性,也将被忽略。
对于本示例,可以配置成如下所示:
<bean
id="sequenceGenerator"
class="sesametech.springrecipes.s007.SequenceGenerator">
<property name="initial"value="100000" />
<property name="suffix"value="A" />
<property name="prefixGenerator">
<bean class="sesametech.springrecipes.s007.DatePrefixGenerator">
<property name="pattern"value="yyyyMMdd" />
</bean>
</property>
</bean>
也可以配置成如下所示:
<bean
id="sequenceGenerator"
class="sesametech.springrecipes.s007.SequenceGenerator">
<constructor-arg>
<bean class="sesametech.springrecipes.s007.DatePrefixGenerator">
<property name="pattern"value="yyyyMMdd" />
</bean>
</constructor-arg>
<constructor-arg value="B"/>
<constructor-arg value="200000"/>
</bean>
作为练习,请读者亲自动手试验一下。
好了,今天就写到这里,待续···