VelocityViewServletにはキャッシュ機能がついてますが、こちらがうまく動作しないようです。
●WebappLoader.templatePaths に保存されているキャッシュを取り出せない(?)。
VelocityTools1.2より、WebappLoader内にテンプレートのパス情報をキャッシュしますが、こちらへの登録時と取り出し時のパスの指定が違うため、保存されているキャッシュを取り出せないようです。
取り出しの際には、request.getServletPath()+request.getPathInfo()の形式をキーとして取り出す(取り出したパスは、"/"で始まる)ため、キャッシュへの登録キーも "/" で始まる必要があります。
これを回避するには、WebappLader.java : 151行目
- templatePaths.put(name, paths[i]);
+ templatePaths.put("/" + name, paths[i]);
と変更します(動作未確認)。
●テンプレートに更新があり、キャッシュの再読み込みをする際に、マルチスレッド対応ができていない(?)。
テンプレートの更新を検知した際に、Template#process() ~ Template#merge(Context context, Writer writer)の処理が多重起動した場合、最後のスレッド以外のmerge()が例外を投げます。
VelocityEngineは1つのインスタンスとなるので、process()の始め、
data = null;
の部分が、他のスレッドにも影響を与え、Template.java : 242行目のif分にてテンプレートが正常に処理されていないものとみなされ、
Template.merge() failure. The document is null, most likely due to parsing error.
との例外が投げられます。
きわどいタイミングですが、JMeterなどで同時アクセスのテストをすると、結構な頻度で例外を投げます。
大量のアクセスのあるサイトなどでは例外が頻発する可能性があります。
(上記のキャッシュ問題が回避されれば、例外出現の可能性はテンプレート更新時の直後の瞬間に限られるはずですが。)
これを回避するには、Template.java : 87行目
- data = null;
とすればいいと思われます(が、影響範囲の特定はできていません)。
また、
velocity.propertiesにおいて、
webapp.resource.loader.cache = false
キャッシュをオフにする。
ただし、テンプレートを毎回読み込むので、負荷がかかる。
もしくは、
webapp.resource.loader.modificationCheckInterval = 0
テンプレートキャッシュの更新を行わない。
ただし、テンプレートの更新を行うには、VelocityViewServletの再起動をする必要がある。
の指定をすることで回避することができます。
こちらのいずれかは、上記であげたキャッシュの問題も同時に回避できるので、開発時には例外に目をつぶり、結合テスト~本番稼動時にこちらのいずれかの処置をとる、でも良いかもしれません。
どちらの処置をとるかは、運用による(テンプレートを更新するならキャッシュを無効に、しないなら更新を無効に)ので、案件によってそれぞれ検討することになります。


コメントする