Публичный аккаунт WeChat: стек червоточины bugstack DDD {Domain-Driven Design} имеет долгую историю, но с появлением микросервисов DDD стал более активно привлекать внимание людей. Он предоставляет набор идей архитектурного дизайна. Мы можем использовать эту методологию для проектирования архитектуры в максимально возможной степени. , Добейтесь высокой степени согласованности, низкой связанности и высокой масштабируемости служб приложений. Этот раздел основан на реальной реализации DDD, и в главах разрабатываются различные архитектурные модели. Обучение и борьба — самый быстрый способ войти в прикладной уровень, Hi HelloWorld! Я иду.
Введение
DDD (Domain-Driven Design Domain-Driven Design) был впервые предложен Эриком Эвансом, цель которого состоит в том, чтобы смоделировать домен, связанный с программным обеспечением, чтобы решить проблему сложности программного обеспечения, вызванную большим масштабом системы. Весь процесс примерно таков: команда разработчиков и эксперты в предметной области используют Ubiquitous Language для понимания и усвоения знаний предметной области, извлечения и разделения знаний предметной области на поддомены (основной поддомен, общий поддомен, вспомогательный поддомен). ) и создайте модель в поддомене, а затем повторите описанные выше шаги, чтобы создать набор моделей, соответствующих текущему домену.
цели развития
Опираясь на идею проектирования, ориентированного на предметную область, создайте модель предметной области посредством штормов событий, разумно разделите логику предметной области и физические границы, установите объекты предметной области, матрицы служб и диаграммы архитектуры служб, определите модель структуры кода, которая соответствует Идея многоуровневой архитектуры DDD и обеспечение согласованности бизнес-моделей с моделью кода. С помощью приведенных выше дизайнерских идей, методов и процессов помогите команде завершить проектирование и разработку микросервисов в соответствии с идеей дизайна DDD. 1. Откажитесь от небольших мономеров из грязевых комков, откажитесь от загрязнения функций и услуг и откажитесь от планирования функций «один плюс» на один месяц. 2. Спроектируйте сервисы приложений с высокой доступностью, которые легко справятся с высокоскоростной итерацией Интернета. 3. Материализованные, собранные и организованные услуги для повышения эффективности работы персонала.
Сервисная архитектура
-
прикладной уровень {приложение}
- Службы приложений расположены на прикладном уровне. Он используется для выражения поведения приложений и пользователей, отвечает за композицию, оркестровку и пересылку сервисов, а также отвечает за обработку последовательности выполнения бизнес-прецедентов и сборку результатов.
- Службы прикладного уровня включают службы приложений и службы, связанные с событиями предметной области.
- Службы приложений могут комбинировать и организовывать доменные службы в микрослужбах и службы приложений вне микрослужб или напрямую работать с данными на базовом уровне, такими как файлы и кэши, для формирования служб приложений и предоставлять услуги общего назначения внешнему миру.
- Службы событий предметной области включают две категории: публикация и подписка на события предметной области. Асинхронная передача данных реализована через шину событий и очередь сообщений для реализации развязки между микросервисами.
-
Слой домена {домен}
- Доменные службы расположены на доменном уровне и являются инкапсулированными службами для выполнения преобразования операций между сущностями или объектами-значениями в домене.Доменные службы участвуют в процессе реализации так же, как сущности и объекты-значения.
- Доменные службы объединяют и инкапсулируют один или несколько методов одного и того же объекта или комбинируют или организуют операции нескольких разных сущностей и предоставляют их как доменные службы. Доменные службы инкапсулируют основную бизнес-логику. Поведение самой сущности реализуется внутри класса сущности и инкапсулируется вверх как доступ к доменной службе.
- Чтобы скрыть реализацию бизнес-логики уровня предметной области, все методы и службы предметной области должны быть доступны через службы предметной области.
- Для обеспечения разделения агрегатов внутри микрослужб в принципе запрещены вызовы межагрегатных доменных служб и межагрегатная корреляция данных.
-
базовый уровень {инфраструктура}
- Основные службы расположены на базовом уровне. Предоставляйте службы ресурсов (такие как базы данных, кэши и т. д.) для каждого уровня, реализовывайте развязку каждого уровня и уменьшайте влияние изменений внешних ресурсов на бизнес-логику.
- Базовые службы в основном представляют собой службы хранилища, которые предоставляют базовые службы ресурсов для каждого уровня посредством инверсии зависимостей.Доменные службы и службы приложений вызывают интерфейсы служб хранилища и используют хранилища для реализации постоянных объектов данных или прямого доступа к базовым ресурсам.
-
уровень интерфейса {интерфейсы}
- Служба интерфейса расположена на уровне пользовательского интерфейса, который используется для обработки запроса Restful, отправленного пользователем, анализа файла конфигурации, введенного пользователем и т. д., и передачи информации на прикладной уровень.
среда разработки
1. jdk1.8 [только частично поддерживается netty ниже jdk1.7] 2. пружинная загрузка 2.0.6.РЕЛИЗ 3. идея + мавен
пример кода
itstack-demo-ddd-01
└── src
├── main
│ ├── java
│ │ └── org.itstack.demo
│ │ ├── application
│ │ │ ├── event
│ │ │ │ └── ApplicationRunner.java
│ │ │ └── service
│ │ │ └── UserService.java
│ │ ├── domain
│ │ │ ├── model
│ │ │ │ ├── aggregates
│ │ │ │ │ └── UserRichInfo.java
│ │ │ │ └── vo
│ │ │ │ ├── UserInfo.java
│ │ │ │ └── UserSchool.java
│ │ │ ├── repository
│ │ │ │ └── IuserRepository.java
│ │ │ └── service
│ │ │ └── UserServiceImpl.java
│ │ ├── infrastructure
│ │ │ ├── dao
│ │ │ │ ├── impl
│ │ │ │ │ └── UserDaoImpl.java
│ │ │ │ └── UserDao.java
│ │ │ ├── po
│ │ │ │ └── UserEntity.java
│ │ │ ├── repository
│ │ │ │ ├── mysql
│ │ │ │ │ └── UserMysqlRepository.java
│ │ │ │ ├── redis
│ │ │ │ │ └── UserRedisRepository.java
│ │ │ │ └── UserRepository.java
│ │ │ └── util
│ │ │ └── RdisUtil.java
│ │ ├── interfaces
│ │ │ ├── dto
│ │ │ │ └── UserInfoDto.java
│ │ │ └── facade
│ │ │ └── DDDController.java
│ │ └── DDDApplication.java
│ ├── resources
│ │ └── application.yml
│ └── webapp
│ └── WEB-INF
│ └── index.jsp
└── test
└── java
└── org.itstack.demo.test
└── ApiTest.java
Продемонстрируйте некоторые ключевые блоки кода, загрузите полный код и следуйте официальной учетной записи; стек червоточины багстека | Ответить приземление DDD
application/UserService.java | Пользовательский сервис прикладного уровня, сервис доменного уровня для конкретной реализации
/**
* 应用层用户服务
* 虫洞栈:https://bugstack.cn
* 公众号:bugstack虫洞栈 | 欢迎关注并获取更多专题案例源码
* Create by fuzhengwei on @2019
*/
public interface UserService {
UserRichInfo queryUserInfoById(Long id);
}
domain/repository/IuserRepository.java | Репозиторий уровня домена, реализованный базовым уровнем
/**
* 虫洞栈:https://bugstack.cn
* 公众号:bugstack虫洞栈 | 欢迎关注并获取更多专题案例源码
* Create by fuzhengwei on @2019
*/
public interface IUserRepository {
void save(UserEntity userEntity);
UserEntity query(Long id);
}
domain/service/UserServiceImpl.java | Класс реализации прикладного уровня, прикладной уровень — это очень тонкий слой, который может выполнять только оркестровку служб.
/**
* 虫洞栈:https://bugstack.cn
* 公众号:bugstack虫洞栈 | 欢迎关注并获取更多专题案例源码
* Create by fuzhengwei on @2019
*/
@Service("userService")
public class UserServiceImpl implements UserService {
@Resource(name = "userRepository")
private IUserRepository userRepository;
@Override
public UserRichInfo queryUserInfoById(Long id) {
// 查询资源库
UserEntity userEntity = userRepository.query(id);
UserInfo userInfo = new UserInfo();
userInfo.setName(userEntity.getName());
// TODO 查询学校信息,外部接口
UserSchool userSchool_01 = new UserSchool();
userSchool_01.setSchoolName("振华高级实验中学");
UserSchool userSchool_02 = new UserSchool();
userSchool_02.setSchoolName("东北电力大学");
List<UserSchool> userSchoolList = new ArrayList<>();
userSchoolList.add(userSchool_01);
userSchoolList.add(userSchool_02);
UserRichInfo userRichInfo = new UserRichInfo();
userRichInfo.setUserInfo(userInfo);
userRichInfo.setUserSchoolList(userSchoolList);
return userRichInfo;
}
}
инфраструктура/po/UserEntity.java | класс объекта базы данных
/**
* 数据库实体对象;用户实体
* 虫洞栈:https://bugstack.cn
* 公众号:bugstack虫洞栈 | 欢迎关注并获取更多专题案例源码
* Create by fuzhengwei on @2019
*/
public class UserEntity {
private Long id;
private String name;
get/set ...
}
infrastructrue/repository/UserRepository.java | Интерфейс определения уровня домена, реализация репозитория базового уровня
/**
* 虫洞栈:https://bugstack.cn
* 公众号:bugstack虫洞栈 | 欢迎关注并获取更多专题案例源码
* Create by fuzhengwei on @2019
*/
@Repository("userRepository")
public class UserRepository implements IUserRepository {
@Resource(name = "userMysqlRepository")
private IUserRepository userMysqlRepository;
@Resource(name = "userRedisRepository")
private IUserRepository userRedisRepository;
@Override
public void save(UserEntity userEntity) {
//保存到DB
userMysqlRepository.save(userEntity);
//保存到Redis
userRedisRepository.save(userEntity);
}
@Override
public UserEntity query(Long id) {
UserEntity userEntityRedis = userRedisRepository.query(id);
if (null != userEntityRedis) return userEntityRedis;
UserEntity userEntityMysql = userMysqlRepository.query(id);
if (null != userEntityMysql){
//保存到Redis
userRedisRepository.save(userEntityMysql);
return userEntityMysql;
}
// 查询为NULL
return null;
}
}
interfaces/dto/UserInfoDto.java|Класс объекта DTO, класс изолированной базы данных
/**
* 虫洞栈:https://bugstack.cn
* 公众号:bugstack虫洞栈 | 欢迎关注并获取更多专题案例源码
* Create by fuzhengwei on @2019
*/
public class UserInfoDto {
private Long id; // ID
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
interfaces/facade/DDDController.java|Фасадный интерфейс
/**
* 虫洞栈:https://bugstack.cn
* 公众号:bugstack虫洞栈 | 欢迎关注并获取更多专题案例源码
* Create by fuzhengwei on @2019
*/
@Controller
public class DDDController {
@Resource(name = "userService")
private UserService userService;
@RequestMapping("/index")
public String index(Model model) {
return "index";
}
@RequestMapping("/api/user/queryUserInfo")
@ResponseBody
public ResponseEntity queryUserInfo(@RequestBody UserInfoDto request) {
return new ResponseEntity<>(userService.queryUserInfoById(request.getId()), HttpStatus.OK);
}
}
Подводить итоги
- Вышеупомянутая демонстрация структуры, основанная на базовом введении в DDD, завершена, и фактическая разработка может быть скорректирована в соответствии с этим режимом.
- В настоящее время архитектурные слои не могут быть четко разделены, а ссылка на иерархические отношения не способствует расширению.
- В будущем мы продолжим улучшать и создавать RPC-фреймворки в сочетании, чтобы сделать всю архитектуру более благоприятной для развития Интернета.