Apa itu Spring? Pengembangan berbasis komponen untuk Java

Spring mungkin yang terbaik dari framework berbasis komponen yang muncul pada pergantian abad ke-21. Ini sangat meningkatkan cara pengembang menulis dan mengirimkan kode infrastruktur dalam aplikasi berbasis Java. Sejak awal, Spring telah diakui sebagai framework terdepan untuk pengembangan Java enterprise. Sebagai kerangka kerja aplikasi ujung ke ujung, Spring mencerminkan beberapa kapabilitas Java EE, tetapi Spring menawarkan kombinasi fitur dan konvensi pemrograman yang tidak akan Anda temukan di tempat lain.

Artikel ini memperkenalkan Spring dan filosofi dan metodologi pemrograman intinya: Inversi kontrol dan injeksi ketergantungan. Anda juga akan mulai dengan anotasi Musim Semi dan beberapa contoh pengkodean langsung.

Injeksi ketergantungan dan inversi kendali

Ide inti Spring adalah alih-alih mengelola sendiri hubungan objek, Anda memindahkannya ke kerangka kerja. Inversion of control (IOC) adalah metodologi yang digunakan untuk mengelola hubungan objek. Injeksi ketergantungan adalah mekanisme untuk mengimplementasikan IOC. Karena kedua konsep ini terkait tetapi berbeda, mari kita pertimbangkan lebih dekat:

  • Inversion of control (IOC) melakukan sesuai dengan namanya: ia membalik hierarki kontrol tradisional untuk memenuhi hubungan objek. Alih-alih mengandalkan kode aplikasi untuk menentukan bagaimana objek berhubungan satu sama lain, hubungan didefinisikan oleh kerangka kerja. Sebagai metodologi, IOC memperkenalkan konsistensi dan prediktabilitas pada relasi objek, tetapi hal ini mengharuskan Anda, sebagai pengembang, untuk melepaskan beberapa kontrol yang sangat baik.
  • Injeksi dependensi (DI) adalah mekanisme di mana framework "memasukkan" dependensi ke dalam aplikasi Anda. Ini adalah implementasi praktis dari IOC. Injeksi ketergantungan bergantung pada polimorfisme, dalam arti memungkinkan pemenuhan jenis referensi berubah berdasarkan konfigurasi dalam kerangka kerja. Kerangka kerja memasukkan referensi variabel, bukan memenuhinya secara manual dalam kode aplikasi.

JSR-330

Seperti kebanyakan di dunia Jawa, apa yang dimulai sebagai inovasi alam liar, Spring, sebagian telah diserap oleh spesifikasi standar. Dalam hal ini, JSR-330 adalah standar Java. Hal yang menyenangkan tentang spesifikasi JSR-330 adalah Anda dapat menggunakannya di tempat lain, dan akan melihatnya digunakan di tempat lain, di luar Spring. Anda dapat menggunakannya tanpa menggunakan Spring. Namun, Spring membawa lebih banyak lagi ke meja.

Contoh # 1: Injeksi ketergantungan pegas

Inversi kontrol dan injeksi ketergantungan paling baik dipahami dengan menggunakannya, jadi kita akan mulai dengan contoh pemrograman cepat.

Katakanlah Anda sedang membuat model mobil. Jika Anda memodelkan di Java lama biasa, Anda mungkin memiliki anggota antarmuka di Carkelas untuk mereferensikan Engineantarmuka, seperti yang ditunjukkan pada Daftar 1.

Kode 1. Relasi objek di Java lama biasa

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

Kode 1 berisi antarmuka untuk suatu Enginetipe, dan kelas untuk Cartipe beton , yang mereferensikan Engine. (Perhatikan bahwa dalam skenario pemrograman nyata ini akan berada dalam file terpisah.) Sekarang, saat Anda membuat sebuah Carinstance, Anda akan mengatur pengaitan seperti yang ditunjukkan pada Listing 2.

Kode 2. Membuat Mobil dengan antarmuka Mesin

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

Perhatikan bahwa Anda membuat Carobjek terlebih dahulu. Anda kemudian membuat objek baru yang memenuhi Engineantarmuka, dan menetapkannya secara manual ke Carobjek. Begitulah cara kerja asosiasi objek di Java lama biasa.

Kelas pemodelan dan objek di Spring

Sekarang mari kita lihat contoh yang sama di Spring. Di sini, Anda bisa melakukan sesuatu seperti apa yang ditampilkan pada Listing 3. Anda mulai dengan Carkelas, tetapi dalam kasus ini Anda menambahkan penjelasan untuk itu: @Inject.

Kode 3. Contoh penggunaan anotasi @Inject di Spring

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

Menggunakan @Injectanotasi (atau @Autowired, jika Anda lebih suka) memberi tahu Spring untuk menelusuri konteks dan secara otomatis memasukkan objek ke dalam referensi, berdasarkan sekumpulan aturan.

Selanjutnya, perhatikan @Componentanotasi, yang ditunjukkan pada Listing 4.

Kode 4. Anotasi @Component

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

Menganotasi kelas dengan @Componentmemberi tahu Spring bahwa itu tersedia untuk memenuhi suntikan. Dalam hal ini, InlineSixCylEngineakan dimasukkan karena tersedia dan memenuhi persyaratan antarmuka dari pengaitan. Di Spring, ini disebut injeksi "autowired". (Lihat di bawah untuk lebih lanjut tentang @Autowiredanotasi Spring .)

Decoupling sebagai prinsip desain

Pembalikan kontrol dengan injeksi ketergantungan menghilangkan sumber ketergantungan konkret dari kode Anda. Tidak ada tempat dalam program ini yang memiliki referensi hardcode untuk Engineimplementasi. Ini adalah contoh decoupling sebagai prinsip desain perangkat lunak. Memisahkan kode aplikasi dari implementasi membuat kode Anda lebih mudah untuk dikelola dan dipelihara. Aplikasi tidak begitu mengetahui tentang bagaimana bagian-bagiannya cocok, tetapi jauh lebih mudah untuk membuat perubahan kapan saja dalam siklus hidup aplikasi.

@Tokopedia

@Autowireddan @Injectmelakukan hal yang sama. Namun, @Injectini adalah anotasi standar Java, sedangkan @Autowiredkhusus untuk Spring. Keduanya memiliki tujuan yang sama yaitu memberi tahu mesin DI untuk menyuntikkan bidang atau metode dengan objek yang cocok. Anda dapat menggunakan salah satunya di Musim Semi.

Tinjauan kerangka Spring

Sekarang Anda telah melihat beberapa kode Spring, mari kita lihat gambaran umum kerangka kerja dan komponennya. Seperti yang Anda lihat, kerangka kerja terdiri dari empat modul utama, yang dipecah menjadi beberapa paket. Spring memberi Anda fleksibilitas yang cukup dengan modul yang akan Anda gunakan.

  • Wadah inti
    • Inti
    • Kacang
    • Konteks
    • Bahasa Ekspresi
  • Pemrograman berorientasi aspek (AOP)
    • AOP
    • Aspek
    • Peralatan
  • Akses dan integrasi data
    • JDBC
    • JPA / ORM
    • JMS
    • Transaksi
  • Web
    • Web / REST
    • Servlet
    • Struts

Daripada membahas semuanya di sini, mari kita mulai dengan dua fitur Spring yang lebih umum digunakan.

Memulai proyek baru: Spring Boot

Kami akan menggunakan Spring Boot untuk membuat proyek contoh, yang akan kami gunakan untuk mendemonstrasikan fitur Spring. Spring Boot membuat memulai proyek baru jauh lebih mudah, seperti yang akan Anda lihat sendiri. Untuk memulai, lihat kelas utama yang ditunjukkan di bawah ini. Di Spring Boot, kita dapat mengambil kelas utama dengan sebuah main()metode, dan kemudian memilih untuk menjalankannya secara mandiri, atau paket untuk disebarkan dalam wadah seperti Tomcat.

Kode 5 memiliki garis besar kelas utama kami, yang akan tinggal di src/main/java/hellolokasi standar .

Kode 5. Kelas utama dengan 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

Jika Anda membuat titik akhir REST dan ingin mengembalikan JSON dari metode, Anda dapat menganotasi metode dengan @ResponseBody. Respons tersebut kemudian akan secara otomatis dikemas sebagai JSON. Dalam hal ini Anda akan mengembalikan objek dari metode.

Menggunakan MVC dengan Spring Web

Mirip dengan Struts, modul Spring Web dapat dengan mudah digunakan untuk pengaturan model-view-controller yang sebenarnya. Dalam kasus tersebut, Anda akan mengembalikan pemetaan dalam bahasa template yang diberikan (seperti Thymeleaf), dan Spring akan menyelesaikan pemetaan, memberikan model yang Anda teruskan, dan memberikan respons.

Contoh # 3: Spring dengan JDBC

Sekarang mari kita lakukan sesuatu yang lebih menarik dengan penangan permintaan kita: mari kita kembalikan beberapa data dari database. Untuk tujuan contoh ini, kita akan menggunakan database H2. Untungnya, Spring Boot mendukung H2 DB dalam memori di luar kotak.