[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的对象。

方法:

    1. 创建一个 Qualifer

 

    1. 创建一个提供实例的类

 

    在提供实例的方法上添加创建的 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。

广告
将在 10 秒后关闭
bannerAds