urlopen で HTTP Header などのデバッグ出力を表示する

HTTP Header が見えるブラウザ拡張入れればいいじゃない、という話は置いておいて。

>>> import urllib2
>>>
>>> handler = urllib2.HTTPHandler()
>>> handler.set_http_debuglevel(1)     ## ここで debuglevel を設定。1,2,3 を試したけど結果は同じでした
>>>
>>> opener = urllib2.build_opener(handler)
>>> opener.open("http://www.yahoo.co.jp")
send: 'GET / HTTP/1.1\r\nAccept-Encoding: identity\r\nHost: www.yahoo.co.jp\r\nConnection: close\r\nUser-Agent: Python-urllib/2.7\r\n\r\n'
reply: 'HTTP/1.1 200 OK\r\n'
header: Date: Thu, 23 Feb 2012 16:42:16 GMT
header: P3P: policyref="http://privacy.yahoo.co.jp/w3c/p3p.xml", CP="CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE GOV"
header: Expires: -1
header: Pragma: no-cache
header: Cache-Control: private, no-cache, no-store, must-revalidate
header: X-XRDS-Location: http://open.login.yahoo.co.jp/openid20/www.yahoo.co.jp/xrds
header: Vary: Accept-Encoding
header: Connection: close
header: Transfer-Encoding: chunked
header: Content-Type: text/html; charset=utf-8
<addinfourl at 4302627328 whose fp = <socket._fileobject object at 0x100489f50>>

転職しました

諸事情により東京から大阪にワープしまして、1月から アクセンス・テクノロジー 大阪オフィス で働いています。関西方面は土地勘がなく、まだまだ分からないことも多いですが、徐々に慣れていこうと思います。どうぞよろしくお願いいたします。


長年お仕事でお世話になった Java とはしばしのお別れですが、Jenkins の plugin などでプライベートでは付き合っていくつもりです。大阪 Jenkins 勉強会 にも行くよ!

Spring Framework Advent Calendar 2011 part.12 JSR-330 への対応

Spring Framework Advent Calender の 12 日目です。昨日に引き続き、アノテーションについての整理をしていきます。

JSR-330 Dependency Injection for Java

JSR-330 は、いわゆる DI の標準仕様を定めるものです。Bob Lee (Guice 作者) と Rod Johnson (Spring Framework 作者) がスペックリードをしています。

名称 説明
@Inject Inject する箇所を示すアノテーション
@Qualifier コンポーネントを限定するための識別子。メタアノテーション
@Named @Qualifier の利用例のひとつ。名前ベースの修飾子
@Scope Injector が生成したインスタンスを使い回すかどうかを指定するメタアノテーション
@Singleton @Scope の利用例のひとつ。コンポーネントが一度だけインスタンス化されることを明示する
Provider T 型のインスタンスを返すプロバイダー。アノテーションではない。通常、Injector とセットで利用される


説明を見ても、分かったような分からないような...。名称に関しては Guice を使っている人のほうが馴染み深いかもしれません。

インストール

maven でのインストール方法のみ書きます。 ディレクティブに以下を追記してください。

  <dependency>
    <groupId>javax.inject</groupId>
    <artifactId>javax.inject</artifactId>
    <version>1</version>
  </dependency>

利用例

Inject する例 (Spring 的には @Autowired)
@Controller
@SessionAttributes("registerForm")
public class ApplicationController {

    @Inject
    private EchoService echoService;
    

ここではフィールドに記述していますが、コンストラクターやメソッドに書くこともできます。

DI で管理するコンポーネントを宣言する例 (Spring 的には @Component)
@Named
public class DefaultEchoService implements EchoService {

    @Override
    public String echo(String str) {
        return str;
    }
}

@Named("foobar") のように書くこともできます。指定した名前でコンポーネントがDIコンテナに登録されます。何も書かないと、クラス名の先頭を小文字にしたものが登録されるようです(Spring の場合)。

Singleton (Spring ではデフォルト)
@Named("myEchoService")
@Singleton
public class DefaultEchoService implements EchoService {

    @Override
    public String echo(String str) {
        return str;
    }
}

スコープを Singleton にしたい場合に記述します。ただし、Spring のデフォルトは Singleton なので、書く必要があまりないでしょう。一方で JSR-330 の仕様を積極的に採用するなら、Scope のデフォルトは Prototype である必要があります*1。これを実現するには、Jsr330ScopeMetadataResolver を使います。

<context:component-scan base-package="example"  scope-resolver="org.springframework.context.annotation.Jsr330ScopeMetadataResolver" />

上記のように設定すると、デフォルトの Scope が Prototype になります。

@Qualifier, @Scope

これらはメタアノテーションのため、直接記述することはありません。
メタアノテーションとは、アノテーションに記述するアノテーションのことです。実際、たとえば @Named の定義は以下のようになっています。

@Qualifier
@Documented
@Retention(RUNTIME)
public @interface Named {

    /** The name. */
    String value() default "";
}

同様にして、ユーザー (あるいはサードパーティーベンダー) が @Qualifier や @Scope を利用した任意のアノテーションを作成することができます。ただし、アノテーションを定義しただけでは何も起こりませんので、それを DI コンテナ側で解釈するための実装も用意する必要があるでしょう。たとえば、Spring であれば、ScopeMetadataResolver の実装を独自に作成することで @Scope を利用した独自アノテーションの解釈を与えることができます。

Provider
public class Car {
     @Inject Car(Provider<Seat> seatProvider) {
        Seat driver = seatProvider.get();
        Seat passenger = seatProvider.get();
        ...
    }
}

@Named
public class SeatProvider implements Provider<Seat> {
    public Seat get() {
        return new Seat();
    }

インスタンスの生成を自前で管理したい場合に利用します。DI 対象でないコンポーネントを Provider でラップして、Inject 対象にするといったことも可能です。Provider の実装は別で定義しておき @Inject します。

*1:javax.inject.Scope の Javadoc に書かれています。http://docs.oracle.com/javaee/6/api/javax/inject/Scope.html

Spring Framework Advent Calendar 2011 part.11 @Autowired, @Resource, @Qualifier

Spring Framework Advent Calender の 11 日目です。今日は、アノテーションベースでの DI を行うときに頻出のアノテーションとなる @Autowired, @Resource, @Qualifier について整理してみます。

@Autowired @Resource
出自 Spring 独自 JSR250
記述できる場所 フィールド、コンストラクター、引数が複数あるメソッド フィールド、引数が1つのセッターメソッド
マッチング方法 型によるバインド 名前によるバインド
候補が複数マッチした場合 @Qualifier がある場合はさらに絞り込み、それでも複数ある場合は例外発生 例外発生
その他 Collection や Map にはバインドできない*1
  • コンストラクターや複数が引数あるメソッドに対する Injection をしたいなら @Autowired を使うしかない。
  • コレクションや Map に対して DI したい場合は、アノテーションベースでやるなら @Autowired は使えない。@Resource であれば可能。
  • @Autowired は Spring 独自。POJO を特定フレームワークに依存させたくないなら @Resource をつかう。
    • ただし、その場合は Component-Scan をどうするかという課題が残る。


今回のエントリに関連するオンラインマニュアルの記述は http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/beans.html#beans-annotation-config です。

Spring Framework Advent Calendar 2011 part.10 英語圏の情報にアクセスする

Spring Framework Advent Calender の 10 日目です。今日は、機能紹介から少し離れて、Spring Framework に関する情報の集め方について整理してみます。


これは自分の所感なのですが、Spring 3.0 が登場する前あたりから、Spring の日本語情報がだんだん少なくなってきているなと感じています。昔の Struts もそうでしたが、すでにひととおり主要な情報が出尽くして、

  • システムアーキテクチャにかかわるような基盤担当の人は、必要に応じて英語圏の情報を漁ったり、ソースコードを読んだりしている
  • アプリケーションのロジックを中心に実装する人は、すでにある日本語情報で事足りる

という構図になっているのではないかな、と。

情報の集め方

英語圏の情報で私がよく利用しているのは、以下です。といっても公式サイトの情報ばかりですが。


私自身、オンラインマニュアルを隅から隅まで読んでいるというわけではなく、必要に応じてスポットで読むようにしています。
また、Eclipse からはライブラリーのソースコードを簡単に閲覧できますので、気になった部分のソースコードはよく読むようにしています。読むときはもちろん、静的なアプローチと動的なアプローチを複合的に用います。

  • 静的なアプローチ ... ソースコードをじっくり読む
  • 動的なアプローチ ... デバッガを仕掛けて、ステップ実行するなどして実際のプログラムの動きを読む

また、時間のあるときになんとなくライブラリーのソースツリーをざっと眺めてみて気になるクラスの Javadoc を読んだり...といったこともやります。Eclipse を使っているなら、あるライブラリーのクラスが含まれるパッケージの他のクラスを知りたいと思ったときは、右クリックのコンテキストメニューから Show In -> Package Explorer などで対象ライブラリーのソースツリーにジャンプできますので便利です。API ドキュメントについても、ドキュメンテーションコメントにマウスカーソルをホバーさせれば、HTMLタグが解釈された Javadoc のドキュメントが表示されますので、わざわざオンラインのAPIドキュメントにアクセスする必要もありません。

ある特定の解決したい問題を抱えている場合は、フォーラムやJIRAも有効活用しましょう。あるクラスの動作が想定通りにいかない、といったレベルで絞り込みができていれば、そのクラス名で検索を駆けるのが手っ取り早いでしょう*1


これまでの Advent Calendar で紹介しているようなフレームワークのカスタマイズについては、オンラインマニュアルだけでは拡張ポイントがわからないこともあります。Spring と深くつきあっていくには、ソースコードを読むことは避けては通れないでしょう*2
Spring Framework は、ちょっと異常とも思えるくらいに公式のドキュメントが (Javadoc, マニュアルともに) 充実しています。わからない英単語は 英辞郎 で調べながら読めば意外となんとかなります。私のような、英語が万年赤点の学生生活を送ってきた人間でもなんとかなっていますので、臆することはないと思います。
そして、わかったことを blog などでアウトプットして頂けると、後続の方がちょっとだけ幸せになれるかもしれません。

*1:もちろん、Google などの検索エンジンも併用しつつ、です。

*2:とはいえ、これはどのフレームワークでも同じですね。