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 Car
kelas untuk mereferensikan Engine
antarmuka, 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 Engine
tipe, dan kelas untuk Car
tipe beton , yang mereferensikan Engine
. (Perhatikan bahwa dalam skenario pemrograman nyata ini akan berada dalam file terpisah.) Sekarang, saat Anda membuat sebuah Car
instance, 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 Car
objek terlebih dahulu. Anda kemudian membuat objek baru yang memenuhi Engine
antarmuka, dan menetapkannya secara manual ke Car
objek. 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 Car
kelas, 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 @Inject
anotasi (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 @Component
anotasi, yang ditunjukkan pada Listing 4.
Kode 4. Anotasi @Component
@Component public class InlineSixCylinderEngine implements Engine{ //... }
Menganotasi kelas dengan @Component
memberi tahu Spring bahwa itu tersedia untuk memenuhi suntikan. Dalam hal ini, InlineSixCylEngine
akan dimasukkan karena tersedia dan memenuhi persyaratan antarmuka dari pengaitan. Di Spring, ini disebut injeksi "autowired". (Lihat di bawah untuk lebih lanjut tentang @Autowired
anotasi 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 Engine
implementasi. 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
@Autowired
dan @Inject
melakukan hal yang sama. Namun, @Inject
ini adalah anotasi standar Java, sedangkan @Autowired
khusus 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/hello
lokasi 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:
- The
parent
element relies on thespring-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, andSpringBootParent
will set the versions to be compatible. When you bump up the parent's version number, the dependency versions and defaults will also change. - The
spring-boot-maven-plugin
allows for the executable JAR/WAR packaging and in-placerun
(via themvn 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.