Этот урок освещает работу с Spring Framework IoC контейнером и основан на оригинальной документации §5. The IoC container.
Что вы создадите
Вы создадите некоторое количество классов, в которых будет рассмотрена функциональность Spring Framework IoC контейнера.
Что вам потребуется
- Любимый текстовый редактор или IDE
- JDK 7 и выше
- Maven 3.0+
- Исходный код предыдущего урока
Настройка проекта
Прежде чем вы начнете изучать этот урок, вам необходимо внести некоторые изменения в проект. Для начала создайте структуру папок src/main/resources и переместите в него файл настроек логгирования log4j.properties , тем самым поместив его в classpath проекта. Теперь немного измените файл сборки pom.xml , добавив и изменив в нем следующее:
. 1.7 1.5.8 . org.slf4j jcl-over-slf4j $ org.slf4j slf4j-api $ org.slf4j slf4j-log4j12 $ . org.apache.maven.plugins maven-compiler-plugin 3.2 $ $ $ -Xlint:all true true .
И наконец, создайте структуру папок src/main/java/lessons/starter/ . В данном пакете вы будете создавать классы с методами public static void main(String[] args) , которые вы будете запускать для того, чтобы можно было видеть результаты действий в процессе изучения данного материала.
Не признали Мистера Бина
Введение
Inversion of Control (IoC), также известное как Dependency Injection (DI), является процессом, согласно которому объекты определяют свои зависимости, т.е. объекты, с которыми они работают, через аргументы конструктора/фабричного метода или свойства, которые были установлены или возвращены фабричным методом. Затем контейнер inject(далее «внедряет») эти зависимости при создании бина. Этот процесс принципиально противоположен, поэтому и назван Inversion of Control, т.к. бин сам контролирует реализацию и расположение своих зависимостей, используя прямое создание классов или такой механизм, как шаблон Service Locator.
Основными пакетами Spring Framework IoC контейнера являются org.springframework.beans и org.springframework.context . Интерфейс BeanFactory предоставляет механизм конфигурации по управлению любым типом объектов. ApplicationContext — наследует нитерфейс BeanFactory и добавляет более специфичную функциональность. Ниже в таблице представлены различия между ними:
Функционал
BeanFactory
ApplicationContext
Инициализация/автоматическое связывание бина
Автоматическая регистрация BeanPostProcessor
Автоматическая регистрация BeanFactoryPostProcessor
Удобный доступ к MessageSource (для i18n)
ApplicationEvent публикация
В большинстве случаев предпочтительно использовать ApplicationContext , поэтому в дальнейшем будет использоваться только он и его реализации. Поскольку он включает в себя всю функциональность BeanFactory , его можно и нужно использовать, за исключением случаев, когда приложение запускается на устройствах с ограниченными ресурсами, в которых объем потребляемой памяти может быть критичным, даже в пределах нескольких килобайт, либо когда вы разрабатываете приложение, в котором необходима поддержка совместимости со сторонними библиотеками, использующими JDK 1.4 или не поддерживают JSR-250. Spring Framework активно использует BeanPostProcessor для проксирования и др., поэтому, если вам необходима поддержка такой функциональности, как AOP и транзакций, то при использовании BeanFactory необходимо добавить вручную регистрацию BeanPostProcessor и BeanFactoryPostProcessor , как показано ниже:
5 СТРАШНЫХ вещей сказанных роботами
ConfigurableBeanFactory factory = new XmlBeanFactory(. ); // теперь зарегистрируем необходимый BeanPostProcessor экземпляр MyBeanPostProcessor postProcessor = new MyBeanPostProcessor(); factory.addBeanPostProcessor(postProcessor); // запускаем, используя factory
XmlBeanFactory factory = new XmlBeanFactory(new FileSystemResource(«beans.xml»)); // получаем какое-то значения свойства из Properties-файла PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer(); cfg.setLocation(new FileSystemResource(«jdbc.properties»)); // теперь заменяем значение свойства на новое cfg.postProcessBeanFactory(factory);
Описание работы IoC контейнера
Ниже представлена диаграмма, отражающая, как работает Spring. Ваши классы приложения совмещаются с метаданными конфигурации, в результате чего будет создан и инициализирован ApplicationContext , а на выходе вы получите полностью настроенное и готовое к выполнению приложение.
ApplicationContext представляет собой Spring IoC контейнер и необходим для инициализации, настройки и сборки бинов для построения приложения.
В метаданных конфигурации разработчик описывает как инициализировать, настроить IoC контейнер и собрать объекты в вашем приложении. В данном и других уроках этого цикла везде, где возможно, будет использоваться подход на основе аннотаций и Java-конфигурации. Если вы сторонник XML-конфигурации, либо хотите посмотреть как делать тоже самое через XML, обратитесь к оригинальной документации по Spring Framework или соответствующего модуля/проекта.
Настройка IoC контейнера
public class Starter < private static final Logger logger = LogManager.getLogger(Starter.class); public static void main(String[] args) < logger.info(«Starting configuration. «); ApplicationContext context = new AnnotationConfigApplicationContext(LessonsConfiguration.class); >>
Как вариант, можно инициализировать контекст(ы) таким образом:
public class Starter < private static final Logger logger = LogManager.getLogger(Starter.class); public static void main(String[] args) < logger.info(«Starting configuration. «); AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.register(LessonsConfiguration.class); context.refresh(); >>
package lessons.services; public interface GreetingService
Теперь, для того, чтобы объект с типом GreetingService был доступен для использования, необходимо описать его в конфигурации следующим образом:
А для того, чтобы использовать его, достаточно выполнить следующее:
public class Starter < private static final Logger logger = LogManager.getLogger(Starter.class); public static void main(String[] args) < logger.info(«Starting configuration. «); ApplicationContext context = new AnnotationConfigApplicationContext(LessonsConfiguration.class); GreetingService greetingService = context.getBean(GreetingService.class); logger.info(greetingService.sayGreeting()); // «Greeting, user!» >>
Метод getBean() может принимать в качестве аргумента как класс(как показано выше), так и названия бина(подробнее будет рассмотрено ниже), либо другие варианты, с которыми вы можете ознакомится в документации. Однако такой подход не рекомендуется использовать в production-конфигурациях, т.к. для подобных целей существует механизм Dependency Injection (DI), собственно говоря, для чего и предназначен Spring IoC контейнер. Использование DI будет рассмотрено ниже в отдельной главе.
Именовать бины принято в соответствии со стандартным соглашением по именованию полей Java-классов. Т.е. имена бинов должны начинаться со строчной буквы и быть в «Верблюжьей» нотации.
Жизненный цикл бина
При совместном использовании методов, интерфейсов и аннотаций, описанных выше, учитывайте их порядок вызовов. Для методов инициализации порядок будет следующий:
Для методов разрушения порядок будет следующий:
Если вам необходимо реализовать свою собственную модель жизненного цикла бина, то в таком случае бин должен реализовывать один из интерфейсов, приведенных ниже:
public interface Lifecycle
public interface LifecycleProcessor extends Lifecycle
public interface SmartLifecycle extends Lifecycle, Phased
SmartLifecycle интересен тем, что наследует интерфейс Phased , в котором есть метод int getPhase(); . Суть в том, что порядок создания бинов, реализующих этот интерфейс, зависит от возвращаемого методом значения и чем оно меньше, тем раньше всех будет создан бин и тем позже он будет разрушен.
Если вы на данном этапе запустите Starter.java , то в логах увидите, что методы разрушения не вызываются, однако программа завершает свою работу корректно. Дело в том, что для обычных приложений для этих целей стоит инициализировать контекст с типом AbstractApplicationContext , который также реализует ApplicationContext и имеет метод registerShutdownHook() . В итоге, у вас должно быть премерно следующее:
public class Starter < private static final Logger logger = LogManager.getLogger(Starter.class); public static void main(String[] args) < logger.info(«Starting configuration. «); AbstractApplicationContext context = new AnnotationConfigApplicationContext(LessonsConfiguration.class); GreetingService greetingService = context.getBean(GreetingService.class); logger.info(greetingService.sayGreeting()); // «Greeting, user!» context.registerShutdownHook(); >>
После этого у вас появятся результаты работы методов при разрушении бина. Однако стоит заметить ещё раз, что это относится к обычным приложения, не относящимся к web-приложения(поскольку для них применяется отдельный тип контекста и подобный метод в них уже есть).
В некоторых случаях необходимо производить манипуляции с ApplicationContext ‘ом, например, в самом бине. Для этого существуют интерфейсы *Aware , полный список которых приведен в таблице 5.4 документации. Поэтому когда ApplicationContext создает экземпляр бина, он учитывает соответствующий интерфейс и передает ссылку на соответствующий ресурс.
Области видимости(scopes) бинов
Когда вы создаете определение бинов, вы вы создаете рецепт для создания экземпляров класса, который определяет бин. Важно понять, что определение бинов является рецептом, потому что он означает, какого класса вы можете создать множество экземпляров по этому рецепту.
Вы можете контролировать не только какие зависимости и значения конфигурации вы можете подключить в объекте, который создан из определения бина, но также область видимости из того же определения бина. Это мощный и гибкий подход, при котором вы можете выбрать область видимости создаваемых объектов. Изначально, Spring Framework поддерживает несколько вариантов, некоторые доступны, только если вы используете web-aware ApplicationContext . Также вы можете создать свою собственную облать видимости. Ниже приведен список областей видимостей, описанных в документации на момент написания урока:
- singleton — По умолчанию. Spring IoC контейнер создает единственный экземпляр бина. Как правило, используется для бинов без сохранения состояния(stateless)
- prototype — Spring IoC контейнер создает любое количество экземпляров бина. Новый экземпляр бина создается каждый раз, когда бин необходим в качестве зависимости, либо через вызов getBean() . Как правило, используется для бинов с сохранением состояния(stateful)
- request — Жизненный цикл экземпляра ограничен единственным HTTP запросом; для каждого нового HTTP запроса создается новый экземпляр бина. Действует, только если вы используете web-aware ApplicationContext
- session — Жизненный цикл экземпляра ограничен в пределах одной и той же HTTP Session . Действует, только если вы используете web-aware ApplicationContext
- global session — Жизненный цикл экземпляра ограничен в пределах глобальной HTTP Session (обычно при использовании portlet контекста). Действует, только если вы используете web-aware ApplicationContext
- application — Жизненный цикл экземпляра ограничен в пределах ServletContext . Действует, только если вы используете web-aware ApplicationContext
С более подробной информацией о настройке приложения для применения областей видимости request , session , global session и application вы можете ознакомиться в документации. Пример реализации собственной области видимости будет рассмотрено в отдельном уроке.
Кода бин имеет зависимость от другого бина, то зависимость выражается просто как вызов метода:
Представим теперь ситуацию, когда у вас есть бин с областью видимости singleton , который имеет зависимость от бина с областью видимости prototype .
public abstract class CommandManager
Таким образом, при инициализации контекста вам не нужно дополнительно указывать загрузку из конфигурации AnotherConfiguration , все останется так, как и было:
public class Starter < private static final Logger logger = LogManager.getLogger(Starter.class); public static void main(String[] args) < logger.info(«Starting configuration. «); ApplicationContext context = new AnnotationConfigApplicationContext(LessonsConfiguration.class); GreetingService greetingService = context.getBean(GreetingService.class); BeanWithDependency withDependency = context.getBean(BeanWithDependency.class); logger.info(greetingService.sayGreeting()); // «Greeting, user!» logger.info(withDependency.printText()); // «Some text!» >>
При этом LessonsConfiguration остается без изменений:
jdbc.url=jdbc:hsqldb:hsql://localhost/xdb
Процесс разрешения зависимостей
IoC контейнер выполняет разрешение зависимостей бинов в следующем порядке:
- Создается и инициализируется ApplicationContext с метаданными конфигурации, которые описывают все бины. Эти метаданные могут быть описаны через XML, Java-код или аннотации
- Для каждого бина и его зависимостей вычисляются свойства, аргументы конструктора или аргументы статического фабричного метода, либо обычного(без аргументов) конструктора. Эти зависимости предоставляются бину, когда он(бин) уже создан. Сами зависимости инициализируются рекурсивно, в зависимости от вложенности в себе других бинов. Например, при инициализации бина А, котый имеет зависимость В, а В зависит от С, сначала инициализируется бин С, потом В, а уже потом А
- Каждому свойству или аргументу конструктора устанавливается значение или ссылка на другой бин в контейнере
- Для каждого свойства или аргумента конструктора подставляемое значение конвертируется в тот формат, который указан для свойства или аргумента. По умолчанию Spring может конвертировать значения из строкового формата во все встроенные типы, такие как int , long , String , boolean и др.
Spring каждый раз при создании контейнера проверяет конфигурацию каждого бина. И только бины с областью видимости(scope) singleton создаются сразу вместе со своими зависимостями, в отличие от остальных, которые создаются по запросу и в соответствии со своей областью видимости. В случае цикличной зависимости(когда класс А требует экземпляр В, а классу В требуется экземпляр А) Spring IoC контейнер обнаруживает её и выбрасывает исключение BeanCurrentlyInCreationException .
Spring контейнер может разрешать зависимости между бинами через autowiring(далее, автоматическое связывание). Данный механизм основан на просмотре содержимого в ApplicationContext и имеет следующие преимущества:
- Автоматическое связывание позволяет значительно сократить количество инструкций для указания свойств или аргументов конструктора
- Автоматическое связывание позволяет обновлять конфигурацию, несмотря на развитие ваших объектов. К примеру, вам необходимо добавить зависимость в классе и эта зависимость может быть разрешена без необходимости модификации конфигурации. Поэтому автоматическое связывание может быть особенно полезным при разработке, не исключая возможность переключения на явное описание, когда кодовая база будет стабильна
Использование стандартных JSR-330 аннотаций
Spring Framework поддерживает JSR-330 аннотации. Эти аннотации работают таким же способом, как и Spring аннотации. Для того, чтобы работать с ними, необходимо добавить в pom.xml следующую зависимость:
javax.inject javax.inject 1
Ниже приведена таблица сравнения JSR-330 и Spring аннотаций для DI:
Источник: spring-projects.ru
Обратная сторона Spring
Неделя Spring на Хабре, судя по всему, открыта. Хочется сказать спасибо переводчику и комментаторам статьи «Почему я ненавижу Spring», которая не смотря на сильный негативный посыл в названии вызвала ряд интересных дискуссий, а так же тем, кто отреагировал на мою прошлую статью Как писать на Spring в 2017. Во многом благодаря комментариям к прошлой статье и появилась эта.
В этот раз мы погрузимся в пучины Spring фреймворка, разоблачим его магию, посмотрим как базовое веб приложение выглядит изнутри, и разберемся, какую-же задачу и как решает Spring Boot.
В комментариях к предыдущей статье несколько человек очень справедливо указали, что пример Hello World-а на Spring все же не очень показателен. Spring, особенно с использованием Spring Boot, дает ощущение простоты и всемогущества, но непонимание основ и внутренностей фреймворка ведет к большой опасности получить стектрейсом по логу. Что ж, чтобы немного развеять ощущение полной магии происходящего, сегодня мы возьмем приложение из предыдущей статьи и разберем, как и что происходит внутри фреймворка и от каких проблем нас отгораживает Boot. Целевая аудитория все же начинающие разработчики, но с некоторым опытом и базовыми знаниями Java и Spring. Хотя, возможно, и опытным пользователям Spring будет интересно освежить знания того, что происходит под капотом.
Ключевые понятия
Бины
Начнем срывать покровы с самых базовых понятий Spring. Бин (bean) — это не что иное, как самый обычный объект. Разница лишь в том, что бинами принято называть те объекты, которые управляются Spring-ом и живут внутри его DI-контейнера. Бином является почти все в Spring — сервисы, контроллеры, репозитории, по сути все приложение состоит из набора бинов. Их можно регистрировать, получать в качестве зависимостей, проксировать, мокать и т.п.
DI контейнер
Ключевой и фундаментальный механизм Spring. Внешне очень простой, но внутри он предоставляет очень много механизмов для тонкой настройки зависимостей. По сути, любое приложение Спринг — это набор бинов, связанных вместе через DI контейнер.
Очень часто при обсуждении Spring звучит аргумент, что его можно легко заменить на любой леговесный DI контейнер (Guice, например) и получить то же самое, но легче и проще. И здесь очень важно понять — ценность Spring DI не в самом факте его наличия, а в его фундаментальности.
Все библиотеки в экосистеме Spring, по сути, просто регистрируют свои бины в этом контейнере (включая и сам Spring) — и через иньекцию зависимостей разработчики приложения смогут получить нужные компоненты. Простой пример: при использовании Spring Security OAuth если сконфигурить параметры OAuth в application.properties , то Spring Security предоставит бин OAuth2RestTemplate который мы можем просто заинжектить в своем коде.
И этот бин при обращении к внешнему API будет знать, куда и как пойти, чтобы получить OAuth токен, как его обновлять, в какое место нашего запроса его добавлять и т.п. Так вот ценность DI тут в том, что это просто механизм общения между нашим кодом и Spring Security. И простой заменой реализации DI на Guice не добиться, чтобы Spring Security тоже начал его использовать. А если в этом новом DI не будет интеграции со всеми библиотеками Spring-а, то и ценность его сильно падает.
Еще один очень важный момент, который многие упускают при обсуждении DI контейнера, это то, что использование инъекции зависимостей не подразумевает создания интерфейсов для каждого компонента. Это очень простая мысль, но я много раз видел, что из-за своей простоты она не всегда очевидна.
Более того, создание интерфейса, если у него лишь одна реализация — считается плохой практикой. Т.е. классы вполне могут сами по себе быть объектами DI. Более того, отсутствие интерфейса даже не мешает их мокать в тестах, т.к. Mockito, например, вполне умеет мокать классы.
Контекст
Представлен интерфейсом ApplicationContext . По сути, представляет собой само приложение Spring. Так же контекст предоставляет возможности реагировать на различные события, которые происходят внутри приложения, управлять жизненным циклом бинов (создавать как синглтон или на каждый запрос, например).
Конфигурация
Итак, если приложение — это набор бинов, чтобы оно заработало нам нужно этот набор описать.
Конфигурация — это просто описание доступных бинов. Spring дает несколько вариантов, как можно описать набор бинов, которые сформируют приложение. Исторический вариант — это через набор xml файлов. В наши дни ему на смену пришли Java аннотации. Spring Boot построен на аннтациях чуть более, чем полностью и большинство современных библиотек в принципе тоже можно сконфигурить через аннотации. В третьем своем поколении, конфигурация бинов пришла к подходу функциональной регистрации (functional bean registration), которая станет одной из важных новых фич готовящегося к выходу Spring 5.
Типичный класс конфигурации может, выглядеть, например так:
Эта конфигурация определяет два бина, причем второй зависит от первого. И здесь в игру вступит Spring – когда мы просим предоставить инстанс PaymentProvider — Spring найдет его в контексте и предоставит нам.
Сканирование компонентов
и разрешим сканирование компонентов — то Spring сам создаст и зарегистрирует бин с именем myCoolComponent , использовав конструктор класса и заинжектив туда все зависимости.
Резюме
Spring Boot
Теперь переходим к следующей части. Допустим, нам надо сконфигурить подключение к MySQL базе данных. Если мы хотим использовать Spring Data JPA с Hibernate в качестве провайдера, нам потребуется сконфигурировать несколько бинов — EntityManagerFactory (основной класс JPA), DataSource для подключения непосредственно к базе через JDBC драйвер и т.п.
Но с другой стороны, если мы это делаем каждый раз и, по сути, делаем одно и то же — почему бы это не автоматизировать? Скажем, если мы указали строку подключения к базе и добавили зависимость на MySQL драйвер — почему бы чему-то автоматически не создать все нужные бины для работы с MySQL? Именно это и делает Spring Boot. По сути, Spring Boot это просто набор классов конфигурации, которые создают нужные бины в контексте. Точно так же их можно создать руками, просто Boot это автоматизирует.
Автоконфигурация
Важное понятие Spring Boot это автоконфигурация. По сути, это просто набор конфигурационных классов, которые создают и регистрируют определенные бины в приложении. По большому счету, даже сам Embedded Servlet Container — это просто еще один бин, который можно сконфигурировать! Пара важных моментов, которые важно знать об автоконфигурации:
Условия и порядок регистрации бинов
Spring Boot активно использует эти аннотации чтобы оставаться как можно более незаметным и не перекрывать пользовательские конфигурации.
Погружение в Hello World
Теперь, имея в запасе базовые теоретические знания, разберем что же происходит при запуске приложения.
Итак, наше приложение включает такой код:
Давайте разберем что здесь происходит по шагам.
Класс DemoApplication
SpringApplication.run()
Это просто хелпер, который делает пару вещей — используя список предоставленных конфигураций (а класс DemoApplication сам по себе конфигурация, см. выше) создает ApplicationContext , конфигурирует его, выводит баннер в консоли и засекает время старта приложения и т.п. Его можно заменить на ручное создание контекста: new AnnotationConfigApplicationContext(DemoApplication.class) . Как можно понять из названия, это контекст приложения, который конфигурируется с помощью аннотаций. Однако, этот контекст не знает ничего об embedded servlet container-ах, и совершенно точно не умеет себя запускать. Его наследник, уже из Spring Boot — AnnotationConfigEmbeddedWebApplicationContext делать это вполне умеет, и если мы в методе main напишем просто
То получим точно такое же работающее приложение, т.к. класс AnnotationConfigEmbeddedWebApplicationContext найдет в контексте бин типа EmbeddedServletContainerFactory и через него создаст и запустит встроенный контейнер. Обратите внимание, что все это работает в рамках общего DI контейнера, то есть этот класс можно реализовать самим.
Эта аннотация включает автоконфигурацию. И здесь, пожалуй, ключевой момент в развенчании магии Spring. Вот как объявлена эта аннотация:
Т.е. это самый обычный импорт конфигурации, про который мы говорили выше. Класс же EnableAutoConfigurationImportSelector (и его преемник в Spring Boot 1.5+ — AutoConfigurationImportSelector ) это просто конфигурация, которая добавит несколько бинов в контекст. Однако, у этого класса есть одна тонкость — он не объявляет бины сам, а использует так называемые фабрики.
Класс EnableAutoConfigurationImportSelector смотрит в файл spring.factories и загружает оттуда список значений, которые являются именами классов (авто)конфигураций, которые Spring Boot импортирует.
Кусочек файла spring.factories (он находится в папке META-INF внутри spring-boot-autoconfigure..jar ), который нам сейчас нужен это:
org.springframework.boot.autoconfigure.EnableAutoConfiguration= org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration, . (100 lines) org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration
По сути, ее можно заменить на ручной импорт нужных конфигураций:
Однако, особенность в том, что Spring Boot пытается применить все конфигурации (а их около сотни). Я думаю, у внимательного читателя уже появилась пара вопросов, которые стоит прояснить.
Краткое резюме
В основе «магии» Spring Boot нет ничего магического, он использует совершенно базовые понятия из Spring Framework. В кратком виде процесс можно описать так:
Это может выглядеть сложно, но по большей части разработчикам приложений влезать во внутренности автоконфигурации не нужно, если речь не идет о поддержке авто-конфигурации для своей библиотеке.
Диагностика
Auto-configuration report
В случае, когда что-то идет не так, Spring Boot позволяет запустить диагностику автоконфигурации и посмотреть, какие именно бины были созданы. Чтобы увидеть эту информацию, нужно запустить приложение с ключом —debug .
java -jar my-app.jar —debug
В ответ Spring выдаст детальный Auto-configuration report:
Строчка в Positive / Negative matches будет для каждой примененной автоконфигурации, более того, Boot сообщит, почему тот или иной бин был создан (т.е. укажет, какие из условий регистрации были выполнены).
Actuator
Spring Boot Actuator это мощный инструмент диагностики работающего приложения, который умеет давать много полезной аналитики (более того, набор этих метрик можно легко расширять из приложения).
После добавления Actuator к проекту, Spring Boot опубликует список доступных бинов через URL http://localhost:8080/beans . Этот список так же доступен через JMX (Java Management Extensions), и последняя версия Intellij IDEA умеет показывать все бины приложения прямо из окна запуска.
Резюме
Spring все же остается большим и не самым простым фреймворком, но это цена высокоуровневых абстракций, которые он предоставляет. И хотя знать все тонкости работы фреймворка в ежедневной разработке не нужно, знать, как он работает изнутри, все же, полезно. Надеюсь, что эта статья помогла понять важность и ценность Spring именно как экосистемы и убрала немного «магичности» в происходящем, особенно при использовании Spring Boot. Мой совет — не бойтесь углубляться в недра фреймворка, читайте исходники и документацию, благо они у Spring-a почти эталонные, на мой взгляд.
Так же стоит отметить, что в готовящемся к выходу в сентябре Spring 5 появится несколько новых концепций, направленных на создание простых приложений, и понижение уровня «магии» (хотя, как мы выяснили, магии там особо и нет). Одна из концепций это Functional Bean Registration, которая позволяет регистрировать бины в контексте с помощью функций, или даже с помощью неплохого DSL на Kotlin (а Spring 5 добавит много хорошего для поддержки Kotlin). Следующая, но еще более важная вещь, это комбинация Functional Web Framework и WebFlux (reactive web framework), которая позволит создавать веб-приложения вообще без зависимости на Spring MVC и запускать их без сервлет контейнеров. Приложение вполне сможет работать без контекста приложений и DI, и описываться просто как набор функций request -> response . Об этом можно чуть больше почитать здесь (на английском).
Источник: habr.com
Русские Блоги
ALTERA КВАРТУСИИ ПРОГРАММА БИН ФАЙЛОВ SOF, POF, JIC Разница файлов
~~.Существует три типа кварталов Скачать файлы: SOF, POF, JIC, в чем разница между этими тремя файлами? См. ниже:
SOF и POF — это файлы Bin, загружаемые в ОЗУ FPGA во время отладки, потери отключения питания, Электроэнергия должна быть повторно сожжена;
SOF загружен через JTAG в оперативную память, и POF загружается через интерфейс.
POF Active: Power-On активно читайте программу в чип FPGA
JIC относится к пассивному режиму: включение FPGA активно прочитано
JIC — это файл выпускного вечера, написаноEPCSxx (Подробнее, пожалуйста, обратитесь к FPGA, вы поймете здесь, чтобы загрузить Bin в RAM. ( Погрузчик через Flash Chip в чип FPGA )
Как правило, он должен быть преобразован в файл .sof в Flash Chip после отладки программы.
Изображение ниже — это определенные этапы SOF до JIC-файла:
Источник: russianblogs.com