Što je proljeće? Razvoj zasnovan na komponentama za Javu

Proljeće je možda najbolje od okvira temeljenih na komponentama koji su se pojavili na prijelazu u 21. stoljeće. Značajno poboljšava način na koji programeri pišu i isporučuju infrastrukturni kod u aplikacijama zasnovanim na Javi. Od svog osnutka Spring je prepoznat kao vodeći okvir za razvoj Java-a u poduzeću. Kao okvir aplikacije od kraja do kraja, Spring odražava neke od mogućnosti Java EE, ali nudi kombinaciju značajki i programskih konvencija koje nećete naći drugdje.

Ovaj članak predstavlja Spring i njegovu temeljnu filozofiju i metodologiju programiranja: Inverzija upravljanja i ubrizgavanje ovisnosti. Također ćete započeti s proljetnim bilješkama i nekoliko praktičnih primjera kodiranja.

Injekcija ovisnosti i inverzija upravljanja

Osnovna ideja Springa je da umjesto da sami upravljate odnosima s objektima, vi ih pretočite u okvir. Inverzija kontrole (IOC) je metodologija koja se koristi za upravljanje objektnim odnosima. Injekcija ovisnosti je mehanizam za provedbu MOK-a. Budući da su ova dva pojma povezana, ali različita, razmotrimo ih bliže:

  • Inverzija kontrole (IOC) čini upravo ono što joj govori ime: invertira tradicionalnu hijerarhiju kontrole za ispunjavanje objektnih odnosa. Umjesto da se oslanjaju na aplikacijski kod za definiranje odnosa objekata međusobno, odnosi se definiraju okvirom. Kao metodologiju, IOC uvodi dosljednost i predvidljivost odnosa objektima, ali zahtijeva od vas kao programera da se odreknete neke sitnozrnate kontrole.
  • Ubrizgavanje ovisnosti (DI) mehanizam je kada okvir "ubacuje" ovisnosti u vašu aplikaciju. To je praktična primjena MOO-a. Ubrizgavanje ovisnosti ovisi o polimorfizmu, u smislu da omogućuje ispunjenje referentnog tipa na temelju konfiguracija u okviru. Okvir ubacuje reference varijabli umjesto da ih ručno ispunjava u kodu aplikacije.

JSR-330

Kao i većina u svijetu Jave, ono što je započelo kao divlja inovacija Spring, djelomično je apsorbirana standardnim specifikacijama. U ovom je slučaju JSR-330 Java standard. Lijepa stvar kod specifikacije JSR-330 je što je možete koristiti negdje drugdje, a vidjet će je i drugdje, izvan Proljeća. Možete ga koristiti bez upotrebe Springa. Međutim, proljeće na stol donosi puno više.

Primjer # 1: Ubrizgavanje ovisnosti o opruzi

Inverziju upravljanja i ubrizgavanje ovisnosti najbolje je razumjeti njihovom upotrebom, pa ćemo započeti s primjerom brzog programiranja.

Recimo da modelirate automobil. Ako modelirate u običnoj staroj Javi, možda imate člana sučelja u Carklasi koji upućuje na Enginesučelje, kao što je prikazano u popisu 1.

Popis 1. Odnosi s objektima u običnoj staroj Javi

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

Popis 1 sadrži sučelje za Enginetip i klasu za konkretni Cartip koji upućuje na Engine. (Imajte na umu da bi u stvarnom programskom scenariju to bile u zasebnim datotekama.) Sada, kada kreirate Carinstancu, postavili biste asocijaciju kao što je prikazano na popisu 2.

Popis 2. Stvaranje automobila s sučeljem motora

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

Imajte na umu da Carprvo stvorite objekt. Zatim izradite novi objekt koji ispunjava Enginesučelje i ručno ga dodijelite Carobjektu. Tako funkcioniraju asocijacije objekata u običnoj staroj Javi.

Modeliranje klasa i predmeta u proljeće

Pogledajmo sada isti primjer u proljeće. Ovdje možete učiniti nešto poput onoga što je prikazano na Listing 3. Možete početi s Carklase, ali u ovom slučaju dodali napomenu na to: @Inject.

Popis 3. Primjer upotrebe bilješke @Inject u proljeće

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

Korištenje @Injectnapomene (ili @Autowiredako želite) govori Springu da pretražuje kontekst i automatski ubrizga objekt u referencu, na temelju skupa pravila.

Dalje, razmotrite @Componentnapomenu, prikazanu na popisu 4.

Unos 4. @Anacija komponenata

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

Bilježenje predavanja s @Componentkaže Springu da je dostupan za ispunjavanje injekcija. U ovom slučaju, InlineSixCylEngineinjekcija bi se ubrizgala jer je dostupna i udovoljava zahtjevima sučelja asocijacije. U proljeće se to naziva injekcija s automatskim povezivanjem. (Pogledajte dolje za više o Proljećevoj @Autowiredbilješci.)

Odvajanje kao princip dizajna

Inverzija kontrole s ubrizgavanjem ovisnosti uklanja izvor konkretne ovisnosti iz vašeg koda. Nigdje u programu nema čvrsto kodirane reference na Engineprovedbu. Ovo je primjer razdvajanja kao principa softverskog dizajna. Odvajanjem aplikacijskog koda od implementacije čini vašim kodom lakše upravljanje i održavanje. Aplikacija zna manje o tome kako se njezini dijelovi međusobno uklapaju, ali mnogo je lakše unijeti promjene u bilo kojem trenutku životnog ciklusa aplikacije.

@Autowired vs @Inject

@Autowiredi @Injectučiniti istu stvar. Međutim, @Injectje li Java anotacija standardna, dok @Autowiredje specifična za Spring. Oboje imaju istu svrhu da DI mehanizmu kažu da ubrizga polje ili metodu s odgovarajućim objektom. U proljeće možete koristiti bilo koji.

Pregled proljetnog okvira

Sad kad ste vidjeli proljetni kod, napravimo pregled okvira i njegovih komponenti. Kao što vidite, okvir se sastoji od četiri glavna modula koji su podijeljeni u pakete. Proljeće vam pruža prilično veliku fleksibilnost s modulima koje ćete koristiti.

  • Spremnik jezgre
    • Jezgra
    • Grah
    • Kontekst
    • Jezik izraza
  • Aspektno orijentirano programiranje (AOP)
    • AOP
    • Aspekti
    • Instrumentacija
  • Pristup podacima i integracija
    • JDBC
    • JPA / ORM
    • JMS
    • Transakcije
  • mreža
    • Web / ODMOR
    • Servlet
    • Podmetači

Umjesto da ovdje pokrijemo sve, krenimo s dvije najčešće korištene značajke Proljeća.

Pokretanje novog projekta: 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

Ako kreirate REST krajnju točku i želite vratiti JSON iz metode, možete je označiti s @ResponseBody. Odgovor će se tada automatski zapakirati u JSON. U ovom slučaju vratit ćete objekt iz metode.

Korištenje MVC-a s Spring Webom

Slično Struts-u, Spring Web modul se lako može koristiti za istinsko postavljanje modela-view-controller. U tom biste slučaju vratili mapiranje u zadanom jeziku predložaka (poput Thymeleaf), a Spring bi razriješio mapiranje, pružio model koji mu prosljeđujete i pružio odgovor.

Primjer # 3: Proljeće s JDBC-om

Sada napravimo nešto zanimljivije s našim obrađivačem zahtjeva: vratimo neke podatke iz baze podataka. U svrhu ovog primjera koristit ćemo H2 bazu podataka. Srećom, Spring Boot podržava in-memory H2 DB izvan okvira.