Co to jest wiosna? Programowanie oparte na komponentach dla języka Java

Wiosna jest prawdopodobnie najlepszym frameworkiem opartym na komponentach, który pojawił się na przełomie XXI i XXI wieku. Znacznie poprawia sposób, w jaki programiści piszą i dostarczają kod infrastruktury w aplikacjach opartych na języku Java. Od samego początku Spring był uznawany za wiodącą platformę do programowania w języku Java dla przedsiębiorstw. Jako kompleksowa platforma aplikacji, Spring odzwierciedla niektóre możliwości Java EE, ale oferuje połączenie funkcji i konwencji programowania, których nie znajdziesz nigdzie indziej.

W tym artykule przedstawiono Spring i jego podstawową filozofię i metodologię programowania: inwersję kontroli i wstrzykiwanie zależności. Zaczniesz też od adnotacji Spring i kilku praktycznych przykładów kodowania.

Wstrzykiwanie zależności i odwrócenie kontroli

Podstawową ideą Springa jest to, że zamiast samodzielnie zarządzać relacjami między obiektami, przenosisz je do struktury. Odwrócenie kontroli (IOC) to metodologia używana do zarządzania relacjami między obiektami. Wstrzykiwanie zależności jest mechanizmem implementacji IOC. Ponieważ te dwie koncepcje są powiązane, ale różne, rozważmy je bliżej:

  • Odwrócenie kontroli (IOC) robi dokładnie to, co mówi jego nazwa: odwraca tradycyjną hierarchię kontroli w celu spełnienia relacji między obiektami. Zamiast polegać na kodzie aplikacji do definiowania relacji między obiektami, relacje są definiowane przez strukturę. Jako metodologia, IOC wprowadza spójność i przewidywalność do relacji z obiektami, ale wymaga od dewelopera rezygnacji z pewnej szczegółowej kontroli.
  • Wstrzykiwanie zależności (DI) to mechanizm, w którym struktura „wstrzykuje” zależności do aplikacji. To praktyczna implementacja IOC. Wstrzykiwanie zależności opiera się na polimorfizmie, w tym sensie, że pozwala na zmianę typu odniesienia na podstawie konfiguracji we frameworku. Framework wstrzykuje odwołania do zmiennych zamiast ręcznie wprowadzać je w kodzie aplikacji.

JSR-330

Podobnie jak wiele innych w świecie Java, to, co zaczęło się jako innowacja na wolności, Spring, zostało częściowo wchłonięte przez standardową specyfikację. W tym przypadku JSR-330 jest standardem Java. Zaletą specyfikacji JSR-330 jest to, że możesz go używać gdzie indziej i zobaczysz go w użyciu gdzie indziej, poza wiosną. Możesz go używać bez użycia Springa. Jednak Wiosna wnosi do stołu o wiele więcej.

Przykład 1: iniekcja zależności sprężyny

Odwrócenie kontroli i wstrzykiwanie zależności najlepiej jest zrozumieć, używając ich, więc zaczniemy od szybkiego przykładu programowania.

Powiedz, że modelujesz samochód. Jeśli modelujesz w zwykłej starej Javie, możesz mieć element członkowski interfejsu w Carklasie odwołujący się do Engineinterfejsu, jak pokazano na liście 1.

Listing 1. Relacje obiektów w zwykłej starej Javie

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

Listing 1 zawiera interfejs dla Enginetypu i klasę dla konkretnego Cartypu, który odwołuje się do Engine. (Zauważ, że w prawdziwym scenariuszu programowania byłyby to oddzielne pliki.) Teraz, kiedy tworzysz Carinstancję, ustawisz powiązanie, jak pokazano na Listingu 2.

Listing 2. Tworzenie samochodu z interfejsem Engine

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

Zwróć uwagę, że najpierw tworzysz Carobiekt. Następnie tworzysz nowy obiekt, który spełnia wymagania Engineinterfejsu i przypisujesz go ręcznie do Carobiektu. Tak działają skojarzenia obiektów w zwykłej starej Javie.

Modelowanie klas i obiektów wiosną

Spójrzmy teraz na ten sam przykład wiosną. Tutaj można zrobić coś takiego, co pokazano na listingu 3. Zaczynasz z Carklasy, ale w tym przypadku należy dodać adnotację do niej: @Inject.

Listing 3. Przykład użycia adnotacji @Inject na wiosnę

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

Użycie @Injectadnotacji (lub @Autowired, jeśli wolisz), mówi Springowi, aby przeszukał kontekst i automatycznie wstrzyknął obiekt do odwołania, na podstawie zestawu reguł.

Następnie rozważ @Componentadnotację pokazaną na liście 4.

Listing 4. @ Adnotacja @Component

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

Dodanie adnotacji do klasy @Componentmówi Springowi, że jest ona dostępna do wypełniania zastrzyków. W tym przypadku InlineSixCylEnginezostanie wstrzyknięty, ponieważ jest dostępny i spełnia wymagania interfejsu skojarzenia. Wiosną nazywa się to „automatycznym” zastrzykiem. (Zobacz poniżej, aby uzyskać więcej informacji na temat @Autowiredadnotacji Spring ).

Odsprzęganie jako zasada projektowania

Odwrócenie kontroli z iniekcją zależności usuwa źródło konkretnej zależności z kodu. Nigdzie w programie nie ma zakodowanego odniesienia do Engineimplementacji. To jest przykład oddzielenia jako zasady projektowania oprogramowania. Oddzielenie kodu aplikacji od implementacji ułatwia zarządzanie kodem i jego konserwację. Aplikacja mniej wie o tym, jak jej części pasują do siebie, ale znacznie łatwiej jest wprowadzić zmiany w dowolnym momencie cyklu życia aplikacji.

@Autowired vs @Inject

@Autowiredi @Injectzrób to samo. Jednak @Injectjest to standardowa adnotacja Java, podczas gdy @Autowiredjest specyficzna dla Spring. Oba służą temu samemu celowi, mówiąc silnikowi DI, aby wstrzyknął pole lub metodę pasującym obiektem. Możesz użyć jednego z nich na wiosnę.

Omówienie struktury Spring

Po zapoznaniu się z kodem Springa, przyjrzyjmy się frameworkowi i jego składnikom. Jak widać, framework składa się z czterech głównych modułów, które są podzielone na pakiety. Spring zapewnia dużą elastyczność w zakresie modułów, których będziesz używać.

  • Pojemnik na rdzeń
    • Rdzeń
    • Fasola
    • Kontekst
    • Język ekspresji
  • Programowanie zorientowane na aspekt (AOP)
    • AOP
    • Aspekty
    • Oprzyrządowanie
  • Dostęp do danych i integracja
    • JDBC
    • JPA / ORM
    • JMS
    • Transakcje
  • Sieć
    • Sieć / REST
    • Servlet
    • Rozpórki

Zamiast omawiać wszystko tutaj, zacznijmy od dwóch najczęściej używanych funkcji Spring.

Rozpoczynanie nowego projektu: 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

Jeśli tworzysz punkt końcowy REST i chcesz zwrócić JSON z metody, możesz dodać adnotację do metody za pomocą @ResponseBody. Odpowiedź zostanie następnie automatycznie zapakowana jako JSON. W tym przypadku zwrócisz obiekt z metody.

Korzystanie z MVC w Spring Web

Podobnie jak Struts, moduł Spring Web może być łatwo użyty do prawdziwej konfiguracji kontrolera widoku modelu. W takim przypadku zwróciłbyś mapowanie w danym języku szablonów (takim jak Thymeleaf), a Spring rozwiązałby mapowanie, dostarczyłby model, który do niego przekazałeś i wyrenderowałby odpowiedź.

Przykład # 3: Wiosna z JDBC

Teraz zróbmy coś bardziej interesującego z naszym modułem obsługi żądań: zwróćmy trochę danych z bazy danych. Na potrzeby tego przykładu użyjemy bazy danych H2. Na szczęście Spring Boot obsługuje po wyjęciu z pudełka bazę danych H2 w pamięci.