[Java][Java EE] 2015年东京Java日,“Java EE 7核心配方”寺田佳央先生的讲座总结
※此文是基于演讲内容整理而成的,但其总结了本人所理解的内容。文中的错误等均由本人负责。
我去参加了在东京国际论坛举办的Java Day Tokyo活动,日期是2015年4月8日。
在其中的一个讲座中,我听了寺田佳央先生的《Java EE 7 精华秘诀》,所以我将一些我能够跟上的内容整理了起来。
我正在查看公开的幻灯片和笔记,回忆起并书写下来。
管控 Bean JSR-250
受管理的Bean用于资源引用、实例生成和实例销毁。JSR-250提供了许多注释选项,但@ManagedBean注释几乎不常用。
资源引用通过注解。
不恰当的写法
InitialContext id = new InitialContext();
ic.lookup("java:comp/DefaultManagedExecutorService");
使用JNDI进行查找并不理想。
现代的写作方式
@Resource(name="comp/DefaultManagedExecutorService")
ManagedExecutorService managedExecSvc;
使用@Resource注释。
不使用构造函数
在调用构造函数时,由于依赖注入(DI)尚未完成,可能会引发空指针异常。
现代的写作方式
public class Foo() {
@PostConstruct
public void init() {
// ...
}
}
在标有@PostConstruct的方法中初始化类。
拦截器 JSR-318
使用Java实现AOP的东西。在EE5中只能用于EJB。在EE6中需要使用XML。在EE7中只需要添加@Priority注解就可以了。
使用拦截器,可以将除了业务逻辑之外的处理(如日志输出和执行时间测量)装入注解中。
比如测量方法执行的时间
不好的写法
public void executeSomeMethod1() {
long start = System.currenTimeMillis();
// 難しいビジネスロジック
long end = System.currentTimeMillis();
long time = end - start;
logger.log(Level.DEBUG, "実行時間:" + time);
}
方法中包含了与想要实现的业务逻辑(业务流程)无关的代码。
现代的写作方式
@MySimpleProfilerInterceptor
public void executeSomeMethod1() {
// 難しいビジネスロジック
}
只需要在方法上添加注释,然后单独编写处理注释的代码。
Bean验证JSR-349
当需要验证Bean中设置的值时,应使用注释而不是逻辑来编写。
现代的写作方式
public class Foo {
@NotNull
@Size(min = 1)
private String name;
@NotNull
@Size(max = 8)
@Pattern("^\\d{3}-\\d{4}$")
private String zipCode;
}
JSR-330是一个可以选择的保留针对DI的规范。
在EE环境中,使用@Inject和@Qualifier注解。在JSF相关部分使用@Named注解。
在实例化中不使用new关键字
在新版本中,类之间紧密相连。实例的创建委托给容器,通过@Inject进行注入。
不太好的表达方式
public class Foo {
public void listBar() {
BarDAO = barDAO = new BarDAOFromCSV();
// ...
}
}
即使想要将BarDAO替换为其他的实现,也无法做到。
现如今的写作方式
public class Foo {
@Inject
private BarDAO barDAO;
public void listBar() {
// ...
}
}
以后可以用其他东西替换BarDAO实现。
多个实施方案时的区分方法
假设有一种名为Foo的实现,分别有FooMan和FooWoman。
public class FooMan implements Foo {
// ...
}
public class FooWoman implements Foo {
// ...
}
写法有误导致错误。
当有两个实现Foo的类时,下面的写法无法解决依赖关系,从而会导致错误。
public class Baz {
@Inject
private Foo foo;
}
解决方案:创建并使用Qualifier
创建用于标识类的Qualifier,并在类和注入点上进行注释标注。
在注入的类上加上Qualifier…
@ManQualifier
public class FooMan implements Foo {
// ...
}
@WomanQualifier
public class FooWoman implements Foo {
// ...
}
在注入点上添加限定符。
public class Baz {
@ManQualifier
@Inject
private Foo fooMan;
@WomanQualifier
@Inject
private Foo fooWoman;
}
这样做就不会出错,并且会注入所期望的类。
制作自定义限定符时需要注意的事项
如果不制定命名约定或将其放入专用的软件包中,可能会导致混乱。
当需要不可变(Immutable)的实例时
有误的书写方式
无法将注入点设为final,因此会出现错误。
public class FooService {
@Inject
private final Foo foo;
}
解决方案:使用构造函数注入
放弃属性注入,改用构造函数注入可以使用final。
public class FooService {
private final Foo foo;
@Inject
public FooService(Foo foo) {
this.foo = foo;
}
}
当有太多实现时,在筛选中会变得很麻烦。
使用@Named注释可以进行区分,但不行。不行不行。
当想要将@Named传递给JSF或EL表达式时使用。
传统工业发展委员会 CDI JSR-346
CDI默认启用
自Java EE 7起默认已启用。
Java EE 6使用了名为beans.xml的文件。而在Java EE 7中,通过为类添加注解,使得类能够被容器加载。
当您希望将物品放入容器时,请附上以下的标注。
@NormalScopedを継承したもの
@Dependent
可以使用beans.xml将所有类放入容器中,但是由于启动会变慢所以不行。
CDI管理的Bean是什么?
通过CDI容器自动生成的代理bean。
CDI会自动生成bean的代理类。注入点将实际注入代理类的实例。
想要实现单例模式的时候
不恰当的写法 (Bù de
因为javax.inject.Singleton不是@NormalScoped的继承类,所以不能成为CDI托管的Bean。
@javax.inject.Singleton
public class Ng {
// ...
}
解决方案:使用ApplicationScoped
@javax.enterprise.context.ApplicationScoped
public class Ok {
// ...
}
在部署时切换多个可用的实施版本
在beans.xml文件中使用@Alternative注解将类切换。
@Alternative
@Dependent
public class Foo1 implements Foo {
// ...
}
@Alternative
@Dependent
public class Foo2 implements Foo {
// ...
}
将beans.xml与类文件放入相同的存档中。
<beans xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
<alternatives>
<class>Foo2</class>
</alternatives>
</beans>
使用Foo2。
Qualifier在beans.xml中具有优先权。
如果为类添加Qualifier,则@Alternative将不起作用,并且将忽略beans.xml中的设置。
你可以给类加上@Specialized来实现。3
可以使用@Produces注解来注入不是CDI Managed Bean的对象。
方法:
-
- 创建一个 Qualifer
-
- 创建一个提供实例的类
- 在提供实例的方法上添加创建的 Qualifer 和 @Produces 注解
给很多注释很麻烦
用刻板印象来解决它。
这种写法很繁琐
有很多标注,几乎要忘记了。
@RequestScoped
@Foo
@Bar
@Baz
@Qux
public class Stress {
// ...
}
解决方案:将常用的标注归类为刻板印象。
创造刻板印象。
@Stereotype
@RequestScoped
@Foo
@Bar
@Baz
@Qux
@Target(TYPE)
@Retention(RUNTIME)
public @interface MyStereotype {}
使用已创作好的刻板印象。清爽。
@MyStereotype
public class Relax {
// ...
}
有内置的刻板印象
@Model和@Named和@RequestScoped一样。
创造独特的刻板印象时要注意什么
如果不制定命名规范或者将其放入专门的包中,可能会导致混乱。
使用CDI中的观察者模式
如果使用CDI,观察者模式也可以轻松实现。
事件发布方
注入Event<?>并调用fire方法。
@Dependent
public class FireStartar {
@Inject
Event<Foo> fooEvent; // 引数にしたいクラスを指定する
public void executeSomething() {
// イベント発火
fooEvent.fire(new Foo());
}
}
接收事件
使用@Observes。
@Dependent
public class FireWorks {
public void startFire(@Observes Foo foo) {
// ...
}
}
CDI的事件是同步处理。 (CDI de shì
因为直到活动结束还没有返回,所以不适合用于繁重的处理任务。
使用EJB或JMS代替。
最后一点:不要将任何东西都装在容器里。
只放上需要的功能。
如果在课程中加上限定符以进行识别,即使之后想要进行实现的更改也无法进行更换,并且不能实现松散耦合……???
这边比选择限定符更好。
对这些方面不是很了解。
很可能是用于JSF的后端bean。