春とは?Javaのコンポーネントベースの開発

春はおそらく21世紀の変わり目に出現したコンポーネントベースのフレームワークの中で最高です。これにより、開発者がJavaベースのアプリケーションでインフラストラクチャコードを記述および提供する方法が大幅に改善されます。Springは、創業以来、エンタープライズJava開発の主要なフレームワークとして認識されてきました。エンドツーエンドのアプリケーションフレームワークとして、SpringはJava EE機能の一部を反映していますが、他では見られない機能とプログラミング規則の組み合わせを提供します。

この記事では、Springとそのコアプログラミング哲学および方法論を紹介します:制御の反転と依存性注入。また、Springアノテーションといくつかの実践的なコーディング例から始めます。

依存性注入と制御の反転

Springの中心的な考え方は、オブジェクトの関係を自分で管理する代わりに、それらをフレームワークにオフロードすることです。制御の反転(IOC)は、オブジェクトの関係を管理するために使用される方法論です。依存性注入は、IOCを実装するためのメカニズムです。これらの2つの概念は関連していますが異なるため、さらに詳しく検討してみましょう。

  • 制御の反転(IOC)は、その名前が示すとおりに機能します。つまり、オブジェクトの関係を実現するための制御の従来の階層を反転します。オブジェクトが相互にどのように関係するかを定義するためにアプリケーションコードに依存する代わりに、関係はフレームワークによって定義されます。方法論として、IOCはオブジェクト関係に一貫性と予測可能性を導入しますが、開発者として、きめ細かい制御をあきらめる必要があります。
  • 依存性注入(DI)は、フレームワークが依存性をアプリに「注入」するメカニズムです。これはIOCの実用的な実装です。依存性注入は、フレームワークの構成に基づいて参照型の履行を変更できるという意味で、ポリモーフィズムに依存します。フレームワークは、アプリケーションコードで変数参照を手動で実行するのではなく、変数参照を挿入します。

JSR-330

Javaの世界の多くと同様に、実際のイノベーションとして始まったSpringは、標準仕様に部分的に吸収されています。この場合、JSR-330がJava標準です。JSR-330仕様の良いところは、他の場所で使用でき、Spring以外の場所でも使用できることです。Springを使わなくても使えます。しかし、Springはさらに多くのことをテーブルにもたらします。

例1:Spring依存性注入

制御の反転と依存性注入は、それらを使用することで最もよく理解できるため、簡単なプログラミング例から始めます。

車をモデリングしているとしましょう。プレーンオールドJavaでモデリングしている場合は、リスト1に示すようにCarEngineインターフェイスを参照するためのインターフェイスメンバーがクラスにある可能性があります。

リスト1.プレーンオールドJavaのオブジェクト関係

 public Interface Engine() { ... } public class Car { private Engine engine; public Engine getEngine() { ... } public void setEngine(Engine engine) { ... } } 

リスト1には、Engine型のインターフェースとCar、を参照する具象型のクラスが含まれていますEngine。(実際のプログラミングシナリオでは、これらは別々のファイルにあることに注意してください。)ここで、Carインスタンスを作成するときに、リスト2に示すように関連付けを設定します。

リスト2.エンジンインターフェースを使用して車を作成する

 // ... Car newCar = new Car(); Engine sixCylEngine = new InlineSixCylinderEngine(); newCar.setEngine(sixCylEngine ); // Do stuff with the car 

Car最初にオブジェクトを作成することに注意してください。次に、Engineインターフェイスを満たす新しいオブジェクトを作成し、それをオブジェクトに手動で割り当てCarます。これが、プレーンオールドJavaでのオブジェクトの関連付けの仕組みです。

Springでのクラスとオブジェクトのモデリング

それでは、Springの同じ例を見てみましょう。ここでは、リスト3に示すようなことを行うことができます。Carクラスから始めますが、この場合は、クラスに注釈を追加します@Inject

リスト3.Springで@Injectアノテーションを使用する例

 public class Car { @Inject private Engine engine; // ... } 

@Injectアノテーションを使用すると(または@Autowired、必要に応じて)、一連のルールに基づいて、コンテキストを検索し、オブジェクトを参照に自動的に挿入するようにSpringに指示します。

次に、@Componentリスト4に示す注釈について考えます。

リスト4. @ Componentアノテーション

 @Component public class InlineSixCylinderEngine implements Engine{ //... } 

クラスに注釈を付けると、@ComponentSpringはインジェクションを実行できることを通知します。この場合、InlineSixCylEngineが使用可能であり、関連付けのインターフェイス要件を満たしているため、が注入されます。春には、これは「自動配線」注入と呼ばれます。(Springの@Autowired注釈の詳細については、以下を参照してください。)

設計原理としてのデカップリング

依存性注入による制御の反転は、コードから具体的な依存性のソースを削除します。プログラムのどこにも、Engine実装へのハードコードされた参照はありません。これは、ソフトウェア設計の原則としてのデカップリングの例です。アプリケーションコードを実装から切り離すことで、コードの管理と保守が容易になります。アプリケーションは、そのパーツがどのように組み合わされているかについてはあまり知りませんが、アプリケーションのライフサイクルのどの時点でも変更を加えるのははるかに簡単です。

@Autowired vs @Inject

@Autowiredそして、@Inject同じことを行います。ただし、これ@InjectはJava標準アノテーションですが、@AutowiredSpringに固有です。これらは両方とも、一致するオブジェクトをフィールドまたはメソッドに挿入するようにDIエンジンに指示するという同じ目的を果たします。春にはどちらでも使えます。

Springフレームワークの概要

Springコードをいくつか見てきたので、フレームワークとそのコンポーネントの概要を見てみましょう。ご覧のとおり、フレームワークは4つのメインモジュールで構成されており、パッケージに分割されています。Springは、使用するモジュールにかなりの柔軟性をもたらします。

  • コアコンテナ
    • 環境
    • 表現言語
  • アスペクト指向プログラミング(AOP)
    • AOP
    • 側面
    • 計装
  • データアクセスと統合
    • JDBC
    • JPA / ORM
    • JMS
    • トランザクション
  • ウェブ
    • Web / REST
    • サーブレット
    • ストラット

ここですべてをカバーするのではなく、より一般的に使用される2つのSpring機能から始めましょう。

新しいプロジェクトの開始:Spring Boot

We'll use Spring Boot to create an example project, which we'll use to demo Spring features. Spring Boot makes starting new projects much easier, as you'll see for yourself. To begin, take a look at the main class shown below. In Spring Boot, we can take a main class with a main() method, and then choose to run it standalone, or package for deployment in a container like Tomcat.

Listing 5 has the outlines of our main class, which will live at the standard src/main/java/hello location.

Listing 5. Main class with Spring Boot

 package hello; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } 

Note two things about the above code: First, all of the work is abstracted into the framework. The main class boots up the app, but it doesn't know anything about how the app works or delivers its functionality. Second, the SpringApplication.run() does the actual job of booting the app and passing in the Application class itself. Again, the work the app does is not apparent here.

The @SpringBootApplication annotation wraps up a few standard annotations and tells Spring to look at the package where the main class exists for components. In our previous example, with the car and engine, this would allow Spring to find all classes annotated with @Component and @Inject. The process itself, called component scanning, is highly customizable.

You can build the app with the standard mvn clean install, and you can run it with the Spring Boot goal (mvn spring-boot:run). Before doing that, let's look at this application's pom.xml file.

Listing 6. Starter pom.xml

 com.javaworld what-is-spring 1.0.0  org.springframework.boot spring-boot-starter-parent 2.1.3.RELEASE     1.8     org.springframework.boot spring-boot-maven-plugin    

Note two important features in the above code:

  1. The parent element relies on the spring-boot-starter-parent project. This parent project defines a number of useful defaults, such as the default compiler level of JDK 1.8. For the most part, you can just trust that it knows what it's doing. As an example, you can omit the version number for many common dependencies, and SpringBootParent will set the versions to be compatible. When you bump up the parent's version number, the dependency versions and defaults will also change.
  2. The spring-boot-maven-plugin allows for the executable JAR/WAR packaging and in-place run (via the mvn spring-boot:run command).

Adding Spring Web as a dependency

So far, we've been able to use spring-boot to limit how much work we put in to get an app up and running. Now let's add a dependency and see how quickly we can get something in a browser.

Listing 7. Adding Spring Web to a project

  org.springframework.boot spring-boot-starter-web  

Note

Spring will automatically detect what files have changed and compile accordingly. You can just execute mvn spring-boot:run to pickup changes.

Now that we've got a basic project setup, we're ready for our two examples.

Example #2: Building RESTful endpoints with Spring Web

We've used spring-boot-starter-web to bring in several dependencies that are useful for building web applications. Next we'll create a route handler for a URL path. Spring's web support is part of the Spring MVC (Model-View-Controller) module, but don't let that worry you: Spring Web has full and effective support for building RESTful endpoints, as well.

The class whose job it is to field URL requests is known as a controller, as shown in Listing 8.

Listing 8. Spring MVC REST controller

 package hello; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RequestParam; @Controller public class GreetingController { @RequestMapping(value = "/hi", method = RequestMethod.GET) public String hi(@RequestParam(name="name", required=false, defaultValue="JavaWorld") String name, Model model) { return "Hello " + name; } } 

The @Controller annotation

The @Controller annotation identifies a class as a controller. A class marked as a controller is also automatically identified as a component class, which makes it a candidate for auto-wiring. Wherever this controller is needed, it will be plugged into the framework. In this case, we'll plug it into the MVC system to handle requests.

The controller is a specialized kind of component. It supports the @RequestMapping and @ResponseBody annotations that you see on the hi() method. These annotations tell the framework how to map URL requests to the app.

At this point, you can run the app with mvn spring-boot:run. When you hit the /hi URL, you'll get a response like "Hello, JavaWorld."

Notice how Spring has taken the basics of autowiring components, and delivered a whole web framework. With Spring, you don't have to explicitly connect anything together!

The @Request annotations

The @RequestMapping allows you to define a handler for a URL path. Options include defining the HTTP method you want, which is what we've done in this case. Leaving RequestMethod off would instruct the program to handle all HTTP method types.

The @RequestParam argument annotation allows us to map the request parameters directly into the method signature, including requiring certain params and defining default values as we've done here. We can even map a request body to a class with the @RequestBody argument annotation.

REST and JSON response

RESTエンドポイントを作成していて、メソッドからJSONを返したい場合は、メソッドに@ResponseBody。という注釈を付けることができます。その後、応答は自動的にJSONとしてパッケージ化されます。この場合、メソッドからオブジェクトを返します。

SpringWebでのMVCの使用

Strutsと同様に、SpringWebモジュールは真のmodel-view-controllerセットアップに簡単に使用できます。その場合、指定されたテンプレート言語(Thymeleafなど)でマッピングを返し、Springがマッピングを解決し、渡したモデルを提供して、応答をレンダリングします。

例3:JDBCを使用したSpring

それでは、リクエストハンドラを使ってもっと面白いことをしましょう。データベースからデータを返しましょう。この例では、H2データベースを使用します。ありがたいことに、SpringBootはインメモリH2DBをすぐにサポートします。