22

我想创建一个 Producer,它可以将 java.util.ResourceBundle 注入任何类,以便轻松获取本地化字符串。我的 ResourceBundle-Producer 如下所示:

public class ResourceBundleProducer {
  @Inject       
  public Locale locale;

  @Inject       
  public FacesContext facesContext;

  @Produces
  public ResourceBundle getResourceBundle() {
    return ResourceBundle.getBundle("/messages", locale )
  }
}

Locale 和 FacesContext 的注入有效(从 Seam 3 Alpha Source 获取相应的生产者)。但不幸的是,ResourceBundle 不是可序列化的,因此不能以这种方式生成。尝试访问调用使用我的 ResourceBundle 的 bean 的 JSF 页面时,我从 Weld 收到以下错误:

Caused by: org.jboss.weld.IllegalProductException: WELD-000054 Producers cannot produce non-serializable instances for injection into non-transient fields of passivating beans\\n\\nProducer\: org.jboss.weld.bean-/D:/Program Files (x86)/GlassFish-Tools-Bundle-For-Eclipse-1.2/glassfishv3/glassfish/domains/teachernews/applications/teachernews/-ProducerMethod-services.producers.ResourceBundleProducer.getResourceBundle()\\nInjection Point\: field web.PersonHome.bundle

有什么方法可以让我的 ResourceBundleResolver 工作吗?还是有任何其他机制可以获得类似的功能?提前致谢!

编辑:

好的,我会花掉一些我辛苦赚来的积分;)也会接受一个很好的解决这个问题的方法!

我得到了另一个无法创建 Producer 的示例:FlashProducer。FacesContext-Flash 也无法生成,因为 Flash 不可序列化。

4

2 回答 2

27

好吧,首先 ResourceBundle不是 Serializable。见这里。信息很明确

无法生成不可序列化的实例以注入到钝化 bean 的非瞬态字段中

钝化豆???我认为web.PersonH​​ome是有状态会话 Bean 或 @ConversationScoped bean。我对吗 ???如果是这样,您应该将您的捆绑属性标记为瞬态

private transient @Inject ResourceBundle bundle;
于 2010-07-17T06:55:44.457 回答
5

根据 Arthur 接受的答案中的评论线程。我跟着这个博客以及这个博客进行了钝化/激活实验。实验证明了 MrD 的评论,即瞬态属性在激活时将为 NULL。因此,为了处理具有钝化能力的 bean(即 sessionscoped、conversationscoped 和有状态会话 bean)的不可序列化成员属性,我建议使用以下解决方案:

private ResourceBundle bundle;

@PostConstruct
@PostActivate
public void getResourceBundle() {
    bundle = ResourceBundle.getBundle("/messages", locale );
}

此解决方案确保每次进入 READY 状态时都重新初始化不可序列化的属性成员。

最后一个要解决的问题

最后一个要解决的问题是注入在 slf4j 1.5.3 之前不可序列化的 SLF4j Logger,我引用

从 SLF4J 版本 1.5.3 开始,记录器实例在序列化后仍然存在。因此,主机类的序列化不再需要任何特殊操作,即使记录器被声明为实例变量。

因此,只要您的 slf4j 依赖项是 1.5.3 或更高版本,您就可以安全地注入 SLF4j Logger,如下所示:

@Produces
@LogbackLogger
public Logger produceLogger(InjectionPoint injectionPoint){
    return LoggerFactory.getLogger(injectionPoint.getMember().getDeclaringClass().getName());
}

假设您声明了限定符:

@Qualifier
@Retention(RUNTIME)
@Target({METHOD, FIELD, PARAMETER, TYPE})
public @interface LogbackLogger {
}

然后在一个具有钝化能力的 bean 中,注入如下:

@Inject
@LogbackLogger
private Logger logger;
于 2014-02-04T20:54:28.300 回答