к непредсказуемым проблемам с производительностью • Сложная раздутая спецификация с проблемами версий от разных вендоров • Специфические протоколы поверх tcp/ip, порты которых часто попадали под блокировки
к непредсказуемым проблемам с производительностью • Сложная раздутая спецификация с проблемами версий от разных вендоров • Специфические протоколы поверх tcp/ip, порты которых часто попадали под блокировки
• Удобство параллелизации разработки • Стандартный, простой и надёжный канал связи (передача текста по HTTP через порт 80). • Оптимизированный обмен сообщениями
• Удобство параллелизации разработки • Стандартный, простой и надёжный канал связи (передача текста по HTTP через порт 80). • Оптимизированный обмен сообщениями • Стабильная спецификация обмена сообщениями. • Изолированность контекстов доменов (Domain contexts).
простой и надёжный канал связи • Оптимизированный обмен сообщениями. • Стабильная спецификация обмена сообщениями. • Асинхронность обмена сообщениями и управление нагрузкой на систему.
простой и надёжный канал связи • Оптимизированный обмен сообщениями. • Стабильная спецификация обмена сообщениями. • Асинхронность обмена сообщениями и управление нагрузкой на систему. • Единая точка для управления версионированием и преобразованием форматов
сервисами. • Единая точка отказа, способная обрушить системы связи всей компании. • Большая сложность конфигурирования и поддержки. • Шина так сложна, что для её управления вам потребуется целая команда.
или простота поддержки? • Как не сожрать все ресурсы? • Как собирать логи и как мониторить? • Как обновлять api и не сломать совместимость? • Как обновлять без даунтайма?
или простота поддержки? • Как не сожрать все ресурсы? • Как собирать логи и как мониторить? • Как обновлять api и не сломать совместимость? • Как обновлять без даунтайма? • Как масштабировать и балансировать нагрузку? • Как отслеживать и останавливать распространение ошибок?
или простота поддержки? • Как не сожрать все ресурсы? • Как собирать логи и как мониторить? • Как обновлять api и не сломать совместимость? • Как обновлять без даунтайма? • Как масштабировать и балансировать нагрузку? • Как отслеживать и останавливать распространение ошибок? • Как не закопать бизнес-логику среди инфраструктурных классов? • Как обновлять общие механизмы?
или простота поддержки? • Как не сожрать все ресурсы? • Как собирать логи и как мониторить? • Как обновлять api и не сломать совместимость? • Как обновлять без даунтайма? • Как масштабировать и балансировать нагрузку? • Как отслеживать и останавливать распространение ошибок? • Как не закопать бизнес-логику среди инфраструктурных классов? • Как обновлять общие механизмы? • Как не угробить расплывающуюся архитектуру? • Как ...
with spring dispatcher servlet, spring listener and security filter name Security filters, users and roles Spring MVC beans Application beans, Import security.xml The project structure
create Spring ContextLoaderListener Start tomcat start applicationContext In bootsrap In bootsrap Create filter mapping Create security filter login Create spring dispatcher servlet Delegate to Controller
is looked up via the jar services API. For each application, an instance of the ServletContainerInitializer is created by the container at application startup time. The framework providing an implementation of the ServletContainerInitializer MUST bundle in the META-INF/services directory of the jar file a file called javax.servlet.ServletContainerInitializer, as per the jar services API, that points to the implementation class of the ServletContainerInitializer. 3.+
method get's a Set of Classes that either extend / implement the classes that the initializer expressed interest in or if it is annotated with any of the classes specified via the @HandlesTypes annotation. 3.+
get all WebApplicationInitializer classes (from @HandlesTypes) |→ call ServletContainerInitializer.onStartup(classes,servletCtx) according to @Order order
сканирует проект – ищет мейны • если есть только один – то это он :) • если больше одного – смотрит где стоит @SpringBootApplication и выбирает его • если @SpringBootApplication нет или >1 – ошибка о множественных main при сборке
the hood, auto-configuration is implemented with standard @Configuration classes. Additional @Conditional annotations are used to constrain when the auto-configuration should apply. Usually auto-configuration classes use @ConditionalOnClass and @ConditionalOnMissingBean annotations. This ensures that auto-configuration only applies when relevant classes are found and when you have not declared your own @Configuration. You can browse the source code of spring-boot-autoconfigure to see the @Configuration classes that we provide (see theMETA-INF/spring.factories file).
@ConditionalOnMissingBean ({ФабрикаКазни. class}) public ФабрикаКазни виселицы() { return new ФабрикаВиселиц( "..."); } @Bean @ConditionalOnClass ({Стул.class, Ток.class}) @ConditionalOnMissingBean ({ФабрикаКазни. class}) public ФабрикаКазни cтулья() { return new ФабрикаЭлектрическихСтульев( "вж вж"); } @Bean @ConditionalOnClass ({Гильотина.class, ХорошееНастроение. class}) @ConditionalOnMissingBean ({ФабрикаКазни. class}) public ФабрикаКазни гильотины() { return new ФабрикаГильотин( "хрусть хрусть"); } } 1. ClassDefNotFound ? 2. Так вообще нельзя, не компилируется 3. Будет работать 4. Будет отлично работать
@ConditionalOnMissingBean ({ФабрикаКазни. class}) public ФабрикаКазни виселицы() { return new ФабрикаВиселиц( "..."); } @Bean @ConditionalOnClass ({Стул.class, Ток.class}) @ConditionalOnMissingBean ({ФабрикаКазни. class}) public ФабрикаКазни cтулья() { return new ФабрикаЭлектрическихСтульев( "вж вж"); } @Bean @ConditionalOnClass ({Гильотина.class, ХорошееНастроение. class}) @ConditionalOnMissingBean ({ФабрикаКазни. class}) public ФабрикаКазни гильотины() { return new ФабрикаГильотин( "хрусть хрусть"); } } 1. ClassDefNotFound ? 2. Так вообще нельзя, не компилируется 3. Будет работать 4. Будет отлично работать
Application extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder a) { return application.sources(Application.class); } public static void main(String[] args) throws Exception { SpringApplication.run(Application.class, args); } } Без main не соберется см. maven/gradle плагины Обязательно
Application extends SpringBootServletInitializer { @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder a) { return application.sources(Application.class); } public static void main(String[] args) throws Exception { SpringApplication.run(Application.class, args); } } Никогда не запустится в embedded режиме Только в Tomcat контейнере Опционально
a version of Gradle that supports compile only dependencies (2.12 or later), you should continue to use providedRuntime. Among other limitations, compileOnly dependencies are not on the test classpath so any web-based integration tests will fail.
написать Сервис: - принимающий на вход объект SolvedExam - отдающий CheckedExam с оценкой - Должны проходить тесты @Test public void checkExamineContract() throws Exception { ... mockMvc.perform(post("/examine")) ... } Use @RestController and @RequestMapping > @*Mapping Luke
написать Сервис: - принимающий на вход объект SolvedExam - отдающий CheckedExam с оценкой - Смотрите в src/test/resources/*.json - Должны проходить тесты @Test public void checkExamineContract() throws Exception { ... mockMvc.perform(post("/examine")) ... } Use @RestController and @RequestMapping > @*Mapping Luke
→ выставляет через Setters → если нет Setter и есть Getter – выставляет напрямую в филды → это все только при наличии пустого конструктора 2. Есть конструктор с @ConstructProperies → выставляет значение через него 3. После зачем то вызовет все геттеры * Но если есть то @JsonIgnore всё по другому * Это поведение по умолчанию
.registerModule( new ParameterNamesModule()) .registerModule( new Jdk8Module()) .registerModule( new JavaTimeModule()); → Или так: mapper.findAndRegisterModules(); Не забыть зависимости: compile 'com.fasterxml.jackson.module:jackson-module-parameter-names' compile 'com.fasterxml.jackson.datatype:jackson-datatype-jdk8' compile 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310' C последних версий есть поддержка Java8
… (CRUD) 2. Получать нужное количество рандомальных вопросов 3. Тест должен проходить @Test public void should_return_random_exercise() throws Exception { mvc.perform(get("/exercise/random?count=3") .contentType( APPLICATION_JSON) ) … Use JpaRepository and @RequestMapping Luke
ли лезть в атом? Теорема Пифагора Неравенство Коши ваы Количество вопросов Количество вопросов Экзаминатор Person p = restTemplate.getForObject("/{name}/details", Person.class, name); Для связи сервисов используем RestTemplate
defaults? Name Description DEFAULT Exposes all public repository interfaces but considers @Repository/@RestResource’s `exported flag ALL Exposes all repositories independently of type visibility and annotations ANNOTATION Only repositories annotated with @Repository/@RestResource are exposed, unless their exported flag is set to false VISIBILITY Only public repositories annotated are exposed
repositoryRestConfigurer() { return new RepositoryRestConfigurerAdapter() { @Override public void configureRepositoryRestConfiguration( RepositoryRestConfiguration config) { configuration.setBasePath( "/api") } }; } } Или в том же RepositoryRestConfigurerAdapter прописать в application.properties - spring.data.rest.base-path=/api
• и тесты для него • тестируем контракт • тестируем взаимодействие ◦ WireMock/Spring MockServer ◦ Spring Boot Test ◦ Context Scanning behaviour Тест SDK Тест Контракта Тест Взаимодействия
@Никаких Аннотация не нужно в 2хх eureka.client.service-url.default-zone: http://127.0.0.1:8761/eureka/ spring.application.name: EXAMINATOR Spring Boot 1.x.x Spring Boot 2.x.x
• Запустить несколько сервисов одного типа, посмотреть результат @Autowired private DiscoveryClient discoveryClient; discoveryClient.getServices() discoveryClient.getInstances("theology")
которым есть интеграция * Но есть ньюансы RestTemplate — более общий инструмент, подойдёт в большем спектре случай, но решение будет читаться хуже и будет больше технических деталей
setters @Aspect // we are an aspect @ToString // generate toString() @EnableWs // SOAP is so enterprisy, we definitely need it @Endpoint // Seriously, just read above @EnableWebMvc // we want MVC @EnableCaching // and we want to cache stuff @Configuration // this class can configure itself @RestController // we want some REST @XmlRootElement // this component is marshallable @EnableWebSocket // we want web socket, it's so new-generation @RedisHash("cat") // this class is an entity saved in redis @EnableScheduling // we want scheduled tasks @EnableWebSecurity // and some built-in security @NoArgsConstructor // generate no args constructor @ContextConfiguration // we want context configuration for unit testing @SpringBootApplication // this is a Sprint Boot application @Accessors(chain = true) // getters/setters are chained (ala jQuery) @EnableAspectJAutoProxy // we want AspectJ auto proxy @EnableAutoConfiguration // and auto configuration
сonfig-server (для всех же одинаковые) • из локальных настроек (ENV/*.yml/etc) Откуда брать координаты сonfig-server • из eureka • из локальных настроек (ENV/*.yml/etc)
обновлять 2. Обновляем в config server foo.bar: some val a. Можно не править а дёрнуть /env если есть actuator 3. Дёргаем у приложения /refresh a. Для этого нужен actuator
при получении refresh ивента в rabbitmq 2. Для автоматизации можно использовать config-monitor + git webhook compile 'org.springframework.cloud:spring-cloud-config-monitor' 3. Не забывать @RefreshScope
Zuul 2 ждали долго • Zuul не совместим с Spring Boot 2.1 • Spring Cloud Gateway работает на Netty • Spring Cloud Gateway имеет сильно больше фильтров “из коробки”
LB App Level LB App Type A Client Side LB App Type A Client Side LB App Type A Client Side LB App Type B Client Side LB App Type B Client Side LB App Type B Client Side LB Zuul haproxy F5 SSL/DDOS/ Protection/BGP/Publication Data Locality/Cluster HA/ Cluster Health App Level LB/Metrics/ Advanced Routing/Auth
LB App Level LB App Type A Client Side LB App Type A Client Side LB App Type A Client Side LB App Type B Client Side LB App Type B Client Side LB App Type B Client Side LB Zuul haproxy F5 SSL/DDOS/ Protection/BGP/Publication Data Locality/Cluster HA/ Cluster Health App Level LB/Metrics/ Advanced Routing/Auth
LB App Level LB App Type A Client Side LB App Type A Client Side LB App Type A Client Side LB App Type B Client Side LB App Type B Client Side LB App Type B Client Side LB Zuul haproxy F5 SSL/DDOS/ Protection/BGP/Publication App Level LB/Metrics/ Advanced Routing/Auth Discovery service Discovery service Discovery service Data Locality/Cluster HA/ Cluster Health
Не пытается сам управлять пулом потоков • Нет request collapser • Есть rate limiter • Есть retry • Удобное оборачивание методов “слоями” в функциональном стиле или набором аннотаций • Собранные “обертки” можно переиспользовать
TraceId No SpanId TraceId = X SpanId = A TraceId = X SpanId = B TraceId = X SpanId = C TraceId = X SpanId = D TraceId = X SpanId = D TraceId = X SpanId = E TraceId = X SpanId = E TraceId = X SpanId = F TraceId = X SpanId = G
TraceId No SpanId TraceId = X SpanId = A TraceId = X SpanId = B TraceId = X SpanId = B TraceId = X SpanId = C TraceId = X SpanId = C TraceId = X SpanId = D TraceId = X SpanId = D TraceId = X SpanId = E TraceId = X SpanId = E TraceId = X SpanId = F TraceId = X SpanId = G
= X SpanId = A No TraceId No SpanId TraceId = X SpanId = A TraceId = X SpanId = A TraceId = X SpanId = B TraceId = X SpanId = B TraceId = X SpanId = C TraceId = X SpanId = C TraceId = X SpanId = D TraceId = X SpanId = D TraceId = X SpanId = E TraceId = X SpanId = E TraceId = X SpanId = F TraceId = X SpanId = G
describes how to be the most fundamental and important document in the world of documents include::https://raw.github.com/asciidoctor/asciidoctor/master/Gemfile[] include::../other.adoc[] include::/home/tolkv/git/docs-0/superdoc.adoc[] 495
how to be the most fundamental and important document in the world of documents include::https://raw.github.com/asciidoctor/asciidoctor/master/Gemfile[] include::gradle://gradle-advanced:service-with-deps:1.0/deps.adoc[] include::gradle://:service/doc.adoc[] 496