札幌Javaコミュニティ第24回勉強会に参加しました
あんまり他の人と話はできなかったけど、純粋にテーマと発表が為になりました。
@shuji_w6eさんと@quicyさんありがとうございました!
GAE/Jについて(@shuji_w6eさん)
spin-up、spin-downについて
- spin-up
- アプリケーションの起動にかかる処理のこと。インスタンスの起動時間。何も考えずに作ると結構時間がかかる。
- spin-down
- Google App Engineでは1分以上リクエストがないと強制的にインスタンスが終了する。Googleのサーバのリソースの円滑な割り当てを行うため。
ある程度大きいサービスを提供する場合、随時人がアクセスしリクエスト発生するためspin-upにかかる時間をそれほど考えなくてよいが、
あまりアクセスされないサービスの場合や、人の少ない深夜であったりすると結構spin-upにより待たされてしまい印象が悪くなってしまう。
それを解決するため、1分に一回自分のcloneを叩くという手もあるが、それはGoogleにより非推奨とされている。
そこで、いかにspin-upに負けないアプリケーションを作るかが鍵となってくる。
spin-up時間が短ければ、いくらspin-downされても大丈夫
Google App Engineの性質
- 業務ではあまり使えない
- 純粋に面白い
- ノウハウは業務で活きる
- 開拓し甲斐のある場所
- CPUは一昔前のパソコン(Celeron)くらいか。ローカルでは速くてもサーバではどうか。
- シンプルさが最重要
spin-up対策
フレームワークの選択
→ slim3の方が本番に近いテストを行いやすい。クラスロードのイニシャルコストもかかる。
→ java.util.loggerで十分
- Groovy、JRuby
→ spin-downしない前提で・・・
→ spin-upが500ms-800msくらい。実用できるかも?
初期化対策
(1)遅延初期化
(2)手動で初期化
- 管理画面から手動実行
- デプロイ後に1回やれば良い場合はそうする(初期データ投入など)
- TaskQueueを活用→サイト構成の再構築処理
(3)そもそも初期化しない
- 初期化コストとのトレードオフ
- キャッシュは毎回Datastoreから取得(適切な自然キーを入れておく)
- Memcacheも結局内部でDatastoreを使ってるし、初期化コスト結構高いので注意
slim3について
- 1Action=1Controller class
- URLからコントローラをリフレクションで生成
- 初期化時にクラスがロードされない
- クラス数が多くなる
- リクエストパスの変更などがやや面倒
設計について
- 静的なページ
→ html自体ををキャッシュして返す
- 動的なコンテンツ
→ テンプレートエンジン→パース→オブジェクト返却
SWT/JFaceについて(@quicyさん)
Swingとの違い
- Swingでいうペインはないが、コンポジットを使う
- Swingとは逆で、ウィジェットを作る際にはコンストラクタに親を渡す設計(親は必ず必要)
- Image、Font、Colorについては明示的なリソースの破棄が必要なので注意
作ったサンプルの一例
package org.hoge; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.layout.*; import org.eclipse.swt.widgets.*; import org.eclipse.swt.*; public class SWTTest { public static void main(String[] args) { Display display = new Display(); Shell shell = new Shell(display); shell.setText("たいとる"); shell.setLayout(new FillLayout()); Text text = new Text(shell,SWT.BORDER|SWT.MULTI); text.setText("てきすと"); Button button = new Button(shell,SWT.NONE); button.setText("ぼたん"); button.addSelectionListener(new SelectionListener() { @Override public void widgetDefaultSelected(SelectionEvent arg0) { } @Override public void widgetSelected(SelectionEvent arg0) { System.out.println("おされた"); } }); shell.open(); //ウインドウが閉じられてなかったら while(!shell.isDisposed()){ if(!display.readAndDispatch()){ display.sleep(); } } } }
package org.jface; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.window.ApplicationWindow; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; public class MyWindow extends ApplicationWindow { public static void main(String[] args){ MyWindow mw = new MyWindow(null); mw.open(); } public MyWindow(Shell parentShell) { super(parentShell); this.setBlockOnOpen(true);//開いたら閉じないでブロック addMenuBar(); } @Override protected void configureShell(Shell shell) { // TODO Auto-generated method stub super.configureShell(shell); shell.setText("たいとる"); } @Override protected Point getInitialSize() { // TODO Auto-generated method stub return new Point(100,100); } @Override protected Control createContents(Composite parent) { Composite client = new Composite(parent,SWT.None); client.setLayout(new FillLayout()); Text text = new Text(client,SWT.BORDER|SWT.MULTI); text.setText("てきすと"); return text; } @Override protected MenuManager createMenuManager() { MenuManager root = new MenuManager("root"); MenuManager mm = new MenuManager("ふぁいる"); root.add(mm); mm.add(new Action("開く"){ @Override public void run(){ MessageDialog.openQuestion(getShell(), "test", "message"); } }); return root; } }