Jakarta EE начинает с того места, где остановилась Java EE 8, но план развития в будущем будет сфокусирован на современных инновациях, таких как микросервисы, модульность и базы данных NoSQL. В этой статье будет рассказано о новейшей веховой версии этой новой спецификации и последующих действиях, направленных на то, чтобы сделать сообщество Jakarta EE еще более значительным в облаке.
Почему Джакарта NoSQL?
Блокировка поставщика — это одна из вещей, которую любой Java-разработчик должен учитывать при выборе баз данных NoSQL. Если есть необходимость в переключении, другие факторы включают время, потраченное на изменение, кривую изучения нового API для использования с этой базой данных, код, который будет потерян, уровень сохраняемости, который необходимо заменить. Jakarta NoSQL позволяет избежать большинства этих проблем с помощью API-интерфейсов связи. Jakarta NoSQL также имеет классы шаблонов, которые применяют шаблонный шаблонный шаблонный метод к операциям с базой данных. А Repository
интерфейс позволяет разработчикам Java создавать и расширять интерфейсы, причем реализация автоматически обеспечивается Jakarta NoSQL — для них автоматически будут реализованы запросы методов поддержки, созданные разработчиками.
Вам также могут понравиться: Джакарта EE: Поколение IV — новая надежда
Чтобы было понятно, давайте создадим пример кода. На рисунке ниже показаны четыре разные базы данных:
- ArangoDB
- MongoDB
- Couchbase
- OrientDB
Что общего у этих баз данных?
Да, все они — базы данных NoSQL для документов, и они пытаются создать документ, кортеж с именем и саму информацию. Однако все они делают одно и то же с одной и той же целью поведения, но с другим классом, именем метода и так далее. Итак, если вы хотите переместить свой код из одной базы данных в другую, вам нужно изучить новый API и обновить весь код базы данных до цели кода API базы данных.
Благодаря спецификации связи мы можем легко переключаться между базами данных, просто используя базы данных драйверов, которые выглядят как драйверы JDBC. Таким образом, вам будет удобнее изучать новую базу данных NoSQL с точки зрения архитектуры программного обеспечения; мы можем легко и быстро перейти на другой NoSQL.
Покажи мне
код
API
код
Чтобы продемонстрировать, как работает Jakarta NoSQL, давайте создадим небольшой REST API; этот API будет работать в облаке с Platform.sh. API будет обрабатывать героев, и вся информация будет храниться в MongoDB. В качестве первого шага нам нужно установить зависимости, которые нужны Jakarta NoSQL:
- Джакартский контекст инъекции зависимостей 2.0 . Внедрение зависимостей Jakarta Contexts определяет средства для получения объектов, которые максимизируют возможность повторного использования, тестируемости и удобства обслуживания по сравнению с традиционными подходами, такими как конструкторы, фабрики и локаторы служб. Думайте об этом как о клее для всего мира Джакарты.
- Джакарта JSON Binding . Определяет структуру привязки для преобразования объектов Java в и из документов JSON.
- Валидация бобов Джакарта 2.0 (необязательно). Валидация Jakarta Bean определяет модель метаданных и API для JavaBean и валидацию методов.
- Eclipse MicroProfile Configuration (необязательно). Eclipse MicroProfile Config — это решение для настройки конфигурации из приложений Java.
XML
1
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
3
<modelVersion>4.0.0</modelVersion>
4
<groupId>org.soujava</groupId>
5
<artifactId>heroes</artifactId>
6
<version>1.0-SNAPSHOT</version>
7
<packaging>war</packaging>
8
<name>heroes-demo</name>
9
<url>https://soujava.org.br/</url>
10
<properties>
11
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
12
<maven.compiler.source>1.8</maven.compiler.source>
13
<maven.compiler.target>1.8</maven.compiler.target>
14
<failOnMissingWebXml>false</failOnMissingWebXml>
15
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
16
<version.microprofile>2.2</version.microprofile>
17
<version.payara.micro>5.193.1</version.payara.micro>
18
<payara.version>1.0.5</payara.version>
19
<platform.sh.version>2.2.3</platform.sh.version>
20
<jakarta.nosql.version>1.0.0-b1</jakarta.nosql.version>
21
</properties>
22
<dependencies>
24
<dependency>
25
<groupId>jakarta.platform</groupId>
26
<artifactId>jakarta.jakartaee-web-api</artifactId>
27
<version>8.0.0</version>
28
</dependency>
29
<dependency>
30
<groupId>org.eclipse.microprofile.config</groupId>
31
<artifactId>microprofile-config-api</artifactId>
32
<version>1.3</version>
33
<scope>provided</scope>
34
</dependency>
35
<dependency>
36
<groupId>org.eclipse.jnosql.artemis</groupId>
37
<artifactId>artemis-document</artifactId>
38
<version>${jakarta.nosql.version}</version>
39
</dependency>
40
<dependency>
41
<groupId>org.eclipse.jnosql.diana</groupId>
42
<artifactId>mongodb-driver</artifactId>
43
<version>${jakarta.nosql.version}</version>
44
</dependency>
45
</dependencies>
46
<build>
47
<finalName>heros</finalName>
48
<plugins>
49
<plugin>
50
<groupId>org.apache.maven.plugins</groupId>
51
<artifactId>maven-war-plugin</artifactId>
52
<version>3.2.2</version>
53
<configuration>
54
<failOnMissingWebXml>false</failOnMissingWebXml>
55
<packagingExcludes>pom.xml</packagingExcludes>
56
</configuration>
57
</plugin>
58
<plugin>
59
<groupId>fish.payara.maven.plugins</groupId>
60
<artifactId>payara-micro-maven-plugin</artifactId>
61
<version>${payara.version}</version>
62
<configuration>
63
<payaraVersion>${version.payara.micro}</payaraVersion>
64
<autoDeployEmptyContextRoot>true</autoDeployEmptyContextRoot>
65
</configuration>
66
</plugin>
67
</plugins>
68
</build>
69
</project>
Одним из удивительных аспектов использования Platform.sh является то, что нам не нужно беспокоиться об установке инфраструктуры, которая включает в себя сам сервер MongoDB ; он создаст несколько контейнеров, которые включают приложение и базу данных. Скоро мы еще поговорим о Platform.sh и его отношениях с cloud-native.
Первым шагом является создание объекта Hero, в пакете аннотаций теперь как jakarta.nosql.mapping
.
Джава
xxxxxxxxxx
1
import jakarta.nosql.mapping.Column;
2
import jakarta.nosql.mapping.Entity;
3
import jakarta.nosql.mapping.Id;
4
import javax.json.bind.annotation.JsonbVisibility;
6
import java.io.Serializable;
7
import java.util.Objects;
8
import java.util.Set;
9
11
FieldPropertyVisibilityStrategy.class) (
12
public class Hero implements Serializable {
13
15
private String name;
16
18
private Integer age;
19
21
private Set<String> powers;
22
24
public boolean equals(Object o) {
25
if (this == o) {
26
return true;
27
}
28
if (!(o instanceof Hero)) {
29
return false;
30
}
31
Hero hero = (Hero) o;
32
return Objects.equals(name, hero.name);
33
}
34
36
public int hashCode() {
37
return Objects.hashCode(name);
38
}
39
41
public String toString() {
42
return "Hero{" +
43
"name='" + name + '\'' +
44
", age=" + age +
45
", powers=" + powers +
46
'}';
47
}
48
}
49
import javax.json.bind.config.PropertyVisibilityStrategy;
51
import java.lang.reflect.Field;
52
import java.lang.reflect.Method;
53
public class FieldPropertyVisibilityStrategy implements PropertyVisibilityStrategy {
55
57
public boolean isVisible(Field field) {
58
return true;
59
}
60
62
public boolean isVisible(Method method) {
63
return true;
64
}
65
}
Следующим шагом будет создание соединения с базой данных NoSQL, поэтому мы создадим DocumentCollectionManager
экземпляр. Думайте EntityManager
как база данных документов. Мы знаем, что жестко закодированная информация небезопасна и не является хорошей практикой. Вот почему двенадцать факторов упоминает это в третьем разделе . Кроме того, приложению не нужно знать, откуда эта информация. Чтобы следовать рекомендациям двенадцати факторов и поддерживать облачный принцип, Jakarta NoSQL поддерживает конфигурацию Eclipse MicroProfile.
Джава
xxxxxxxxxx
1
import jakarta.nosql.document.DocumentCollectionManager;
2
import org.eclipse.microprofile.config.inject.ConfigProperty;
3
import javax.enterprise.context.ApplicationScoped;
5
import javax.enterprise.inject.Disposes;
6
import javax.enterprise.inject.Produces;
7
import javax.inject.Inject;
8
10
class DocumentManagerProducer {
11
13
(name = "document")
14
private DocumentCollectionManager manager;
15
17
public DocumentCollectionManager getManager() {
18
return manager;
19
}
20
public void destroy( DocumentCollectionManager manager) {
22
manager.close();
23
}
24
}
Как только это будет сделано, мы создадим класс соединения, который сделает DocumentCollectionManager
экземпляр доступным для CDI, благодаря методу, помеченному как Produces
.
Конфигурация базы данных готова к локальному запуску. Для этого приложения вне CRUD, давайте создадим еще три запроса:
- Найти всех героев
- Найти героев старше определенного возраста
- Найти героев моложе определенного возраста
- Найти героев по имени, идентификатору
- Найти героев по силе
У нас есть несколько способов создать этот запрос в Jakarta NoSQL. Давайте познакомимся с первым способом DocumentTemplate
. Классы шаблонов выполняют операции с базой данных NoSQL на Mapper
уровне, поэтому для каждого типа NoSQL существует класс шаблона, который поддерживает Jakarta NoSQL: DocumentTemplate
для документа, KeyValueTemplate
для базы данных ключей и т. Д.
Несмотря на это Document Template
, у нас есть два пути для обращения информации в базы данных NoSQL. Первый программно. У API есть свободный способ создать DocumentQuery
экземпляр.
Джава
x
1
import jakarta.nosql.document.DocumentDeleteQuery;
2
import jakarta.nosql.document.DocumentQuery;
3
import jakarta.nosql.mapping.document.DocumentTemplate;
4
import com.google.common.collect.Sets;
5
import javax.enterprise.context.ApplicationScoped;
7
import javax.inject.Inject;
8
import java.util.Optional;
9
import java.util.stream.Collectors;
10
import java.util.stream.Stream;
11
import static jakarta.nosql.document.DocumentDeleteQuery.delete;
13
import static jakarta.nosql.document.DocumentQuery.select;
14
import static java.util.Arrays.asList;
15
17
public class FluentAPIService {
18
20
private DocumentTemplate template;
21
public void execute() {
23
Hero iron = new Hero("Iron man", 32, Sets.newHashSet("Rich"));
25
Hero thor = new Hero("Thor", 5000, Sets.newHashSet("Force", "Thunder", "Strength"));
26
Hero captainAmerica = new Hero("Captain America", 80, Sets.newHashSet("agility",
27
"Strength", "speed", "endurance"));
28
Hero spider = new Hero("Spider", 18, Sets.newHashSet("Spider", "Strength"));
29
DocumentDeleteQuery deleteQuery = delete().from("Hero")
31
.where("_id").in(Stream.of(iron, thor, captainAmerica, spider)
32
.map(Hero::getName).collect(Collectors.toList())).build();
33
template.delete(deleteQuery);
34
template.insert(asList(iron, thor, captainAmerica, spider));
37
//find by id
38
Optional<Hero> hero = template.find(Hero.class, iron.getName());
39
System.out.println(hero);
40
//query younger
42
DocumentQuery youngQuery = select().from("Hero")
43
.where("age").lt(20).build();
44
//query seniors
46
DocumentQuery seniorQuery = select().from("Hero")
47
.where("age").gt(20).build();
48
//query powers
50
DocumentQuery queryPower = select().from("Hero")
51
.where("powers").in(Collections.singletonList("Strength"))
52
.build();
53
Stream<Hero> youngStream = template.select(youngQuery);
55
Stream<Hero> seniorStream = template.select(seniorQuery);
57
Stream<Hero> strengthStream = template.select(queryPower);
59
String yongHeroes = youngStream.map(Hero::getName).collect(Collectors.joining(","));
61
String seniorsHeroes = seniorStream.map(Hero::getName).collect(Collectors.joining(","));
62
String strengthHeroes = strengthStream.map(Hero::getName).collect(Collectors.joining(","));
63
System.out.println("Young result: " + yongHeroes);
65
System.out.println("Seniors result: " + seniorsHeroes);
66
System.out.println("Strength result: " + strengthHeroes);
67
}
68
}
Чтобы поговорить о запросе «найти всех героев», мы создадим определенный класс, потому что когда мы говорим о возврате всей информации в базу данных, нам нужно избегать влияния на производительность. Поскольку база данных может содержать более миллиона информационных точек, не имеет смысла выводить всю эту информацию одновременно (в большинстве случаев).
Джава
xxxxxxxxxx
1
import jakarta.nosql.document.DocumentDeleteQuery;
2
import jakarta.nosql.document.DocumentQuery;
3
import jakarta.nosql.mapping.document.DocumentTemplate;
4
import com.google.common.collect.Sets;
5
import javax.enterprise.context.ApplicationScoped;
7
import javax.inject.Inject;
8
import java.util.Arrays;
9
import java.util.Optional;
10
import java.util.stream.Collectors;
11
import java.util.stream.Stream;
12
import static jakarta.nosql.document.DocumentDeleteQuery.delete;
14
import static jakarta.nosql.document.DocumentQuery.select;
15
import static java.util.Arrays.asList;
16
18
public class FluentAPIFindAllService {
19
21
private DocumentTemplate template;
22
public void execute() {
24
Hero iron = new Hero("Iron man", 32, Sets.newHashSet("Rich"));
26
Hero thor = new Hero("Thor", 5000, Sets.newHashSet("Force", "Thunder"));
27
Hero captainAmerica = new Hero("Captain America", 80, Sets.newHashSet("agility",
28
"strength", "speed", "endurance"));
29
Hero spider = new Hero("Spider", 18, Sets.newHashSet("Spider"));
30
DocumentDeleteQuery deleteQuery = delete().from("Hero")
32
.where("_id").in(Stream.of(iron, thor, captainAmerica, spider)
33
.map(Hero::getName).collect(Collectors.toList())).build();
34
template.delete(deleteQuery);
35
template.insert(Arrays.asList(iron, thor, captainAmerica, spider));
36
DocumentQuery query = select()
38
.from("Hero")
39
.build();
40
Stream<Hero> heroes = template.select(query);
42
Stream<Hero> peek = heroes.peek(System.out::println);
43
System.out.println("The peek is not happen yet");
44
System.out.println("The Heroes names: " + peek.map(Hero::getName)
45
.collect(Collectors.joining(", ")));
46
DocumentQuery querySkipLimit = select()
48
.from("Hero")
49
.skip(0)
50
.limit(1)
51
.build();
52
Stream<Hero> heroesSkip = template.select(querySkipLimit);
54
System.out.println("The Heroes names: " + heroesSkip.map(Hero::getName)
55
.collect(Collectors.joining(", ")));
56
}
57
}
Кроме того, API имеет функцию разбиения на страницы, которая легко приспосабливает нумерацию страниц и функционирует с большими наборами данных.
Джава
xxxxxxxxxx
1
import jakarta.nosql.document.DocumentDeleteQuery;
2
import jakarta.nosql.document.DocumentQuery;
3
import jakarta.nosql.mapping.Page;
4
import jakarta.nosql.mapping.Pagination;
5
import jakarta.nosql.mapping.document.DocumentQueryPagination;
6
import jakarta.nosql.mapping.document.DocumentTemplate;
7
import com.google.common.collect.Sets;
8
import javax.enterprise.context.ApplicationScoped;
10
import javax.inject.Inject;
11
import java.util.Arrays;
12
import java.util.stream.Collectors;
13
import java.util.stream.Stream;
14
import static jakarta.nosql.document.DocumentDeleteQuery.delete;
16
import static jakarta.nosql.document.DocumentQuery.select;
17
19
public class FluentAPIPaginationService {
20
22
private DocumentTemplate template;
23
public void execute() {
25
Hero iron = new Hero("Iron man", 32, Sets.newHashSet("Rich"));
27
Hero thor = new Hero("Thor", 5000, Sets.newHashSet("Force", "Thunder"));
28
Hero captainAmerica = new Hero("Captain America", 80, Sets.newHashSet("agility",
29
"strength", "speed", "endurance"));
30
Hero spider = new Hero("Spider", 18, Sets.newHashSet("Spider"));
31
DocumentDeleteQuery deleteQuery = delete().from("Hero")
33
.where("_id").in(Stream.of(iron, thor, captainAmerica, spider)
34
.map(Hero::getName).collect(Collectors.toList())).build();
35
template.delete(deleteQuery);
36
template.insert(Arrays.asList(iron, thor, captainAmerica, spider));
37
DocumentQuery query = select()
39
.from("Hero")
40
.orderBy("_id")
41
.asc()
42
.build();
43
DocumentQueryPagination pagination =
45
DocumentQueryPagination.of(query, Pagination.page(1).size(1));
46
Page<Hero> page1 = template.select(pagination);
48
System.out.println("Page 1: " + page1.getContent().collect(Collectors.toList()));
50
Page<Hero> page2 = page1.next();
52
System.out.println("Page 2: " + page2.getContent().collect(Collectors.toList()));
54
Page<Hero> page3 = page1.next();
56
System.out.println("Page 3: " + page3.getContent().collect(Collectors.toList()));
57
}
58
}
Свободный API удивителен и безопасен для написания и чтения запросов для базы данных NoSQL, но как насчет запроса по тексту? Хотя свободный API безопаснее, иногда он многословен. Вы знаете что, хотя? Jakarta NoSQL поддерживает запрос по тексту, который включает информацию о том, PrepareStatement
где, будучи Java-разработчиком, вы можете установить параметр динамически.
Джава
xxxxxxxxxx
1
import jakarta.nosql.mapping.PreparedStatement;
2
import jakarta.nosql.mapping.document.DocumentTemplate;
3
import com.google.common.collect.Sets;
4
import javax.enterprise.context.ApplicationScoped;
6
import javax.inject.Inject;
7
import java.util.Arrays;
8
import java.util.stream.Collectors;
9
import java.util.stream.Stream;
10
12
public class TextService {
13
15
private DocumentTemplate template;
16
public void execute() {
18
Hero iron = new Hero("Iron man", 32, Sets.newHashSet("Rich"));
20
Hero thor = new Hero("Thor", 5000, Sets.newHashSet("Force", "Thunder"));
21
Hero captainAmerica = new Hero("Captain America", 80, Sets.newHashSet("agility",
22
"strength", "speed", "endurance"));
23
Hero spider = new Hero("Spider", 18, Sets.newHashSet("Spider"));
24
template.query("delete from Hero where _id in ('Iron man', 'Thor', 'Captain America', 'Spider')");
26
template.insert(Arrays.asList(iron, thor, captainAmerica, spider));
27
//query younger
28
PreparedStatement prepare = template.prepare("select * from Hero where age < @age");
29
prepare.bind("age", 20);
30
Stream<Hero> youngStream = prepare.getResult();
32
Stream<Hero> seniorStream = template.query("select * from Hero where age > 20");
34
Stream<Hero> powersStream = template.query("select * from Hero where powers in ('Strength')");
36
Stream<Hero> allStream = template.query("select * from Hero");
38
Stream<Hero> skipLimitStream = template.query("select * from Hero skip 0 limit 1 order by _id asc");
40
String yongHeroes = youngStream.map(Hero::getName).collect(Collectors.joining(","));
42
String seniorsHeroes = seniorStream.map(Hero::getName).collect(Collectors.joining(","));
43
String allHeroes = allStream.map(Hero::getName).collect(Collectors.joining(","));
44
String skipLimitHeroes = skipLimitStream.map(Hero::getName).collect(Collectors.joining(","));
45
String powersHeroes = powersStream.map(Hero::getName).collect(Collectors.joining(","));
46
System.out.println("Young result: " + yongHeroes);
48
System.out.println("Seniors result: " + seniorsHeroes);
49
System.out.println("Powers Strength result: " + powersHeroes);
50
System.out.println("All heroes result: " + allHeroes);
51
System.out.println("All heroes skip result: " + skipLimitHeroes);
52
}
53
}
Что вы думаете? Слишком сложный? Не волнуйтесь, мы можем упростить это для вас с помощью репозитория. Здесь абстракция репозитория позволяет значительно сократить объем стандартного кода, необходимого для реализации уровней доступа к данным для различных хранилищ данных.
Джава
xxxxxxxxxx
1
import jakarta.nosql.mapping.Page;
2
import jakarta.nosql.mapping.Pagination;
3
import jakarta.nosql.mapping.Repository;
4
import java.util.stream.Stream;
6
public interface HeroRepository extends Repository<Hero, String> {
8
Stream<Hero> findAll();
10
Page<Hero> findAll(Pagination pagination);
12
Stream<Hero> findByPowersIn(String powers);
14
Stream<Hero> findByAgeGreaterThan(Integer age);
16
Stream<Hero> findByAgeLessThan(Integer age);
18
}
19
import jakarta.nosql.mapping.Page;
22
import jakarta.nosql.mapping.Pagination;
23
import com.google.common.collect.Sets;
24
import javax.enterprise.context.ApplicationScoped;
26
import javax.inject.Inject;
27
import java.util.Optional;
28
import java.util.stream.Collectors;
29
import java.util.stream.Stream;
30
import static java.util.Arrays.asList;
32
34
public class RepositoryService {
35
37
private HeroRepository repository;
38
public void execute() {
40
Hero iron = new Hero("Iron man", 32, Sets.newHashSet("Rich"));
42
Hero thor = new Hero("Thor", 5000, Sets.newHashSet("Force", "Thunder", "Strength"));
43
Hero captainAmerica = new Hero("Captain America", 80, Sets.newHashSet("agility",
44
"Strength", "speed", "endurance"));
45
Hero spider = new Hero("Spider", 18, Sets.newHashSet("Spider", "Strength"));
46
repository.save(asList(iron, thor, captainAmerica, spider));
49
//find by id
50
Optional<Hero> hero = repository.findById(iron.getName());
51
System.out.println(hero);
52
Stream<Hero> youngStream = repository.findByAgeLessThan(20);
54
Stream<Hero> seniorStream = repository.findByAgeGreaterThan(20);
55
Stream<Hero> strengthStream = repository.findByPowersIn("Strength");
56
Stream<Hero> allStream = repository.findAll();
57
String yongHeroes = youngStream.map(Hero::getName).collect(Collectors.joining(","));
59
String seniorsHeroes = seniorStream.map(Hero::getName).collect(Collectors.joining(","));
60
String strengthHeroes = strengthStream.map(Hero::getName).collect(Collectors.joining(","));
61
String allHeroes = allStream.map(Hero::getName).collect(Collectors.joining(","));
62
System.out.println("Young result: " + yongHeroes);
64
System.out.println("Seniors result: " + seniorsHeroes);
65
System.out.println("Strength result: " + strengthHeroes);
66
System.out.println("All heroes result: " + allHeroes);
67
//Pagination
69
Pagination pagination = Pagination.page(1).size(1);
70
Page<Hero> page1 = repository.findAll(pagination);
71
System.out.println("Page 1: " + page1.getContent().collect(Collectors.toList()));
72
Page<Hero> page2 = page1.next();
73
System.out.println("Page 2: " + page2.getContent().collect(Collectors.toList()));
74
Page<Hero> page3 = page1.next();
75
System.out.println("Page 3: " + page3.getContent().collect(Collectors.toList()));
76
}
77
}
На этом мы завершаем первую часть нашей статьи, представляя концепцию Jakarta и NoSQL, а также API документа с MongoDB. Во второй части мы поговорим о нативном облаке и о том, как легко перенести это приложение в облако с помощью Platform.sh. Если вам любопытно и вы не возражаете против спойлера, вы можете взглянуть на пример кода в своем хранилище .
Дальнейшее чтение
Движение Джакарты вперед: Jakarta NoSQL одобрен как проект EE4J