2016-05-23 9 views
1

従来のSpring DIベースのアプリケーションでは、application.xmlファイルを定義し、必要に応じてBeanを配線します。あなたのメインクラスでは、ApplicationContext(それらの配線で構成されています)をつかむことも、クラスを作ることさえできます。ApplicationContextAware例によるGroovyベースのSpringブートDI

しかし、Spring Bootではすべてが変わったようです。起動すると、クラスに@Componentという注釈を付けるように見えますが、本当に良い例を見つけることができませんでした。さらに、依存するBeanと異なるクラスまたはコンポーネントの異なるインスタンスが存在するシナリオ、または@CanonicalのようなGroovyismで@Componentベースの注入がどのように動作するかについての解決策はありません。だから私は、私は具体的な例から始めて、誰もが正しい方向に私を指すことができるかどうかと考えました。

// Groovy pseudo-code 
@Canonical 
class Fizz { 
    boolean checked 
    String umberGUID 
} 

@Canonical 
class Buzz { 
    Fizz fizz // # always use Fizz instance #1 for all Buzz instances 
    int value 
} 

@Canonical 
class Widget { 
    Fizz fizz // always use Fizz instance #2 for all Widget instances 
    String magicNumber // we need to define and wire a different magic number into each Widget instance 
} 

=== 
The example below is how I would accomplish dependency injection in Guice 
using the classes and constraints above: 
=== 
@Canonical 
class Fizz { 
    @Inject @Named('checked') 
    boolean checked 

    @Inject @Named('umberGUID') 
    String umberGUID 
} 

@Canonical 
class Buzz { 
    @Inject @Named('buzz_fizz') 
    Fizz fizz 

    @Inject @Named('buzz_value') 
    int value 
} 

@Canonical 
class Widget { 
    @Inject @Named('widget_fizz') 
    Fizz fizz 

    @Inject @Named('magic_number') 
    String magicNumber 
} 

class MyGuiceModule extends AbstractModule { 
    @Override 
    void configure() { 
    } 

    // I wont write Provider methods for everything above, just showing 
    // 2 here as as an example. 
    @Provides @Named('buzz_fizz') 
    Fizz provideBuzzFizz() { 
     new Fizz(true, 'A', null) 
    } 

    @Provides @Named('widget_fizz') 
    Fizz provideWidgetFizz() { 
     new Fizz(false, 'D', 'blue') 
    }   
} 

どのように私は春ブーツで互いにこれらのBeanをアップ配線でしょうか?最終的な結果は、たとえば、HerpDerpのようないくつかの第4クラスのWidgetインスタンスにアクセスし、Widgetインスタンスにfizz/magicNumberフィールドが正しく挿入されている必要があります。その答えがもっと情報を必要とするならば、私は何かを鞭打ちして喜んで、頼むだけです!

+1

春と春のブートプロジェクトには、いくつかの最高のドキュメントがあります。 DIセクションを読むことから始めることをお勧めします。また、GitHubリポジトリに含まれている多数のサンプルプロジェクトを指摘しています。 – cjstehno

+0

closevote @cjstehno(+1)に感謝しますが、この質問はSpring DI ** + Groovy **、特に '@ Canonical'の使用に関するものです。私はすでに読んだことをもとにして、ドキュメントから抽出したものを説明して研究を示しました。この質問は**詐欺ではなく、[SSCCE](http://sscce.org)ですので、クローズ投票をお控えください!ドキュメントには、私の特定の問題をどのように解決するかについてのヒント*が含まれていますが、具体的なものはありません。 – smeeb

+1

@smeebので、あなたの質問にいくつかの点が不明です。 1)あなたの質問で '@ Canonical'の妥当性は何ですか? '@ Canonical'は、いくつかの他のGroovyアノテーション、@EqualsAndHashCode、@ToStringおよび@TupleConstructorアノテーションを組み合わせた複合アノテーションです。これらのすべては、equalsおよびhashCode、toStringメソッド、およびデフォルトコンストラクタのデフォルト実装を作成するだけです。その影響はなく、Spring/Spring Bootに関連しています。 – pczeus

答えて

1

これはSpringBootやGroovyの機能に依存する質問ではありませんが、Springに関する質問やXMLベースの設定の違いはどういう意味ですか:application.xml、対Javaベースのコンフィグレーション、および/または@Componentのような注釈の使用を使用します。

ドキュメントを探しているなら、Javaベースの設定に関するSpringのドキュメントを参考にして、ほとんどの情報を得ることができます。良いスタートは5.12.1 Basic concepts: @Bean and @Configurationです。

あなたの質問へのコメントで述べたように、私は@Canonical注釈がこれに全く影響しないと思います。 @Canonicalは、単純に複合アノテーションであり、一般的に使用されるメソッドをGroovyクラスに自動的に生成するために使用されます。具体的には、@Canonical GroovyDocに直接述べたように:

@Canonicalメタアノテーションは@EqualsAndHashCode、@ToStringと@TupleConstructor注釈を組み合わせます。これは、可変クラスの作成を支援するために使用されます。これは、位置コンストラクター、equals、hashCode、およびかなりのtoStringをあなたのクラスに追加するAST変換を実行するようにコンパイラーに指示します。

Java、Spring、Groovy、またはSpring Bootのいずれを使用しているかにかかわらず、Beanのアプリケーションへの接続方法には影響しません。

これらのことはすべて、Spring BootとGroovyを使用してどのように要件を達成すると思いますか?

具体的な例を挙げて説明するとよいでしょう。 良い例を提供するために、ビルドツールとしてGradleを使用し、選択言語としてGroovyを使用して、Test SpringBootプロジェクトを作成しました。この例では、Groovyクラスをcom.app.bootinjectionパッケージに配置しています。ここでは、フォルダやパッケージ構造を示すスクリーンショットである:

buildscript { 
    ext { 
     springBootVersion = '1.3.1.RELEASE' 
    } 
    repositories { 
     jcenter() 
     mavenCentral() 
    } 
    dependencies { 
     classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") 
    } 
} 

apply plugin: 'groovy' 
apply plugin: 'idea' 
apply plugin: 'spring-boot' 

repositories { 
    jcenter() 
    mavenCentral() 
} 

dependencies { 
    compile('org.codehaus.groovy:groovy-all:2.4.5') 
    compile('org.springframework.boot:spring-boot-starter-web') 
    compile('org.apache.tomcat.embed:tomcat-embed-jasper:8.0.30') 
    compile('com.fasterxml.jackson.core:jackson-core:2.7.1') 
    compile('com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.7.1') 
} 

springBoot{ 
    mainClass = 'com.app.Application' 
} 
task wrapper(type: Wrapper) { 
    gradleVersion = '2.9' 
} 

注:私は、次の内容を画像で見られるbuild.gradleファイルを、

enter image description here

アプリケーションを構築するために作成しましたbuild.gradleファイルで、私は2つのコンパイル時の依存関係をJacksonライブラリに追加しました。 JSON出力をサポートする 'core'ライブラリ、ブラウザのようなクライアントでJSON出力をうまくフォーマットする 'dataformat'ライブラリ。

Application.groovy:

これはSpringBootアプリケーションをすることですので

、私はmainメソッドが含まれており、我々のアプリケーションを起動する@SpringBootApplicationアノテーションを付け、簡単なApplicationクラスを作成しましたFizzBuzzWidgetHerpDerp

package com.app 

import org.springframework.boot.SpringApplication 
import org.springframework.boot.autoconfigure.SpringBootApplication 
import org.springframework.context.ApplicationContext 

@SpringBootApplication 
public class Application { 

    public static void main(String[] args) { 
     ApplicationContext ctx = SpringApplication.run(Application.class, args) 
    } 
} 
は、私はまた、あなたの質問に記載された各クラスのGroovyのクラス代表を作成しました。それぞれには、 @Canonical注釈と @Component注釈の両方で注釈が付けられます。コンポーネントのスキャンが完了すると、Springは @Componentアノテーションを参照し、デフォルトではそのクラスの単一の(シングルトンのような)インスタンスを構築し、Beanとして登録します。デフォルトでは、Beanの名前はクラスの名前と同じになり、クラス名の最初の文字はケース下部になります。したがって、 FizzクラスはBeanとしてインスタンス化され、Bean名 'fizz'の下に登録されます。詳細については、 Section 5.10.1 @ComponentのSpringドキュメントを参照してください。ちなみに、 @Scope(value = "prototype")を使用して、注入するたびに作成された新しいものを持つようにBeanの 'スコープ'を変更することができます。しかし、絶対に必要な場合にのみそれを行うことをお勧めします。

Fizz.groovy:

package com.app.bootinjection 

import groovy.transform.Canonical 
import org.springframework.stereotype.Component 

@Canonical 
@Component 
class Fizz { 
    boolean checked 
    String umberGUID = 0 
} 

注:私はデモ/出力のために0の値にumberGUIDをデフォルトとしています。

Buzz.groovy:

package com.app.bootinjection 

import groovy.transform.Canonical 
import org.springframework.stereotype.Component 

import javax.annotation.Resource 

@Canonical 
@Component 
class Buzz { 
    @Resource 
    Fizz fizz1 
    int value 
} 

Widget.groovy:

package com.app.bootinjection 

import groovy.transform.Canonical 
import org.springframework.stereotype.Component 

import javax.annotation.Resource 

@Component 
@Canonical 
class Widget { 
    @Resource 
    Fizz fizz2 

    @Resource 
    Buzz buzz 

    @Resource 
    String magicalNumber 
} 

HerpDerp.groovy:

package com.app.bootinjection 

import groovy.transform.Canonical 
import org.springframework.stereotype.Component 

import javax.annotation.Resource 

@Component 
@Canonical 
class HerpDerp { 
    @Resource 
    Widget widget 

    @Resource 
    Fizz fizz 
} 

注豆を私たちのオブジェクトに注入するための@Resourceの使用。私たちのプロジェクトでは、最初に@Autowiredから@Injectに、そして@Resourceというアノテーションに切り替えました。ほとんどの場合、私たちは@Resourceがより適切であり、私たちのプロジェクトでより頻繁に働くことを発見しました。たとえば、クラスBuzzFizz fizz1の宣言に注意してください。 @Resourceを使用して、適切なインスタンスFizzを挿入します。ここでは、Bean名はfizz1と一致します。なぜどちらかを使用する際に/上より明確にするため、州春のドキュメントのセクション5.9.3を参照してください:

あなたが名前で、アノテーション駆動型の注入を表現する場合

ヒント

、しないでください技術的に@Qualifier値によってBean名を参照できる場合でも、主に@Autowiredを使用します。代わりに、JSR-250 @Resource注釈を使用します。これは、特定のターゲットコンポーネントを固有の名前で識別するために意味的に定義されています。宣言されたタイプは、マッチングプロセスとは関係ありません。

この意味の違いの特定の結果として、コレクションまたはマップタイプとして定義されたBeanは、@Autowiredを通じて注入できません。タイプマッチングが適切に適用されないためです。このようなBeanには@Resourceを使用し、特定のコレクションまたはマップBeanを一意の名前で参照します。

@Autowiredは、フィールド、コンストラクタ、および複数引数のメソッドに適用され、パラメータレベルで修飾子注釈を絞り込むことができます。対照的に、@Resourceは単一の引数を持つフィールドとBeanのプロパティ設定メソッドに対してのみサポートされています。したがって、注入ターゲットがコンストラクタまたは複数引数のメソッドの場合は、修飾子を使用してください。

私はどのようにして同じインスタンスの複数の豆を異なる名前で宣言しますか?@Component注釈だけを使用して、クラスのインスタンスを1つ作成して、クラス名(最初の文字は小文字)にデフォルト設定することができます。 @Componentを使用するときに、デフォルトを上書きする名前を指定することもできます。例:@Component("myBean")。それでも、1つのインスタンスが作成されます。前述のように、@Scope("prototype")アノテーションを使用して 'スコープ'を指定することもできます。さて、Beanが注入されるたびに、新しいインスタンスが作成され注入されます。

作成するBeanの数を制御し、固有の名前を指定し、固有の名前を挿入する場合は、より構成可能な解決策が必要です。 XML構成と比較した場合の好ましい解決策は、Javaベースのソリューションです。任意のクラスを作成し、@Configuration注釈を使用して設定して、Springにこのクラスが設定情報を提供することを示すことができます。この例では、私はApplicationConfigurationクラスを作成しました:

ApplicationConfiguration.groovy:FIZZ1とfizz2:

package com.app 

import com.app.bootinjection.Fizz 
import org.springframework.context.annotation.Bean 
import org.springframework.context.annotation.Configuration 

@Configuration 
class ApplicationConfiguration { 

    @Bean 
    Fizz fizz1(){ 
     new Fizz(checked: true, umberGUID: 1) 
    } 

    @Bean 
    Fizz fizz2(){ 
     new Fizz(checked: false, umberGUID: 2) 
    } 

    @Bean 
    @Scope("prototype") 
    String magicNumber(){ 
     System.currentTimeMillis() 
    } 
} 

を構成では、我々は2つのユニークフィズインスタンスを作成するためのFizzクラスの2つの方法を作成します。メソッドの名前はBeanの名前になりますので、メソッドfizz1()fizz2)です。また、それぞれのインスタンスが1つだけ作成されることにも注意してください。 SpringはBeanをインスタンス化し、それぞれのインスタンスを1つだけ作成します。あなたはBuzzクラスに戻って見れば

は今、あなたは私たちが、構成クラスで宣言されたBean名と一致するBean名fizz1を、一致するFizzクラスのインスタンスを注入する@Resourceアノテーションを使用していることがわかります。同じことがについてはWidgetに該当します。また、デモンストレーションの目的で、fizzと呼ばれるHerpDerpクラスにFizzインスタンスも挿入することに注意してください。クラスに@Componentと注釈を付けたので、Springがコンポーネントスキャンを実行すると、注釈付きクラスが表示され、デフォルトでfizzの別のインスタンスが作成されます。

コンフィグレーションクラスでは、magicNumber()という@Beanというアノテーションが付いた別のBeanメソッドがあります。私たちは毎回ユニークな魔法の数字を注入したいので、その豆にプロトタイプ:Scope("prototype")のスコープを付けて注釈を付けました。次いで、タイプStringの豆を、必要に応じてWidgetクラスに注入する。

最後に、すべてをまとめて、私は単純にHerpDerpのBeanインスタンスを挿入して返すREST Webサービスコントローラを作成しました。そしてそれをJSONにシリアル化して、期待される出力を示します。結果はhttp://localhost:8080にアクセスして見られる:

TestController.groovy:私はこれをカバーし、包括的なデモであることが証明さを願ってい

<HerpDerp xmlns=""> 
    <widget> 
     <fizz2> 
      <checked>false</checked> 
      <umberGUID>2</umberGUID> 
     </fizz2> 
     <buzz> 
      <fizz1> 
       <checked>true</checked> 
       <umberGUID>1</umberGUID> 
      </fizz1> 
      <value>0</value> 
     </buzz> 
     <magicalNumber>1464240486303</magicalNumber> 
    </widget> 
    <fizz> 
     <checked>false</checked> 
     <umberGUID>0</umberGUID> 
    </fizz> 
</HerpDerp> 

package com.app.bootinjection 

import org.springframework.web.bind.annotation.RequestMapping 
import org.springframework.web.bind.annotation.RestController 

import javax.annotation.Resource 

@RestController 
class TestController { 
    @Resource 
    HerpDerp herpDerp 

    @RequestMapping("/") 
    def index(){ 
     [herpDerp] 
    } 
} 

の結果として出力してあなたが達成しようとしているトピック。 Spring/SpringBootは、探している結果を簡単に生成することができます。がんばろう!

+0

素晴らしい、すばらしい、素晴らしい答え@pczeus(+1) - 私はこれ以上upvoteできればいいと思う!!! 2つの素早く(うまくいけば)質問:**(1)** '@ Component'で注釈付けされていないクラスの中にあるプロパティで' @ Resource'アノテーションを使用するとどうなりますか?エラー?あるいは、春はそれらの注射を無視するだけですか?そして**(2)**すべての*クラスに '@ Component'を注釈を付ける必要がありますか、それとも" *ちょっと、春、DIを使ってすべてのクラスをリストアップするか、 XYZパッケージ?* "もう一度ありがとう! – smeeb

+0

質問に答えるには1) - Springに登録されたBeanではない '@ Resource'を持つクラスに注釈を付けることは単に無視され、プロパティは注入されません。もちろん、それが注入されて利用可能になると思っていた場合は、nullポインタやその他の問題が発生する可能性があります。明示的なエラーは生成されないので、注意してください。 – pczeus

+0

2)私は、すべてのクラスのBeanを作成したり、パッケージを指定したりするためにSpringが提供するメカニズムは見当たりません。これは意図的であり、理にかなっています。作成されるすべてのBeanはメモリに格納されたシングルトンです。そこでSpringはこれを意図的に行うので、豆が不必要に作成されて明示的に処理されることはありません。 Springは、Beanを手動で登録できるようにするAPIを提供しています。したがって、これはカスタム方法で実行できます。しかし、私はそれをどうやって行うのか、それが可能なのかについての詳細はここに入れることが広く、別の質問であるべきだと思います。あなたのものは特別なケースであり、どこでそれをしたいのか分かります。 – pczeus

関連する問題