2

@ApplicationScoped @ManagedBean2 秒ごとにいくつかのプロパティを JSF アプリにロードする to call およびスケジュールされたタスクを使用しようとしています。何らかの理由で機能していません。私が従う手順を参照してください。

最初に、ファイル システムから 2 秒ごとにロードするクラスを作成します。

@ManagedBean
@ApplicationScoped
public class ProppertyReader {


    @PostConstruct
    public void init(){
        SystemReader systemReader = new SystemReader();
        systemReader.schedule();
    }

    private class SystemReader {
        private final  ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
        private  Logger LOGGER = Logger.getLogger(ProppertyReader.class.getName());

        public void schedule(){
            scheduler.scheduleAtFixedRate(new Runnable() {
                public void run() {
                    Properties properties = loadProperties();
                    LOGGER.info("Loaded property enabled:" + properties.getProperty("enabled"));
                }
            }, 0L, 2L, TimeUnit.SECONDS);
        }

        private Properties loadProperties() {
            try {
            Properties properties = new Properties();
            properties.load(new FileInputStream("~/Desktop/propertiesRepo/example.properties"));
                return properties;
            } catch (IOException e) {
            e.printStackTrace();
            }
            return null;
        }
    }
}

次に、別の Bean に移動し、プロパティを使用しようとします。

@ManagedBean
@SessionScoped
public class SomeBean {
    //...
    private Properties properties = new Properties();
    private boolean enabled = new Boolean(properties.getProperty("enabled"));
    //...
    public boolean isEnabled() {
        return enabled;
    }
}

#{someBean.enabled}その値に応じてコンポーネントを表示または非表示にするために JSF if ステートメントで使用する Bean を使用しようとすると、動作しないようです。

<c:if test="#{someBean.enabled}">
          <h1>Works!</h1>                 
</c:if>

何が悪いのかわかりません。

更新: Properties クラスに誤りがあります。私は今、破棄されていないこれらのプロパティを作成しようとしているので、コードを少しきれいにしましたが、アプリの起動時に NullPointer を取得しています。

プロパティ リーダーを 2 つのクラスに分割しました。

@ManagedBean
@ApplicationScoped
public class ProppertyReader {

    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
    private SystemReader systemReader = new SystemReader();
    public static Properties appProperties;

    @PostConstruct
    public void init(){
        schedule();
    }

    private void schedule(){
        scheduler.scheduleAtFixedRate(new Runnable() {
            public void run() {
                appProperties = systemReader.loadProperties();
            }
        }, 0L, 2L, TimeUnit.SECONDS);
    }
}

システムからの読み取りを行う場所は次のとおりです。

public class SystemReader {

        public Properties loadProperties() {
            try {
                Properties properties = new Properties();
                properties.load(new FileInputStream("~/Desktop/propertiesRepo/example.properties"));
                return properties;
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }
}

私が今それを呼び出す方法は次のとおりです。

@ManagedBean
@SessionScoped
public class SomeBean {

    private boolean enabled = new Boolean(ProppertyReader.appProperties.getProperty("enabled"));
//...

現時点では NullPointer 例外が発生していますが、近づいていると思います。

4

1 に答える 1

2

これはJavaの仕組みではありません。

目標を達成するには、プロパティ ファイルをアプリケーション スコープ Bean のインスタンス変数として保持し、毎回再作成して破棄 (!!) するのではなく、その内容を毎回リロードする必要があります。セッション スコープの Bean でもプロパティ クラスの完全に独立したインスタンスを作成するのではなく、アプリケーション スコープの Bean に保持されているインスタンスを実際に使用する必要があります。

ここに書き直します:

@ManagedBean
@ApplicationScoped
public class PropertiesHolder {

    private static final String PATH = "~/Desktop/propertiesRepo/example.properties";
    private Properties properties;
    private ScheduledExecutorService scheduler;

    @PostConstruct
    public void init() {
        properties = new Properties();
        scheduler = Executors.newSingleThreadScheduledExecutor();
        scheduler.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                try {
                    properties.load(new FileInputStream(PATH));
                } catch (IOException e) {
                    throw new RuntimeException("Failed to load properties", e);
                }
            }
        }, 0L, 2L, TimeUnit.SECONDS);
    }

    @PreDestroy
    public void destroy() {
        scheduler.shutdownNow();
    }

    public String getProperty(String key) {
        return properties.getProperty(key);
    }

}

@PreDestroyスケジューラをシャットダウンするも追加したことに注意してください。そうしないと、Java ランタイム環境がスレッドを使い果たすまで、サーバーを再起動するたびにスレッドがリークする可能性があります。

最新の値を取得する場合に備えて、セッション スコープ Bean でそれを使用する方法は次のとおりです。

@ManagedBean
@SessionScoped
public class SomeBean {

    @ManagedProperty("#{propertiesHolder}")
    private PropertiesHolder propertiesHolder;

    public void setPropertiesHolder(PropertiesHolder propertiesHolder) {
        this.propertiesHolder = propertiesHolder;
    }

    public boolean isEnabled() {
        return new Boolean(propertiesHolder.getProperty("enabled"));
    }

}

プロパティは Bean のインスタンス化で取得されないことに注意してください。そうしないと、すべての getter 呼び出しで Bean のインスタンス化の時点の値のみが取得され、同じセッション内の後続のリクエストで更新された値が取得されません。

さらに、値は本質的にリクエストスコープであるため、セッションスコープは単に値を保持するための間違ったスコープです。代わりに、リクエスト スコープの Bean にします。

@ManagedBean
@RequestScoped
public class SomeBean {

    @ManagedProperty("#{propertiesHolder.getProperty('enabled')}")
    private boolean enabled;

    public boolean isEnabled() {
        return enabled;
    }

    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
    }

}
于 2013-11-02T11:33:10.557 に答える