Как создать приложение с помощью фреймворка Spring Java.
Давайте взглянем на основы фреймворка Spring. Эта статья содержит в себе все основные этапы того, как вы можете создать приложение с использованием фреймворка Spring.
Создание нового проекта с использованием Maven
Прежде чем мы начнём создавать программу, давайте создадим проект Maven. Я буду использовать SDK 1.8:
Затем введём Name
, GroupID
и ArtifactID
нашего проекта (на самом деле не имеет значения то, что вы вводите в демонстрационных целях).
@javatg – лучшие инструменты Java разработчика.
После того, как мы нажмём Finish
, мы увидим пустой проект без каких-либо java-классов, но с pom.xml
файлом (если вы знакомы с Node.js
проектами — это как файл package.json
):
Вот что этот файл содержит в себе:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.nemrosim</groupId>
<artifactId>spring-fundamentals</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
</project>
Стартовая точка проекта
Теперь мы готовы добавить наш первый класс и проверить, что всё работает так, как ожидалось, без каких-либо проблем:
Application.java
файл:
package com.nemrosim;
public class Application {
public static void main(String[] args) {
System.out.println("Hello world");
}
}
После запуска нашего приложения, мы должны получить вывод строки в нашей консоли:
Отлично! Теперь мы можем добавить зависимость Spring в наш проект.
Добавление зависимости Spring
Чтобы иметь возможность использовать фреймворк Spring в нашем проекте, нам нужно будет добавить эту зависимость в наш pom.xml
файл:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.5</version>
</dependency>
Не забудьте обновить свой проект после добавления spring-context
зависимости.
Теперь наш pom.xml
файл будет выглядеть следующим образом:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.nemrosim</groupId>
<artifactId>spring-fundamentals</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.5</version>
</dependency>
</dependencies>
</project>
Если вас интересует, откуда была получена эта информация о зависимостях со всеми данными groupId
и version
, вы можете узнать об этом по данной ссылке на репозиторий Maven.
После обновления нашего проекта вы заметите новые внешние библиотеки в нём:
Теперь нам нужно добавить некоторый код.
Добавьте Models, Repositories и Services.
Мы создадим наш демонстрационный проект так же, как вы бы делали в производстве, то есть используя Models
, Repositories
и Services
.
Мы создадим простую пользовательскую модель — простой Java-класс с двумя полями: FirstName, LastName
с геттерами и сеттерами:
package com.nemrosim.models;
public class User {
private String firstName;
private String lastName;
public User(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
Наша папка с репозиториями будет содержать два Java-класса:
- Реализация репозитория (мы не будем подключаться ни к каким базам данных, мы будем использовать простые имитированные данные);
- Интерфейс репозитория;
Давайте создадим двух пользователей и вернём их в виде списка:
package com.nemrosim.repositories;
import com.nemrosim.models.User;
import java.util.ArrayList;
import java.util.List;
public class HibernateUserRepositoryImpl implements UserRepository {
@Override
public List<User> findAll(){
List<User> list = new ArrayList<User>();
User user1 = new User("John", "Doe");
User user2 = new User("Bruce", "Wayne");
list.add(user1);
list.add(user2);
return list;
}
}
Интерфейс будет выглядеть примерно так, ничего страшного:
package com.nemrosim.repositories;
import com.nemrosim.models.User;
import java.util.List;
public interface UserRepository {
List<User> findAll();
}
Services
будут аналогичны классам репозиториев:
Это представление бизнес-логики (возможно, мы хотели бы что-то сделать с этими пользователями из базы данных … но мы не будем):
package com.nemrosim.services;
import com.nemrosim.models.User;
import com.nemrosim.repositories.UserRepository;
import java.util.List;
public class UserServiceImpl implements UserService {
private UserRepository repository;
@Override
public List<User> findAll() {
return repository.findAll();
}
public void setRepository(UserRepository repository) {
this.repository = repository;
}
}
UserService
интерфейс:
package com.nemrosim.services;
import com.nemrosim.models.User;
import java.util.List;
public interface UserService {
List<User> findAll();
}
Конфигурация приложения
Теперь, после добавления всех этих классов, мы готовы создать наш класс конфигурации Spring:
Аннотация @Configuration
является отправной точкой фреймворка Spring, а аннотация @Bean
введёт контейнер Spring IoC
:
package com.nemrosim;
import com.nemrosim.repositories.HibernateUserRepositoryImpl;
import com.nemrosim.repositories.UserRepository;
import com.nemrosim.services.UserService;
import com.nemrosim.services.UserServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfiguration {
@Bean(name = "userService")
public UserService getUserService() {
UserServiceImpl service = new UserServiceImpl();
service.setRepository(getUserRepository());
return service;
}
@Bean(name = "userRepository")
public UserRepository getUserRepository() {
return new HibernateUserRepositoryImpl();
}
}
ЗАМЕТКА: Каждый компонент Spring по умолчанию является одноэлементным. Это означает, что не имеет значения, сколько раз вы будете вызывать метод “getUserRepository()
” → Spring вернет точно такой же экземпляр HibernateUserReposytoryImp
ЗАМЕТКА: Мы могли бы удалить всю аннотацию @Bean
с помощью @ComponentScan
и @Autowire
, но мы рассмотрим это позже
Пример:
Как вы можете видеть, Spring вернёт точно такой же объект (это хэш-значение является простой ссылкой на память, оно не изменяется). Вы можете изменить это поведение, изменив @Scope
компонента с singleton
на prototype
:
ЗАМЕТКА: В фреймворке Spring есть три дополнительные области (всего их 5, но нам нужны эти 3): Request
, Session
и Global
.
Теперь давайте добавим стартовую точку нашего приложения на Spring. Нам нужно будет обновить наш класс Application
с помощью функции main()
:
package com.nemrosim;
import com.nemrosim.models.User;
import com.nemrosim.services.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Application {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfiguration.class);
UserService service = context.getBean("userService", UserService.class);
User user = service.findAll().get(0);
System.out.println(user.getFirstName());
}
}
Давайте перезапустим наше приложение:
Консольный вывод:
Поздравляем, Spring настроен и запущен!
Constructor injection
Ранее мы использовали Setter injection
, а теперь давайте используем Constructor injection
. Для этого нам нужно будет добавить конструктор в класс UserServiceImpl
и провести рефакторинг класса AppConfiguration
:
Если мы повторно запустим наше приложение, то получим тот же результат.
Autowired аннотация
С помощью аннотации @Autowired
, мы могли бы избавиться от наших injections Setter/Constructor
.
Добавьте аннотацию @Autowired
к методу setRepository
:
Теперь Spring автоматически введёт UserRepository
в UserService
:
Результат:
Стереотипные аннотации ComponentScan
Spring также предоставляет нам стереотипные аннотации → “Аннотации, обозначающие роли типов или методов в общей архитектуре (на концептуальном уровне, а не на уровне реализации)”, и с использованием @ComponentScan
Spring автоматически сканирует нашу объявленную папку на наличие таких компонентов, как @Service
и @Repository
:
Напоминание о том, что у нас было в предыдущей версии программы:
package com.nemrosim;
import com.nemrosim.repositories.HibernateUserRepositoryImpl;
import com.nemrosim.repositories.UserRepository;
import com.nemrosim.services.UserService;
import com.nemrosim.services.UserServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfiguration {
@Bean(name = "userService")
public UserService getUserService() {
return new UserServiceImpl(getUserRepository());
}
@Bean(name = "userRepository")
public UserRepository getUserRepository() {
return new HibernateUserRepositoryImpl();
}
}
Теперь мы можем избавиться от всех наших предыдущих конфигураций, а Spring Framework сделает всё остальное за нас. Вот что получится:
package com.nemrosim;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan({"com.nemrosim"})
public class AppConfiguration {}
Если мы удалим аннотацию @Autowired
из сеттера и установим её в конструктор…
… мы получим следующий результат: