Springでは自動配線はどのように機能しますか?


510

コントロールIoC)の反転がでどのように機能するかについて、少し混乱していますSpring

インターフェースUserServiceImplを実装するサービスクラスが呼び出されたとしUserServiceます。

これはどうでしょう@Autowired

そして、私の中にControllers、どのようになり、私はこのサービスの?instantiateinstance

次のようにすればよいですか?

UserService userService = new UserServiceImpl();

回答:


703

まず、最も重要なことは、すべてのSpring Beanが管理されていることです。これらは、「アプリケーションコンテキスト」と呼ばれるコンテナ内で「ライブ」です。

次に、各アプリケーションにはそのコンテキストへのエントリポイントがあります。Webアプリケーションにはサーブレットがあり、JSFはel-resolverなどを使用します。また、アプリケーションコンテキストがブートストラップされ、すべてのBeanが自動接続される場所があります。Webアプリケーションでは、これはスタートアップリスナーになります。

自動配線は、あるBeanのインスタンスを別のBeanのインスタンスの目的のフィールドに配置することによって行われます。どちらのクラスもBeanである必要があります。つまり、アプリケーションコンテキストで実行されるように定義する必要があります。

アプリケーションのコンテキストで「生きている」とは何ですか?これは、コンテキストがあなたではなくオブジェクトをインスタンス化することを意味します。new UserServiceImpl()つまり、あなたが作ることは決してありません-コンテナは各注入ポイントを見つけ、そこにインスタンスを設定します。

コントローラーには、次のものがあります。

@Controller // Defines that this class is a spring bean
@RequestMapping("/users")
public class SomeController {

    // Tells the application context to inject an instance of UserService here
    @Autowired
    private UserService userService;

    @RequestMapping("/login")
    public void login(@RequestParam("username") String username,
           @RequestParam("password") String password) {

        // The UserServiceImpl is already injected and you can use it
        userService.login(username, password);

    }
}

いくつかのメモ:

  • では、applicationContext.xmlを有効にし<context:component-scan>て、クラス@Controller@Service、などの注釈がスキャンされるようにする必要があります。
  • Spring-MVCアプリケーションのエントリポイントはDispatcherServletですが、ユーザーからは隠されているため、アプリケーションコンテキストの直接の対話とブートストラップはバックグラウンドで行われます。
  • UserServiceImplアノテーション<bean id=".." class="..">を使用するか使用して、Beanとしても定義する必要があります@Service。の唯一の実装者UserServiceになるため、挿入されます。
  • @Autowiredアノテーションとは別に、SpringはXMLで構成可能な自動配線を使用できます。その場合、既存のBeanと一致する名前またはタイプを持つすべてのフィールドに、自動的にBeanが挿入されます。実際、これは自動配線の最初のアイデアでした。設定なしでフィールドに依存関係を挿入することです。以下のような他の注釈は@Inject@Resourceまた、使用することができます。

7
はい、UserServiceImplはServiceで注釈され、UserServiceはインターフェースです
Bozho

16
デフォルトのスコープはシングルトンなので、複数の場所に注入されるBeanのインスタンスは1つしかありません。スコープを「プロトタイプ」として明示的に定義すると、複数のインスタンスが存在し、おそらく(構成によっては)遅延します
Bozho

2
あなたの投稿に感謝します、それは本当に私にとって事をクリアしました。「それは唯一の実装者またはUserServiceになるため、挿入されます。」-Userserviceを実装するクラスが複数ある場合はどうなりますか?Springはどの実装を使用すべきかをどのようにして知るのですか?
獅子神2013

7
「プライマリ」として指定されたものがある場合は、それを使用します。それ以外の場合は例外がスローされます
Bozho 2013

3
いいえ、userServiceは1回だけ作成され、シングルトンスコープで作成されます
Bozho

64

アノテーションルートが必要か、Bean XML定義ルートが必要かによって異なります。

あなたがあなたの中で定義された豆を持っていたとしましょうapplicationContext.xml

<beans ...>

    <bean id="userService" class="com.foo.UserServiceImpl"/>

    <bean id="fooController" class="com.foo.FooController"/>

</beans>

アプリケーションの起動時に自動配線が行われます。したがって、ではfooController、引数のためにUserServiceImplクラスを使用したい場合、次のように注釈を付けます。

public class FooController {

    // You could also annotate the setUserService method instead of this
    @Autowired
    private UserService userService;

    // rest of class goes here
}

が見つかると@Autowired、Spring applicationContextはのプロパティに一致するクラスを探し、それを自動的に挿入します。複数のUserServiceBeanを使用している場合は、使用するBeanを限定する必要があります。

次の場合:

UserService service = new UserServiceImpl();

@Autowired自分で設定しない限り、はピックアップされません。


2
だから、定義するのに使用するものであるbean idにはapplicationContext.xml。タイプでuserService変数を定義する必要がありますUserService。では、なぜxmlファイルにエントリを作成するのか。
viper

20

@Autowired Spring 2.5で導入されたアノテーションであり、インジェクションにのみ使用されます。

例えば:

class A {

    private int id;

    // With setter and getter method
}

class B {

    private String name;

    @Autowired // Here we are injecting instance of Class A into class B so that you can use 'a' for accessing A's instance variables and methods.
    A a;

    // With setter and getter method

    public void showDetail() {
        System.out.println("Value of id form A class" + a.getId(););
    }
}

10
これはコンパイルされず、通常は正しくありません。@AutowiredBクラスからクラス内のすべての関数(メソッド)と変数を使用できる」という意味ではありませんA。何それがないことのインスタンスもたらしているAのインスタンスにしB、あなたが行うことができますa.getId()からB
ドミトリーミンコフスキー2015年

@dimadimaしたがって、もし彼がSystem.out.println( "ID form A classの値" + a.getId());を実行すると、実際に行ったのではなく、より正確になります。これは私には直感的に明らかであり、私の現在の理解レベルでは自動配線を説明しているので、返信してください。
John Doe


1
私がこれに慣れていないのでアンダースタディンを良くするには、@ autowiredがデフォルトのコンストラクタを使用してクラスAをインスタンス化しますか?そうでない場合、autowiredを使用する場合、値はBeanまたはサービスでインスタンス化されます。デフォルトのコンストラクターを呼び出す場合、なぜ最初に自動配線を使用するのか、A a = new A()を実行するだけです。どうか明らかにしてください?
2016年

@Sameer依存関係を自動配線することにより、フィールドのインスタンス化が自動的に行われるため、ユニットテストやコントローラー、サービス、Daoクラスに多くのボイラープレートコードを保存できます。コンストラクタを呼び出す必要はありません。
kiltek

9

@Autowired内部ではどのように機能しますか?

例:

class EnglishGreeting {
   private Greeting greeting;
   //setter and getter
}

class Greeting {
   private String message;
   //setter and getter
}

.xmlファイルを使用しない場合は、@Autowired次のようになります。

<bean id="englishGreeting" class="com.bean.EnglishGreeting">
   <property name="greeting" ref="greeting"/>
</bean>

<bean id="greeting" class="com.bean.Greeting">
   <property name="message" value="Hello World"/>
</bean>

あなたが使用している@Autowired場合:

class EnglishGreeting {
   @Autowired //so automatically based on the name it will identify the bean and inject.
   private Greeting greeting;
   //setter and getter
}

.xmlファイルを使用しない場合は、@Autowired次のようになります。

<bean id="englishGreeting" class="com.bean.EnglishGreeting"></bean>

<bean id="greeting" class="com.bean.Greeting">
   <property name="message" value="Hello World"/>
</bean>

まだ疑問がある場合は、ライブデモの下をご覧ください。

@Autowiredは内部的にどのように機能しますか?


6

サービスクラスUserServiceImplに注釈を付けるだけです。

@Service("userService")

Springコンテナーは、サービスとして登録するときに、このクラスのライフサイクルを処理します。

次に、コントローラーで自動配線(インスタンス化)してその機能を使用できます。

@Autowired
UserService userService;

3

Spring依存性注入は、クラスからカップリングを削除するのに役立ちます。このようなオブジェクトを作成する代わりに:

UserService userService = new UserServiceImpl();

DIを導入した後、これを使用します。

@Autowired
private UserService userService;

これを実現するには、ServiceConfigurationファイルにサービスのBeanを作成する必要があります。その後、そのServiceConfigurationクラスをクラスにインポートして、次のWebApplicationConfigurationようにそのBeanをコントローラーに自動配線できるようにする必要があります。

public class AccController {

    @Autowired
    private UserService userService;
} 

ここに例として、Java設定ベースのPOCがあり ます


1

標準的な方法:

@RestController
public class Main {
    UserService userService;

    public Main(){
        userService = new UserServiceImpl();
    }

    @GetMapping("/")
    public String index(){
        return userService.print("Example test");
    }
}

ユーザーサービスインターフェイス:

public interface UserService {
    String print(String text);
}

UserServiceImplクラス:

public class UserServiceImpl implements UserService {
    @Override
    public String print(String text) {
        return text + " UserServiceImpl";
    }
}

出力: Example test UserServiceImpl

これは密結合クラスの優れた例であり、設計例が悪いため、テストに問題があります(PowerMockitoも悪い)。

次に、疎結合の良い例であるSpringBoot依存性注入を見てみましょう。

インターフェースは変わりませんが、

メインクラス:

@RestController
public class Main {
    UserService userService;

    @Autowired
    public Main(UserService userService){
        this.userService = userService;
    }

    @GetMapping("/")
    public String index(){
        return userService.print("Example test");
    }
}

ServiceUserImplクラス:

@Component
public class UserServiceImpl implements UserService {
    @Override
    public String print(String text) {
        return text + " UserServiceImpl";
    }
}

出力: Example test UserServiceImpl

そして今、テストを書くのは簡単です:

@RunWith(MockitoJUnitRunner.class)
public class MainTest {
    @Mock
    UserService userService;

    @Test
    public void indexTest() {
        when(userService.print("Example test")).thenReturn("Example test UserServiceImpl");

        String result = new Main(userService).index();

        assertEquals(result, "Example test UserServiceImpl");
    }
}

私が示した@Autowiredコンストラクタに注釈をそれはまた、セッターまたはフィールド上で使用することができます。


0

制御の逆転の全体的な概念は、オブジェクトを手動でインスタンス化してすべての必要な依存関係を提供するという面倒から解放されることを意味します。クラスに適切な注釈(例:)を付けると、@ServiceSpringは自動的にオブジェクトをインスタンス化します。アノテーションに慣れていない場合は、代わりにXMLファイルを使用することもできます。ただし、Spring newコンテキスト全体をロードしたくない場合は、ユニットテストで手動で(キーワードを使用して)クラスをインスタンス化することをお勧めします。


0

Spring 構成ファイルに@Autowired要素<context:annotation-config/>を追加してアノテーションを有効にする必要があることに注意してください。これはAutowiredAnnotationBeanPostProcessor、アノテーションの処理を処理するを登録します。

そして、フィールドインジェクション方式を使用してサービスを自動配線できます。

public class YourController{

 @Autowired
 private UserService userService; 

}

私はこれをSpring @autowiredアノテーションの投稿から見つけました


0

を使用してインスタンスを作成する方法は3つあります@Autowired

1. @Autowiredプロパティについて

アノテーションはプロパティで直接使用できるため、ゲッターとセッターの必要がなくなります。

    @Component("userService")
    public class UserService {

        public String getName() {
            return "service name";
        }
    }

    @Component
    public class UserController {

        @Autowired
        UserService userService

    }

上記の例では、Springはが作成されたuserServiceときに検索して注入しUserControllerます。

2. @Autowiredセッターについて

@Autowired注釈は、setterメソッドで使用することができます。以下の例では、setterメソッドでアノテーションが使用されている場合、setterメソッドはuserServicewhen UserControllerが作成されたときのインスタンスで呼び出されます。

public class UserController {

    private UserService userService;

    @Autowired
    public void setUserService(UserService userService) {
            this.userService = userService;
    }
}

3. @Autowiredコンストラクタについて

@Autowired注釈はまた、コンストラクタで使用することができます。以下の例では、アノテーションがコンストラクターで使用されている場合、のインスタンスが作成userService時にコンストラクターへの引数として挿入されますUserController

public class UserController {

    private UserService userService;

    @Autowired
    public UserController(UserService userService) {
        this.userService= userService;
    }
}

0

簡単に言えば、自動配線、つまり自動的にリンクを配線することですが、これを誰がどのような種類の配線で行うかという問題が生じます。答えは次のとおりです。コンテナがこれを行い、セカンダリタイプの配線がサポートされます。プリミティブは手動で実行する必要があります。

質問:コンテナはどのようなタイプの配線をどのようにして知るのですか?

回答:これをbyType、byName、constructorと定義します。

質問:自動配線のタイプを定義しない方法はありますか?

回答:はい、@ Autowiredという1つのアノテーションを実行することで実現します。

質問:しかし、システムはどのようにしてこのタイプの二次データを選択する必要があるのでしょうか

回答:そのデータをspring.xmlファイルで提供するか、クラスにsterotypeアノテーションを使用して、コンテナー自体がオブジェクトを作成できるようにします。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.