Apa itu Spring? Pembangunan berasaskan komponen untuk Java

Musim bunga mungkin yang terbaik dari kerangka kerja berasaskan komponen yang muncul pada pergantian abad ke-21. Ini sangat meningkatkan cara pemaju menulis dan menyampaikan kod infrastruktur dalam aplikasi berbasis Java. Sejak dimulakan, Spring telah diakui sebagai kerangka utama pengembangan Java perusahaan. Sebagai kerangka aplikasi end-to-end, Spring mencerminkan beberapa kemampuan Java EE, tetapi menawarkan kombinasi ciri dan konvensyen pengaturcaraan yang tidak akan anda temukan di tempat lain.

Artikel ini memperkenalkan Spring dan falsafah dan metodologi pengaturcaraan utamanya: Pembalikan kawalan dan suntikan kebergantungan. Anda juga akan memulakan dengan anotasi Spring dan beberapa contoh pengekodan langsung.

Suntikan ketergantungan dan pembalikan kawalan

Idea utama Spring adalah bahawa daripada menguruskan hubungan objek dengan diri sendiri, anda membuangnya ke kerangka kerja. Inversion of control (IOC) adalah metodologi yang digunakan untuk menguruskan hubungan objek. Suntikan ketergantungan adalah mekanisme untuk melaksanakan IOC. Oleh kerana kedua-dua konsep ini saling berkaitan tetapi berbeza, mari kita mempertimbangkannya dengan lebih dekat:

  • Inversion of control (IOC) melakukan apa yang disebut namanya: ia membalikkan hierarki kawalan tradisional untuk memenuhi hubungan objek. Daripada bergantung pada kod aplikasi untuk menentukan bagaimana objek saling berkaitan, hubungan ditentukan oleh kerangka kerja. Sebagai metodologi, IOC memperkenalkan konsistensi dan kebolehprediksi terhadap hubungan objek, tetapi ia memerlukan anda, sebagai pembangun, untuk melepaskan beberapa kawalan yang terperinci.
  • Suntikan ketergantungan (DI) adalah mekanisme di mana kerangka kerja "menyuntikkan" kebergantungan ke dalam aplikasi anda. Ini adalah pelaksanaan praktikal IOC. Suntikan ketergantungan bergantung pada polimorfisme, dalam arti bahawa ia memungkinkan pemenuhan jenis rujukan untuk berubah berdasarkan konfigurasi dalam kerangka. Rangka kerja menyuntikkan rujukan yang berubah-ubah dan bukannya memenuhi syarat secara manual dalam kod aplikasi.

JSR-330

Seperti banyak di dunia Jawa, apa yang dimulai sebagai inovasi liar, Spring, sebagian telah diserap oleh spesifikasi standard. Dalam kes ini, JSR-330 adalah standard Java. Perkara yang baik mengenai spesifikasi JSR-330 adalah anda boleh menggunakannya di tempat lain, dan akan melihatnya digunakan di tempat lain, di luar Spring. Anda boleh menggunakannya tanpa menggunakan Spring. Walau bagaimanapun, Spring membawa lebih banyak perkara ke meja.

Contoh # 1: Suntikan pergantungan musim bunga

Inversi kawalan dan suntikan kebergantungan difahami dengan sebaiknya dengan menggunakannya, jadi kita akan mulakan dengan contoh pengaturcaraan cepat.

Katakan anda memperagakan kereta. Sekiranya anda membuat pemodelan di Java lama biasa, anda mungkin mempunyai anggota antarmuka di Carkelas untuk merujuk Engineantarmuka, seperti yang ditunjukkan dalam Penyenaraian 1.

Penyenaraian 1. Hubungan objek di Jawa lama

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

Penyenaraian 1 mengandungi antara muka untuk Enginejenis, dan kelas untuk Carjenis konkrit , yang merujuk pada Engine. (Perhatikan bahawa dalam senario pengaturcaraan yang sebenarnya ini akan berada dalam file terpisah.) Sekarang, ketika Anda membuat Carinstance, Anda akan menetapkan hubungan seperti yang ditunjukkan dalam Penyenaraian 2.

Penyenaraian 2. Membuat Kereta dengan antara muka Engine

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

Perhatikan bahawa anda membuat Carobjek terlebih dahulu. Anda kemudian membuat objek baru yang memenuhi Engineantara muka, dan menetapkannya secara manual ke Carobjek tersebut. Begitulah cara kerja persatuan objek di Jawa lama.

Kelas pemodelan dan objek pada musim bunga

Sekarang mari kita lihat contoh yang sama di Spring. Di sini, anda boleh melakukan sesuatu seperti apa yang ditunjukkan di dalam Senarai 3. Anda bermula dengan Carkelas, tetapi dalam kes ini anda menambah anotasi kepadanya: @Inject.

Penyenaraian 3. Contoh penggunaan anotasi @Inject pada Spring

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

Menggunakan @Injectanotasi (atau @Autowired, jika anda suka) memberitahu Spring untuk mencari konteks dan memasukkan objek secara automatik ke dalam rujukan, berdasarkan sekumpulan peraturan.

Seterusnya, pertimbangkan @Componentanotasi yang ditunjukkan dalam Penyenaraian 4.

Penyenaraian 4. @ anotasi Komponen

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

Mengelaskan kelas dengan @Componentmemberitahu Spring bahawa ia tersedia untuk memenuhi suntikan. Dalam kes ini, InlineSixCylEngineia akan disuntik kerana tersedia dan memenuhi keperluan antara muka persatuan. Pada musim bunga, ini dipanggil suntikan "autowired". (Lihat di bawah untuk maklumat lanjut mengenai @Autowiredanotasi Spring .)

Pecahan sebagai prinsip reka bentuk

Pembalikan kawalan dengan suntikan ketergantungan menghilangkan sumber kebergantungan konkrit dari kod anda. Di mana-mana program tidak ada rujukan keras Enginepelaksanaannya. Ini adalah contoh penyahpasangan sebagai prinsip reka bentuk perisian. Memisahkan kod aplikasi dari pelaksanaan menjadikan kod anda lebih mudah diurus dan dikendalikan. Aplikasi tahu lebih sedikit mengenai bagaimana bahagiannya bersatu, tetapi lebih mudah untuk membuat perubahan pada bila-bila masa dalam kitaran hayat aplikasi.

@Autowired vs @Inject

@Autowireddan @Injectbuat perkara yang sama. Namun, @Injectapakah penjelasan standard Java, sedangkan @Autowiredkhusus untuk Spring. Mereka berdua memiliki tujuan yang sama untuk memberitahu mesin DI untuk menyuntikkan medan atau kaedah dengan objek yang sesuai. Anda boleh menggunakannya di Spring.

Gambaran keseluruhan rangka kerja Spring

Sekarang setelah anda melihat beberapa kod Spring, mari kita ikhtisar kerangka dan komponennya. Seperti yang anda lihat, kerangka kerja terdiri daripada empat modul utama, yang dibahagikan kepada pakej. Spring memberi anda sedikit fleksibiliti dengan modul yang akan anda gunakan.

  • Bekas teras
    • Teras
    • Kacang
    • Konteks
    • Bahasa Ekspresi
  • Pengaturcaraan berorientasikan aspek (AOP)
    • AOP
    • Aspek
    • Instrumentasi
  • Akses dan penyatuan data
    • JDBC
    • JPA / ORM
    • JMS
    • Urus Niaga
  • Web
    • Web / REST
    • Servlet
    • Struts

Daripada merangkumi semua perkara di sini, mari kita mulakan dengan dua ciri Spring yang lebih biasa digunakan.

Memulakan projek baru: 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

Sekiranya anda membuat titik akhir REST dan anda ingin mengembalikan JSON dari kaedah tersebut, anda boleh memberi anotasi kaedah dengan @ResponseBody. Sambutan kemudian akan dikemas secara automatik sebagai JSON. Dalam kes ini, anda akan mengembalikan objek dari kaedah.

Menggunakan MVC dengan Spring Web

Mirip dengan Struts, modul Spring Web dengan mudah dapat digunakan untuk penyediaan model-view-controller yang sebenarnya. Sekiranya demikian, anda akan mengembalikan pemetaan dalam bahasa templat yang diberikan (seperti Thymeleaf), dan Spring akan menyelesaikan pemetaan, memberikan model yang Anda sampaikan kepadanya, dan memberikan respons.

Contoh # 3: Musim bunga dengan JDBC

Sekarang mari buat sesuatu yang lebih menarik dengan pengendali permintaan kami: mari kembalikan beberapa data dari pangkalan data. Untuk tujuan contoh ini, kami akan menggunakan pangkalan data H2. Syukurlah, Spring Boot menyokong H2 DB dalam memori di luar kotak.