如需转载,请注明出处,谢谢http://equalxx.iteye.com/
这次代码格式调整有点凌乱
Chapter 1.Introduction 介绍
你现在是不是特别想开始写你的第一个bean了?或者你很犹豫,不知道CDI规范有什么地方会很难。别急,其实你可能已经写过成千上百个bean了,CDI只是让你用它们更简单地创建一个应用!
1.1 what is a bean 什么是bean
bean就是你想的那样。也就现在它在容器环境中有了定义,在java EE 6之前,在javaEE平台上术语”bean”没有明确的定义。当然,我们已经把web和企业级应用里面的java类叫做bean很多年了。甚至在javaEE规范里有好几种不同的叫做bean的东西,这其中包括EJB bean和JSF托管bean。同时,其他的第三方框架,比如Spring和Seam,介绍了他们自己对bean的理解。我们缺一个官方公共定义。
最终Java EE 6在Managed Bean规范中给出了bean的官方定义。Bean被定义为具有最小编程限制的容器管理对象,在某种情形下被称为POJO(Plain Old Java Object)。他们提供少量基本服务,比如资源注入,生命周期回调,以及拦截器。这些规范,比如EJB和CDI,都建立在此基础之上。但是,最终,这些bean和轻量级组件模型都会统一起来,在不同JavaEE平台上保持一致。
大多时候(除了很少的例外情形),构造器没有参数(或一个构造器被@Inject标注)的具体类被当做bean。这包括了所有的JavaBean和所有EJB会话Bean(EJB Session Bean)。如果你已经写过JavaBean和EJB的bean的话,相当于已经接触过bean了,不需要在此之上多添加什么特别的配置。你之前每天写的bean到目前为止还没有用到CDI规范里的新服务,但你现在可以试着利用CDI对任何一个bean进行操作:允许容器创建和销毁bean的实例,并将它们与指定的上下文相关联,将它们注入到其他bean中,在EL表达式中使用它们,用限定的注释去标注,甚至给他们添加拦截器和装饰器——这并不需要你修改现有的代码,最多就是加点注释。现在就让我们来创建你的第一个用CDI生成的bean吧。
1.2 Getting our feet wet 试水
假设我们有两个现有的Java类,我们已经在各种应用里用了很多年了。第一个类是把一个字符串转换成句子list:
public class SentenceParser {
public List<String> parse(String text) { ... }
}
第二个类是一个供外部系统前端调用的无状态会话bean,功能是将句子从一种语言翻译成另一种语言:
@Stateless
public class SentenceTranslator implements Translator {
public String translate(String sentence) { ... }
}
其中Translator是EJB本地接口:
@Local
public interface Translator {
public String translate(String sentence);
}
让我们写一个bean,翻译整个文本:
public class TextTranslator {
private SentenceParser sentenceParser;
private Translator sentenceTranslator;
@Inject
TextTranslator(SentenceParser sentenceParser, Translator sentenceTranslator) {
this.sentenceParser = sentenceParser;
this.sentenceTranslator = sentenceTranslator;
}
public String translate(String text) {
StringBuilder sb = new StringBuilder();
for (String sentence: sentenceParser.parse(text)) {
sb.append(sentenceTranslator.translate(sentence));
}
return sb.toString();
}
}
但等等,没有无参数构造器的TextTranslator是否仍然是个bean?如果你还记得的话,一个类没有无参构造器,但如果有@Inject注解的话,它仍然是个bean。
正如你所想,@Inject和依赖注入有关!@Inject适用于bean的构造器或者方法,然后容器在初始化的时候调用这些构造器或者方法。容器也可以通过这些构造器和方法的参数来注入其他bean。
我们可以获得TextTranslator的实例通过将其注入到一个bean构造函数、方法、域中,或是一个JavaEE组件类的域或方法(如servlet)。容器选择被注入的对象是通过注入地方的类型,而不是域、方法或者参数的名称。
让我们来创建一个通过域注入来获得TextTranslator实例的UI Controller bean吧,用来翻译用户输入的文本。
@Named @RequestScoped
public class TranslateController {
@Inject TextTranslator textTranslator;
private String inputText;
private String translation;
// JSF action method, perhaps
public void translate() {
translation = textTranslator.translate(inputText);
}
public String getInputText() {
return inputText;
}
public void setInputText(String text) {
this.inputText = text;
}
public String getTranslation() {
return translation;
}
}
小贴士:
注意这个Controller是被标注了request-scoped和named的。因为现在web应用里同时用这俩注释非常常见,所以CDI里有个内置的注解@Model,如果用了@Model,就相当于创建了一个@request-scope,@Named bean。
另外,我们也可以通过编程方式用bean的类型作为参数,从一个被注入的实例的实例获取一个TextTranslator实例,语言说起来有点鸡肋,看代码吧:
import javax.enterprise.inject.Instance;
import javax.inject.Inject;
....
@Inject Instance<TextTranslator> textTranslatorInstance;
...
public void translate() {
textTranslatorInstance.get().translate(inputText);
}
请注意没必要为了把一个bean注入到另一个bean而去写getter或setter方法。CDI可以直接访问一个被注入的域(甚至它是私有的),这样可以少些无用代码。域的名字可以任意命名,它决定了什么会被注入。
在系统初始化期间,容器必须验证注入的类的存在。在我们的例子中,如果没有Translator的实现方法(如果SentenceTranslator EJB没有加载),容器会通知我们这里有个问题依赖(unsatisfied
dependency)。如果有多个Translator的实现类,容器会通知我们依赖模糊(ambiguous dependency)。
在我们深入细节以前,让我们先停下来检查一下bean的结构。bean的哪方面最重要,是什么让它最重要。所以与其给你看bean的例子,我们将要找出是什么组成了一个bean。
如需转载,请注明出处,谢谢http://equalxx.iteye.com/