【问题标题】:How do you create and later access an application level resource?您如何创建和稍后访问应用程序级资源?
【发布时间】:2014-01-17 18:13:32
【问题描述】:

编辑:我正在尝试为 Web 应用程序的所有会话创建一个共享数据库连接池。另一篇文章说创建 servlet 上下文对象的最佳方法是让 init 侦听器创建它。然而,我不清楚如何使这个对象可供我的 servlet 使用。

【问题讨论】:

  • 你能给我们一些代码来帮助解释你的问题吗?
  • 不能使用空的构造函数吗?然后检查字段是否已经初始化?最终的意义何在?
  • 请 StackOverflow 上的人为您编写初始化代码。

标签: java servlets web-applications servletcontextlistener shared-resource


【解决方案1】:

另一种方法是使用静态初始化:

public class SomeClass {

    private static final Object[] CONTENT;

    static {
        CONTENT = new Object[SomeOtherClass.getContentSize()]; // To show you can access runtime variables
    }

}

一旦使用 ClassLoader 加载类,这将初始化 CONTENT 数组。

【讨论】:

    【解决方案2】:

    一种解决方案是使用私有持有者类:

    public class SomeClass {
        private static class ResourceHolder {
            private static final Resource INSTANCE = new Resource();
        }
    
        public static Resource getInstance() { 
            return ResourceHolder.INSTANCE;
        }
    }
    

    SomeClass.getInstance()第一次被调用时,实例将被初始化。

    【讨论】:

    • 这被称为Singleton Holder 模式。它是干净且线程安全的,但确实使代码难以测试和模块化。因此应谨慎使用。
    • 是否可以延迟初始化此模式,就像我说的我无法访问在加载时创建此对象所需的参数。
    • @user3056052 你有什么理由需要它 static final 吗?
    • 是数据库连接? static 因为数据库连接是有限的资源, final 因为我不希望在建立连接后更改它。至于为什么我不对其进行硬编码,因为我必须从 web.xml 文件中提取 url 和凭据。
    • @user3056052 我对 servlet 不是很熟悉。如果有疑问,您应该问一个更具体的问题来解释您要达到的目标 - 我很确定有一种标准的方法可以做到这一点,而单例,即使它可以工作,也可能不是最好的方法。
    【解决方案3】:

    最简单的延迟初始化是对一个实例使用enum

    enum Singleton {
        INSTANCE; // lazy initialised
    }
    

    另外的问题是你想要初始化值。要处理这个问题,您可以嵌套类。

    enum Utility {;
         static MyType val;
         static OtherType val2;
    
         enum Holder {
             INSTANCE;
    
             Holder() {
                // uses val and val2
             }
         }
    
         public static Holder getInstance(MyType val, OtherType val2) {
             Utility.val = val;
             Utility.val2 = val2;
             return Holder.INSTANCE; // only created the first time.
         }
     }
    

    注意:这是线程安全的,因为静态块初始化是安全的。

    【讨论】:

      【解决方案4】:

      类似:

      public static abstract class Lazy<T> {
      
          private T t = null;
      
          public synchronized T get() {
              if (t == null) {
                  t = create();
              }
              return t;
          }
      
          protected abstract T create();
      }
      
      public static final Lazy<List<String>> lazyList = new Lazy<List<String>>(){
      
          @Override
          protected List<String> create() {
              return new ArrayList<String>();
          }
      }; 
      

      【讨论】:

        【解决方案5】:

        我会提前警告您,您所描述的内容有一点代码味道,我怀疑您最好完全避免这种模式。依赖于外部运行时状态的静态资源破坏了关于变量范围的各种最佳实践。


        但是,您所描述的内容最好由SupplierFuture 实现,具体取决于成功构建所需对象所涉及的工作。区别有点迂腐,但您通常会使用 Future 来保存需要很长时间来计算的引用,而 Supplier 通常会快速返回。 Future 还与 Java 的并发实用程序有一些不错的挂钩,但听起来你并不需要它。

        你会像这样使用Supplier

        public class GlobalState {
          public static final Supplier<LazyData> MY_DATA = Suppliers.memoize(
            new Supplier<LazyData>() {
              public LazyData get() {
                // do whatever you need to construct your object, only gets executed once needed
              }
            });
        
          ...
        }
        

        Suppliers.memoize() 将以线程安全的方式缓存对底层Supplier 的第一次调用的结果,因此只需使用此调用包装您定义的Supplier 即可防止重复处理。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2021-12-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-08-30
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多