php cdi_从CDI的Swing中吸取的教训

php cdi

自从我进入CDI以来,我就探索了经典的Java EE使用。 然后,我将CDI用于我的一个宠物项目,以了解如何在Swing应用程序中使用它。 本文总结了到目前为止我从中学到的教训。

本文假定您对CDI有所了解; 如果没有,请阅读我以前有关CDI的文章(CDI概述第1部分和第2部分)或阅读文档。

在我最后一次尝试Swing时(我是一名Web开发人员),我认为在Spring中配置大多数UI组件比手动编码参数会更好。 在此过程中,我使用了传统的XML配置方法,因为使用批注会将我的代码耦合到Spring JAR,这是我讨厌做的。 但是,使用CDI,我可以将代码绑定到标准API上:我可以更改实现。 这类似于开发一个servlet,在其中引用Servlet API,然后在所需的任何容器中运行它。

我以这种方式进行编码和编码,查看制作的东西,进行重构,然后再进行其他编码,就像这是一个私人项目并且您没有截止日期一样。 然后,我意识到我可以吸取一些教训,以备将来使用。 在这里,它们没有特定的顺序。

正确的JAR

为您的Java SE项目获取所有合适的CDI JAR可能是一项艰巨的任务。 为了减轻您的痛苦,Weld为您提供了一个多合一的JAR,恰当地命名为weld-se。 不要争辩它已经过大并重新包装,只需使用它,您就可以避免很多痛苦。 对于Maven用户,这是配置:

<project>
...
  <dependencies>
    <dependency>
      <groupId> org.jboss.weld </groupId>
      <artifactId> weld-se </artifactId>
      <version> 1.0.1-Final </version>
    </dependency>
  </dependencies>
</project>

她是一个轻松的记录员

我所知道的所有日志框架(JDK,Commons Logging,Log4J和SLF4J)都使您可以轻松地声明类记录器:

privatestaticfinalLoggerLOGGER=LoggerFactory.getLogger(MyClass.class);

无论如何,在大多数情况下,要使用此功能,您可以:

  • 在您的IDE中创建一个模板。 但是,在每个IDE中配置模板可能会很繁琐。
    自我说明提出一项功能,可以将这样的模板(和首选项)保存在网络上并在我的所有IDE实例之间共享
  • 从某处复制该行,然后将其粘贴到需要的地方。 然后,您更改要记录的类。 坦率地说,尽管这并没有增加我的传说(恰恰相反),但这就是我一直在做的事情

而且一直在进行后者,碰巧我忘记更改记录的类。 愚蠢的,不是吗? 也许吧,但是更愚蠢的是,我必须首先编写它:类是我的上下文,应该对其进行推断。 猜测一下,Weld在焊机记录器JAR的帮助下做了什么(它使用SLF4J,所以请注意或将代码用作模板来使用另一个框架):

@Inject
privateLoggerlogger;

我真的不认为这会更简单! 唯一的缺点是您失去了常量:对于我现在处理的项目,我可以接受它。 要使用此功能,只需将以下依赖项添加到您的POM中:

<project>
...
  <dependencies>
    <dependency>
      <groupId> org.jboss.weld </groupId>
      <artifactId> weld-logger </artifactId>
      <version> 1.0.1-Final </version>
    </dependency>
  </dependencies>
</project>

记住初始化

CDI当然可以注入您的依赖项。 但是注入依赖项并不会在屏幕上组装它们。 幸运的是,CDI还为您提供了一个钩子: @PostConstruct注解的领域。 让我们举一个非常简单的例子:

publicclassMyPanelextendJPanel{

  @Inject
  privateJCheckBoxcheckbox;

  @PostConstruct
  publicvoidafterPropertiesSet(){
    setLayout(newFlowLayout());
    add(checkbox);
  }
}

在注入所有依赖项之后,将调用afterPropertiesSet()方法,该方法将扮演先前在构造函数中完成的角色。

是的,该方法以在InitializingBean接口中定义的旧Spring方法命名,其版本为1。现在可以通过在XML bean定义文件中指定bean的init-method属性或使用@PostConstruct批注来替换该方法。

(不要)数量增加

使用CDI,您的班级将相互注入。 但是,这意味着每个组件都应具有自己的类。 这可能相当麻烦:例如,对于按钮,每个按钮都应在特定的基础上附加其动作。 随着时间的流逝,即使是中等大小的应用程序,其类的数量也会比标准应用程序大得多。 恕我直言,这是不可取的,因为:

  • 它会使您的代码库更大,从而增加您的开发复杂性
  • 在Sun的JVM中,加载更多的类意味着您将使用更多的PermGen空间,并且更有可能遇到OutOfMemoryError

为了限制我产生的类的数量,我使用了一个装有产生器方法的组件工厂。 CDI将这些方法标识为注射提供者。

publicclassComponentFactory{

  @Produces
  publicJButtongetButton(){
    returnnewJButton();
  }
}

使用注射点

这很好,但还不够,因为必须在注入的类中完成动作(或文本和图标)关联。 我想用按钮文本之类的信息注释注入的属性,并在我的生产者方法中获取该信息。 这是InjectionPoint可选参数的目标。 如果您在方法中将其作为参数引用,CDI将免费提供给您。

publicclassComponentFactory{

  @Produces
  publicJButtongetButton(InjectionPointip){
    JButtonbutton=newJButton();
    // Do something based on annotations on the parameter
    ...
    returnbutton;
  }
}

这正是创建焊接记录器(参见上文)的方式。

尊重海格兰德规则

汉兰达的规则是:“只能有一个”。 除了被年轻人大多不知道的电影所拍摄外,它还阐明了一个基本事实。 由于注射必须是确定性的,因此注射点不能有两个候选者。 如前所述,使用生产者方法会遇到这个问题:CDI将同时具有JButton类和生产者方法,并且会以通常的方式大声抱怨它。

Exception in thread "main" org.jboss.weld.exceptions.DeploymentException:
 WELD-001409 Injection point has ambiguous dependencies.....
 at org.jboss.weld.bootstrap.Validator.validateInjectionPoint(Validator.java:280)
 at org.jboss.weld.bootstrap.Validator.validateBean(Validator.java:122)
 at org.jboss.weld.bootstrap.Validator.validateRIBean(Validator.java:141)
 at org.jboss.weld.bootstrap.Validator.validateBeans(Validator.java:331)
 at org.jboss.weld.bootstrap.Validator.validateDeployment(Validator.java:317)
 at org.jboss.weld.bootstrap.WeldBootstrap.validateBeans(WeldBootstrap.java:399)
 at org.jboss.weld.environment.se.Weld.initialize(Weld.java:81)
 at org.jboss.weld.environment.se.StartMain.go(StartMain.java:45)
 at org.jboss.weld.environment.se.StartMain.main(StartMain.java:57)

为了符合Highlander规则,您必须放弃JButton类作为注入候选对象。 为此,我在注入点和生产者方法上都使用了限定符。 由于我不想每个注入点/生产者方法对都使用限定符,因此我将其参数化:

@Qualifier
@Target({FIELD,METHOD})
@Retention(RUNTIME)
public@interfaceJType{
  publicClass<?extendsJComponent>value();
}

JType批注注释注入的属性和生产者方法,使我的代码符合Highlander规则!

传播这个词

我可以建议的一个好习惯是创建一个特殊的Properties类,该类的任务是初始化标签(以及另一个用于您的首选项等),然后将其注入所需的所有客户端类中。 现在,所有课程都可以访问您的国际化标签。 真了不起!

忘记Java WebStart

焊接JAR分析过程与Java WebStart不兼容。 您可能会收到以下错误消息:

122 [javawsApplicationMain] WARN org.jboss.weld.environment.se.discovery.URLScanner - could not read entries

java.io.FileNotFoundException:
  http:\xxxxxxxxxx\weld-logger-1.0.0-CR2.jar (La syntaxe du nom de fichier, de répertoire ou de volume est incorrecte)
  at java.util.zip.ZipFile.open(Native Method)
  at java.util.zip.ZipFile.<init>(Unknown Source)
  at java.util.zip.ZipFile.<init>(Unknown Source)
  at org.jboss.weld.environment.se.discovery.URLScanner.handleArchiveByFile(URLScanner.java:142)
  at org.jboss.weld.environment.se.discovery.URLScanner.handle(URLScanner.java:126)
  at org.jboss.weld.environment.se.discovery.URLScanner.scanResources(URLScanner.java:107)
  at org.jboss.weld.environment.se.discovery.SEWeldDiscovery.scan(SEWeldDiscovery.java:71)
  at org.jboss.weld.environment.se.discovery.SEWeldDiscovery.<init>(SEWeldDiscovery.java:45)
  at org.jboss.weld.environment.se.discovery.SEBeanDeploymentArchive$1.<init>(SEBeanDeploymentArchive.java:45)
  at org.jboss.weld.environment.se.discovery.SEBeanDeploymentArchive.<init>(SEBeanDeploymentArchive.java:44)
  at org.jboss.weld.environment.se.discovery.SEWeldDeployment.<init>(SEWeldDeployment.java:37)
  ...
  at com.sun.javaws.Launcher.run(Unknown Source)
  at java.lang.Thread.run(Unknown Source)

我希望它将在将来的版本中修复...

单身人士并不邪恶

我已经两次偶然发现一种奇怪的行为:在不应该切换按钮或状态丢失时选择切换按钮。 经过疯狂的调试后,我看到@PostConstruct方法的调用远远超出了初始调用。 看来我的代码在那之后要求再次注入。 为了对此进行补救,请使用@Singleton注释您的类,以便在多个调用之间共享实例。 我没有做更多的调查,因为:

  • 我解决了这个错误
  • 我不知道为什么我不应该在Swing应用程序中使用单例

结论

我仍在开发中,所以我认为我没有看到所有要看的东西。 但是,对于要在Java SE上下文中使用CDI的任何项目,前面的观点可以成为一个很好的起点。

而且请原谅双关语,因为我们这个😅️的夏天,我感到很开心

翻译自: https://blog.frankel.ch/lessons-learned-from-cdi-in-swing/

php cdi

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值