Java spring руководство

Чтобы вы ни создавали, эти материалы разработаны для повышения вашей эффективности, благодаря
использованию последних выпусков Spring-проектов и техник, рекомендованных
разработчиками Spring.

Разработанные для изучения за 15-30 минут, эти материалы содержат краткие практические
иструкции для реализации «Hello Word» и других подобных задач. В большинстве случаев,
предварительно необходимо установить JDK и текстовый редактор.

Обработка данных

Как с использованием Spring Integration создать приложение для сбора и обработки данных и записи результатов в файл.

Обработка настроек сайта

Как с использованием Spring определить, как более предпочтительно отобразить страницу сайта,
обычную, мобильную версию или планшетную.

Разработанные для изучения эти материалы содержат практические
иструкции для реализации «Hello Word» и других задач, которые отражают функциональность и применимость
Spring Framework, а также сопутствующих его проектов. В большинстве случаев, предварительно необходимо
установить JDK и текстовый редактор.

Spring Framework является одним из самых сложных фремворков для понимания и изучения. Большинство разработчиков изучают его медленно, через практические задачи и гугл. Этот подход не эффективен, так как не даёт полной картины и при этом требует больших затрат.

Я хотел бы предложить вам принципиально новый подход к изучению Спринга. Он заключается в том, что человек проходит через серию специально подготовленных туториалов и самостоятельно реализует функционал спринга. Особенность этого подхода в том, что он, помимо 100%-го понимания изучаемых аспектов Spring даёт ещё большой прирост в Java Core (Annotations, Reflection, Files, Generics).

Статья подарит вам незабываемые ощущения и позволит почувствовать себя разработчиком Pivotal. Шаг за шагом, вы сделаете ваши классы бинами и организуете их жизненный цикл (такой же, как и в реальном спринге). Классы, которые вы будете реализовывать — BeanFactory, Component, Service, BeanPostProcessor, BeanNameAware, BeanFactoryAware, InitializingBean, PostConstruct, PreDestroy, DisposableBean, ApplicationContext, ApplicationListener, ContextClosedEvent.

Немного о себе

Меня зовут Ярослав, и я Java Developer с 4-х летним опытом работы. На данный момент я работаю в компании EPAM Systems (СПБ), и с интересом углубляюсь в те технологии, которые мы используем. Довольно часто приходится иметь дело со спрингом, и я вижу в нём некоторую золотую середину, в которой можно разиваться (Java все итак нормально знают, а слишком специфические инструменты и технологии могут приходить и уходить).

Пару месяцев назад я прошёл сертификацию Spring Professional v5.0 (без прохождения курсов). После этого я задумался над тем, как можно обучать спрингу других людей. К сожалению, на данный момент нет эффективной методики обучения. У большинства разработчиков складывается весьма поверхностное представление о фреймворке и его особенностях. Дебажить исходники спринга слишком тяжело и абсолютно не эффективно с точки зрения обучения (я как-то увлекался этим). Сделать 10 проектов? Да, вы где-то сможете углубить свои знания и получите много практического опыта, но многое из того, что «под капотом», так и не откроется перед вами. Читать книгу Spring in Action? Круто, но затратно по усилиям. Я вот проработал её 40% (во время подготовки к сертификации), но это было не просто.

Единственный способ понять что-то до конца — самостоятельно разработать это. Недавно у меня появилась идея о том, что можно провести человека через интересный туториал, который будет курировать разработку своего DI-фреймворка. Главная его особенность будет заключаться в том, что API будет совпадать с изучаемым API. Офигенность данного подхода в том, что помимо глубокого (без пробелов) понимания спринга, человек получит ОГРОМНОЕ количество опыта по Java Core. Признаюсь честно, я сам много всего нового узнал во время подготовки статьи, как по Spring, так и по Java Core. Давайте приступим к разработке!

Проект с нуля

Итак, первое, что нужно сделать — это открыть любимую IDE и создать проект с чистого листа. Никаких Maven, никаких сторонних библиотек мы подключать не будем. Даже Spring-зависимости подключать не будем. Наша цель — разработать API, максимально похожий на Spring API, и реализовать его самостоятельно.

В чистом проекте создайте 2 главных пакета. Первый пакет — ваше приложение (com.kciray), и класс Main.java внутри него. Второй пакет — org.springframework. Да, мы будем дублировать структуру пакетов оригинального спринга, название его классов и их методов. Есть такой интересный эффект — когда вы создаете что-то свое, это свое начинает казаться простым и понятным. Потом, когда вы будете работать в больших проектах, вам будет казаться, что там все создано на основе вашей заготовки. Такой подход может очень положительно сказаться на понимании работы системы в целом, её улучшении, исправлении багов, решении проблем и так далее.

Если будут вознить какие-то проблемы, работающий проект можете взять тут.

Создаём контейнер

Для начала, поставим задачу. Представим, что у нас есть 2 класса — ProductFacade и PromotionService. Теперь представим, что вы хотите связать эти классы между собой, но так, чтобы сами классы не знали друг о друге (Паттерн DI). Нужен какой-то отдельный класс, который будет управлять всеми этими классами и определять зависимости между ними. Назовём его контейнер. Создадим класс Container… Хотя нет, подождите! В Spring нету единого класса-контейнера. У нас есть много реализаций контейнеров, и все эти реализации можно разделить на 2 типа — фабрики бинов и контексты. Фабрика бинов создаёт бины и связывает их между собой (инъекция зависимостей, DI), а контекст делает примерно то же самое, плюс ещё добавляет некоторые дополнительные функции (например, интернационализация сообщений). Но эти дополнительные функции нам не нужны сейчас, поэтому будем работать с фабрикой бинов.

Создайте новый класс BeanFactory и поместите его в пакет org.springframework.beans.factory. Пускай внутри этого класса хранится Map<String, Object> singletons, в которой id бина замапено на сам бин. Добавьте к нему метод Object getBean(String beanName), который вытаскивает бины по идентификатору.

public class BeanFactory {
    private Map<String, Object> singletons = new HashMap();

    public Object getBean(String beanName){
        return singletons.get(beanName);
    }
}

Обратите внимание на то, что BeanFactory и FactoryBean — это разные вещи. Первое — это фабрика бинов (контейнер), а второе — это бин-фабрика, который сидит внутри контейнера и тоже производит бины. Фабрика внутри фабрики. Если вы путаетесь между этими определениями, можете запомнить, что в английском языке второе существительное является ведущим, а первое — служит чем-то типа прилагательного. В слове BeanFactory Главным словом является фабрика, а в FactoryBean — бин.

Теперь, создадим классы ProductService и PromotionsService. ProductService будет возвращать продукт из БД, но перед этим нужно проверить, применимы ли к этому продукту какие-либо скидки (Promotions). В электронной коммерции работу со скидками часто выделяют в отдельный класс-сервис (а иногда и в сторонний веб-сервис).

public class PromotionsService {

}

public class ProductService {
    private PromotionsService promotionsService;

    public PromotionsService getPromotionsService() {
        return promotionsService;
    }

    public void setPromotionsService(PromotionsService promotionsService) {
        this.promotionsService = promotionsService;
    }
}

Теперь нам надо сделать так, чтобы наш контейнер (BeanFactory) обнаружил наши классы, создал их за нас и инжектировал один в другой. Операции типа new ProductService() должны находится внутри контейнера и делаться за разработчика. Давайте используем самый современный подход (сканирование классов и аннотации). Для этого нам нужно ручками создать аннотацию @Component (пакет org.springframework.beans.factory.stereotype).

@Retention(RetentionPolicy.RUNTIME)
public @interface Component {

}

По умолчанию аннотации не загружаются в память во время работы программы (RetentionPolicy.CLASS). Мы изменили данное поведение через новую политику удержания (RetentionPolicy.RUNTIME).

Теперь добавьте @Component перед классами ProductService и перед PromotionService.

@Component
public class ProductService {
    //...
}
@Component
public class PromotionService {
    //...
}

Нам нужно, чтобы BeanFactory сканировал наш пакет (com.kciray) и находил в нем классы, которые аннотированы @Component. Эта задача совсем не тривиальная. В Java Core нет готового решения, и нам придётся делать костыль самому. Тысячи приложений на спринге используют сканирование компонентов через этот костыль. Вы узнали страшную правду. Вам придется извлекать из ClassLoader названия файлов и проверять, заканчиваются они на «.class» или нет, а потом строить их полное имя и вытаскивать по нему объекты классов!

Сразу хочу предупредить, что будет много проверяемых исключений, поэтому будьте готовы их оборачивать. Но для начала, давайте определимся, чего мы хотим. Мы хотим добавить специальный метод в BeanFactory и вызывать его в Main:

//BeanFactory.java
public class BeanFactory{
    public void instantiate(String basePackage) {

    }
}

//Main.java
BeanFactory beanFactory = new BeanFactory();
beanFactory.instantiate("com.kciray");

Далее, нам нужно получить ClassLoader. Он отвечает за загрузку классов, и добывается довольно просто:

ClassLoader classLoader = ClassLoader.getSystemClassLoader();

Наверно вы уже заметили, что пакеты разделяются точкой, а файлы — прямым слешем. Нам надо преобразовать пакетный путь в путь к папке, и получить что-то типа List<URL> (пути в вашей файловой системе, по которым можно искать class-файлы).

String path = basePackage.replace('.', '/'); //"com.kciray" -> "com/kciray"
Enumeration<URL> resources = classLoader.getResources(path);

Так, подождите! Enumeration<URL> это не List<URL>. Что это вообще такое? О ужас, это же старый прародитель Iterator, доступный ещё с времен Java 1.0. Это легаси, с которым нам приходится иметь дело. Если по Iterable можно пройтись с помощью for (все коллекции его реализуют), то в случае Enumeration вам придётся делать обход ручками, через while(resources.hasMoreElements()) и nextElement(). И ещё там нет возможности удалять элементы из коллекции. Только 1996 год, только хардкор. Ах да, в Java 9 добавили метод Enumeration.asIterator(), так что можете работать через него.

Поехали дальше. Нам надо извлечь папки и проработать содержимое каждой из них. Преобразуем URL в файл, а затем получаем его имя. Тут надо отметить, что мы не будем сканировать вложенные пакеты, чтобы не усложнять код. Можете усложнить себе задачу и сделать рекурсию, если есть желание.

while (resources.hasMoreElements()) {
    URL resource = resources.nextElement();

    File file = new File(resource.toURI());
    for(File classFile : file.listFiles()){
        String fileName = classFile.getName();//ProductService.class

    }
}

Дальше, нам нужно получить название файла без расширения. На дворе 2018 год, Java много лет развивала File I/O (NIO 2), но до сих пор не может отделить расширение от имени файла. Приходится свой велосипед создавать, т.к. мы решили не использовать сторонние библиотеки вроде Apache Commons. Давайте используем старый дедовский способ lastIndexOf("."):

if(fileName.endsWith(".class")){
    String className = fileName.substring(0, fileName.lastIndexOf("."));
}

Далее, мы можем по полному имени класса получить объект класса (для этого вызываем класс класса Class):

Class classObject = Class.forName(basePackage + "." + className);

Окей, теперь наши классы в наших руках. Далее, осталось только выделить среди них те, что имеют аннотацию @Component:

if(classObject.isAnnotationPresent(Component.class)){
    System.out.println("Component: " + classObject);
}

Запустите и проверьте. В консоли должно быть что-то вроде этого:

Component: class com.kciray.ProductService
Component: class com.kciray.PromotionsService

Теперь нам нужно создать наш бин. Надо сделать что-то вроде new ProductService(), но для каждого бина у нас свой класс. Рефлексия в Java предоставляет нам универсальное решение (вызывается конструктор по-умолчанию):

Object instance = classObject.newInstance();//=new CustomClass()

Далее, нам нужно поместить этот бин в Map<String, Object> singletons. Для этого нужно выбрать имя бина (его id). В Java мы называем переменные подобно классам (только первая буква в нижнем регистре). Данный подход может быть применим к бинам тоже, ведь Spring — это Java-фреймворк! Преобразуйте имя бина так, чтобы первая буква была маленькая, и добавьте его в мапу:

String beanName = className.substring(0, 1).toLowerCase() + className.substring(1);
singletons.put(beanName, instance);

Теперь убедитесь в том, что всё работает. Контейнер должен создавать бины, и они должны извлекаться по имени. Обратите внимание на то, что название вашего метода instantiate() и название метода classObject.newInstance(); имеют общий корень. Более того, instantiate() — это часть жизненного цикла бина. В джаве всё взаимосвязано!

//Main.java
BeanFactory beanFactory = new BeanFactory();
beanFactory.instantiate("com.kciray");
ProductService productService = (ProductService) beanFactory.getBean("productService");
System.out.println(productService);//ProductService@612

Попробуйте также реализовать аннотацию org.springframework.beans.factory.stereotype.Service. Она выполняет абсолютно ту же функцию, что и @Component, но называется по-другому. Весь смысл заключён в названии — вы демонстриуете, что класс является сервисом, а не просто компонентом. Это что-то типа концептуальной типизации. В сертификации по спрингу был вопрос «Какие аннотации являются стереотипными? (из перечисленных)». Так вот, стереотипные аннотации — это те, которые находятся в пакете stereotype.

Наполняем свойства

Посмотрите на схему ниже, на ней представлено начало жизненного цикла бина. То, что мы делали до этого, это Instantiate (создание бинов через newInstance()). Следующий этап — это перекрестное инжектирование бинов (инъекция зависимостей, она же инверсия контроля (IoC)). Нужно пройтись по свойствам бинов и понять, какие именно свойства нужно заинжектить. Если вы сейчас вызовете productService.getPromotionsService(), то получите null, т.к. зависимость ещё не добавлена.

Для начала, создадим пакет org.springframework.beans.factory.annotation и добавим в него аннотацию @Autowired. Идея в том, чтобы помечать этой аннотацией те поля, которые являются зависимостями.

@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {
}

Далее, добавим её к свойству:

@Component
public class ProductService {
    @Autowired
    PromotionsService promotionsService;

    //...
}

Теперь нам нужно научить наш BeanFactory находить эти аннотации и инжектировать зависимости по ним. Добавим отдельный метод для этого, и вызовем его из Main:

public class BeanFactory {
    //...
    public void populateProperties(){
        System.out.println("==populateProperties==");

    }
}

Далее, нам нужно всего-лишь пройтись по всем нашим бинам в мапе singletons, и для каждого бина пройтись по всем его полям (метод object.getClass().getDeclaredFields() возвращает все поля, включая приватные). И проверить, есть ли у поля аннотация @Autowired:

for (Object object : singletons.values()) {
    for (Field field : object.getClass().getDeclaredFields()) {
        if (field.isAnnotationPresent(Autowired.class)) {

        }
    }
}

Далее, нам надо ещё разок пройтись по всем бинам и посмотреть их тип — вдруг это тот тип, который хочет себе взять наш бин. Да, у нас получается трехмерный цикл!

for (Object dependency : singletons.values()) {
    if (dependency.getClass().equals(field.getType())) {

    }
}

Далее, когда мы нашли зависимость, надо её заинжектить. Первое что вам может прийти в голову — это записать поле promotionsService с помощью рефлексии напрямую. Но спринг так не работает. Ведь если поле имеет модификатор private, то нам придется сначала установить его как public, потом записать наше значение, потом снова установить в private (чтобы сохранить целостность). Звучит как большой костыль. Давайте вместо большого костыля сделаем маленький костыль (сформируем название сеттера и вызовем его):

String setterName = "set" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);//setPromotionsService
System.out.println("Setter name = " + setterName);
Method setter = object.getClass().getMethod(setterName, dependency.getClass());
setter.invoke(object, dependency);

Теперь запустите ваш проект и убедитесь, что при вызове productService.getPromotionsService() вместо null возвращается наш бин.

То, что мы реализовали — это инъекция по типу. Есть ещё инъекция по имени (аннотация javax.annotation.Resource). Отличается она тем, что вместо типа поля будет извлекаться его имя, и по нему — зависимость из мапы. Тут всё аналогично, даже в чем-то проще. Я рекомендую вам поэкспериментировать и создать какой-нибудь свой бин, а потом заинжектить его с помощью @Resource и расширить метод populateProperties().

Поддерживаем бины, знающие о своем имени

Бывают случаи, когда внутри бина нужно получить его имя. Такая потребность возникает не часто, т.к. бины, по своей сути, не должны знать друг о друге и о том, что они бины. В первых версиях спринга предполагалось, что бин — это POJO (Plain Old Java Objec, старый добрый Джава-объект), а вся конфигурация вынесена в XML-файлы и отделена от реализации. Но мы реализуем данный функционал, так как инъекция имени — это часть жизненного цикла бина.

Как нам узнать, какой бин хочет узнать, как его зовут, а какой не хочет? Первое, что приходит в голову — это сделать новую аннотацию типа @InjectName и лепить её на поля типа String. Но это решение будет слишком общим и позволяет выстрелить себе в ногу много раз (разместить эту аннотацию на полях неподходящих типов (не String), или же пытаться инжектировать имя в несколько полей в одном классе). Есть другое решение, более аккуратное — создать специальный интерфейс с одним методом-сеттером. Все бины, что его реализуют — получает своё имя. Создайте класс BeanNameAware в пакете org.springframework.beans.factory:

public interface BeanNameAware {
    void setBeanName(String name);
}

Далее, пускай наш PromotionsService его реализует:

@Component
public class PromotionsService implements BeanNameAware {
    private String beanName;

    @Override
    public void setBeanName(String name) {
        beanName = name;
    }

    public String getBeanName() {
        return beanName;
    }
}

И, наконец, добавим новый метод в фабрику бинов. Тут всё просто — мы проходимся по нашим бинам-синглтонам, проверяем, реализует ли бин наш интерфейс, и вызываем сеттер:

public void injectBeanNames(){
    for (String name : singletons.keySet()) {
        Object bean = singletons.get(name);
        if(bean instanceof BeanNameAware){
            ((BeanNameAware) bean).setBeanName(name);
        }
    }
}

Запустите и убедиесь, что всё работает:

BeanFactory beanFactory = new BeanFactory();
beanFactory.instantiate("com.kciray");
beanFactory.populateProperties();
beanFactory.injectBeanNames();

//...

System.out.println("Bean name = " + promotionsService.getBeanName());

Надо отметить, что в спринге есть и другие подобные интерфейсы. Я рекомендую вам самостоятельно реализовать интерфейс BeanFactoryAware, который позволит бинам получать ссылку на фабрику бинов. Реализуется он аналогично.

Инициализируем бины

Представим, что у вас возникла ситуация, когда нужно выполнить некоторый код после того, как зависимости были проинжектированы (свойства бина установлены). Говоря простым языком, нам нужно предоставить бину возможность инициализировать самого себя. Как вариант, мы можем создать интерфейс InitializingBean, и в него поместить сигнатуру метода void afterPropertiesSet(). Реализация данного механизма абсолютно аналогична той, что была представлена для интерфейса BeanNameAware, поэтому решение под спойлером. Потренируйтесь и сделайте его самостоятельно за минуту:

Решение для инициализации бина

//InitializingBean.java
package org.springframework.beans.factory;

public interface InitializingBean {
    void afterPropertiesSet();
}

//BeanFactory.java
public void initializeBeans(){
    for (Object bean : singletons.values()) {
        if(bean instanceof InitializingBean){
            ((InitializingBean) bean).afterPropertiesSet();
        }
    }
}

//Main.java
beanFactory.initializeBeans();

Добавляем пост-процессоры

Представьте себя на месте первых разработчиков спринга. Ваш фреймворк растёт и пользуется огромной популярностью среди девелоперов, на почту каждый день приходят письма с просьбами добавить ту или иную полезную фичу. Если для каждой такой фичи добавлять свой собственный интерфейс и проверять его в жизенном цикле бина, то он (жизненный цикл) окажется засоренным ненужной информацией. Вместо этого, мы можем создать один универсальный интерфейс, который позволит добавлять выполнение некоторой логики (абсолютно любой, будь то проверка на аннотацию, замена бина на другой бин, установка некоторых особых свойств и так далее).

Давайте подумаем, для чего предназначен данный интерфейс. Он должен производить некоторую пост-обработку бинов, следовательно его можно назвать BeanPostProcessor. Но перед нами стоит непростой вопрос — когда следует выполнять логику? Ведь мы можем выполнить её до инициализации, а можем выполнить и после. Для одних задач лучше подходит первый вариант, для других — второй… Как быть?

Мы можем позволить оба варианта сразу. Пускай один пост-процессор несёт две логики, два метода. Один выполняется до инициализации (до метода afterPropertiesSet()), а другой — после. Теперь давайте задумаемся над самими методами — какие параметры у них должны быть? Очевидно, что там должен быть сам бин (Object bean). Для удобства, кроме бина можно передавать имя этого бина. Вы же помните, что бин сам по себе не знает о своём имени. И мы не хотим заставлять все бины реализовывать интерфейс BeanNameAware. Но, на уровне пост-процессора, имя бина может очень даже пригодиться. Поэтом удобавляем его как второй параметр.

А что должен возвращать метод при пост-обработке бина? Сделаем так, чтобы он возвращал сам бин. Это даёт нам супер-гибкость, ведь вместо бина можно подсунуть прокси-объект, который оборачивает его вызовы (и добавляет секьюрити). А можно и вовсе вернуть другой объект, пересоздав бин заново. Разработчикам даётся очень большая свобода действия. Ниже представлена окончательная версия спроектированного интерфейса:

package org.springframework.beans.factory.config;

public interface BeanPostProcessor {
    Object postProcessBeforeInitialization(Object bean, String beanName);
    Object postProcessAfterInitialization(Object bean, String beanName);
}

Далее, нам нужно добавить список из прост-процессоров к нашей фабрике бинов и возможность добавлять новые. Да, это обычный ArrayList.

//BeanFactory.java
private List<BeanPostProcessor> postProcessors = new ArrayList<>();
public void addPostProcessor(BeanPostProcessor postProcessor){
    postProcessors.add(postProcessor);
}

Теперь поменяем метод initializeBeans так, чтобы он учитывал пост-процессоры:

public void initializeBeans() {
    for (String name : singletons.keySet()) {
        Object bean = singletons.get(name);
        for (BeanPostProcessor postProcessor : postProcessors) {
            postProcessor.postProcessBeforeInitialization(bean, name);
        }
        if (bean instanceof InitializingBean) {
            ((InitializingBean) bean).afterPropertiesSet();
        }
        for (BeanPostProcessor postProcessor : postProcessors) {
            postProcessor.postProcessAfterInitialization(bean, name);
        }
    }
}

Давайте создадим небольшой пост-процессор, который просто трассирует вызовы в консоль, и добавим его в нашу фабрику бинов:

public class CustomPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        System.out.println("---CustomPostProcessor Before " + beanName);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        System.out.println("---CustomPostProcessor After " + beanName);
        return bean;
    }
}

//Main.java
BeanFactory beanFactory = new BeanFactory();
beanFactory.addPostProcessor(new CustomPostProcessor());

Теперь запустите и убедитесь, что всё работает. В качестве тренировочного задания создайте пост-процессор, который будет обеспечивать работу аннотации @PostConstruct (javax.annotation.PostConstruct). Она предоставляет альтернативный способ инициализации (имеющий корни в Java, а не в спринге). Суть его в том, что вы размещаете аннотацию на некотором методе, и этот метод будет вызван ПЕРЕД стандартной спринговой инициализацией (InitializingBean).

Обязательно создавайте все аннотации и пакеты (даже javax.annotation) вручную, не подключайте зависимости! Это поможет вам увидеть разницу между ядром спринга и его расширениями (поддержка javax), и запомнить её. Это позволит придерживаться одного стиля в будущем.

Вам будет интересен тот факт, что в реальном спринге аннотация @PostConstruct именно так и реализована, через пост-процессор CommonAnnotationBeanPostProcessor. Но не подглядывайте туда, напишите свою реализацию.

На последок, я вам рекомендую добавить метод void close() в класс BeanFactory и отработать ещё два механизма. Первый — аннотация @PreDestroy (javax.annotation.PreDestroy), предназначена для методов, которые должны быть вызваны при закрытии контейнера. Второй — интерфейс org.springframework.beans.factory.DisposableBean, который содержит метод void destroy(). Все бины, исполняющие данный интерфейс, будут иметь возможность сами себя уничтожить (освободить ресурсы, например).

@PreDestroy + DisposableBean

//DisposableBean.java
package org.springframework.beans.factory;

public interface DisposableBean {
    void destroy();
}

//PreDestroy.java
package javax.annotation;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface PreDestroy {
}

//DisposableBean.java
public void close() {
    for (Object bean : singletons.values()) {
        for (Method method : bean.getClass().getMethods()) {
            if (method.isAnnotationPresent(PreDestroy.class)) {
                try {
                    method.invoke(bean);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        }
        if (bean instanceof DisposableBean) {
            ((DisposableBean) bean).destroy();
        }
    }
}

Полный жизненный цикл бина


Вот мы и реализовали полный жизненный цикл бина, в его современном виде. Я надеюсь, что такой подход поможет вам его запомнить.

Наш любимый контекст

Программисты очень часто используют термин контекст, но не все понимают, что же он на самом деле значит. Сейчас мы расставим всё по-полочкам. Как я уже отметил в начале статьи, контекст — это реализация контейнера, как и BeanFactory. Но, кроме базовых функций (DI), она ещё добавляет некоторые крутые фичи. Одна из таких фич — это отправка и обработка событий между бинами.

Статья получилась слишком большой и содержимое стало обрезаться, поэтому я поместил информацию по контексту под спойлер.

Реализуем контект

Начнем с заготовки контекста. Создайте пакет org.springframework.context, и класс ApplicationContext внутри него. Пусть он содержит внутри себя экземпляр класса BeanFactory. Все этапы инициализации поместим в конструктор, а также добавим перенаправление метода close().

public class ApplicationContext {
    private BeanFactory beanFactory = new BeanFactory();

    public ApplicationContext(String basePackage) throws ReflectiveOperationException{
        System.out.println("******Context is under construction******");

        beanFactory.instantiate(basePackage);
        beanFactory.populateProperties();
        beanFactory.injectBeanNames();
        beanFactory.initializeBeans();
    }

    public void close(){
        beanFactory.close();
    }
}

Добавьте его в класс Main, запустите и убедитесь, что он работает:

ApplicationContext applicationContext = new ApplicationContext("com.kciray");
applicationContext.close();

Теперь давайте подумаем, как организовать события. Поскольку у нас уже есть метод close(), мы можем создать событие «Закрытие контекста» и перехватить его внутри какого-нибудь бина. Создайте простой класс, представляющий данное событие:

package org.springframework.context.event;

public class ContextClosedEvent {
} 

Теперь нам надо создать интерфейс ApplicationListener, который позволит бинам слушать наши события. Поскольку мы решили представлять события в виде классов, то имеет смысл типизировать этот интерфейс по классу события (ApplicationListener<E>). Да, мы будем использовать Java-дженерики, и вы получите немножко опыта по работе с ними. Далее, вам нужно придумать название для метода, который будет обрабатывать событие:

package org.springframework.context;

public interface ApplicationListener<E>{
    void onApplicationEvent(E event);
}

Теперь вернёмся к классу ApplicationContext. Нам нужно в методе close() пройтись по всем нашим бинам, и выяснить, какие из них являются слушателями событий. Если бин заимплементил ApplicationListener<ContextClosedEvent>, значит нужно вызвать его onApplicationEvent(ContextClosedEvent). Кажется просто и логично, не так ли?

public void close(){
    beanFactory.close();
    for(Object bean : beanFactory.getSingletons().values()) {
        if (bean instanceof ApplicationListener) {

        }
    }
}

Но нет. Тут возникает трудность. Мы НЕ МОЖЕМ сделать проверку типа bean instanceof ApplicationListener<ContextClosedEvent>. Это связано с особенностью реализации Java. При компиляции происходит так называемая очистка типов (type erasure), при которой все <T> заменяются на <Object>. Как же быть, что же делать? Как нам выловить бины, которые имплементят именно ApplicationListener<ContextClosedEvent>, а не другие типы событий?

На самом деле, информация о типах сохраняется в метаданных класса, и очень даже успешно извлекается через рефлексию. Для начала, нам нужно получить список из интерфейсов, которые данный бин реализует, и отфильтровать среди них те, которые имеют параметры:

for (Type type: bean.getClass().getGenericInterfaces()){
    if(type instanceof ParameterizedType){
        ParameterizedType parameterizedType = (ParameterizedType) type;

    }
}

Далее, мы всего лишь извлекаем тип первого параметра, и убеждаемся, что он — наш класс события. Если это так, мы получаем наш метод через рефлексию и вызываем его:

Type firstParameter = parameterizedType.getActualTypeArguments()[0];
if(firstParameter.equals(ContextClosedEvent.class)){
    Method method = bean.getClass().getMethod("onApplicationEvent", ContextClosedEvent.class);
    method.invoke(bean, new ContextClosedEvent());
}

Пускай один из ваших классов реализует интерфейс ApplicationListener:

@Service
public class PromotionsService implements BeanNameAware, ApplicationListener<ContextClosedEvent> {
    //...

    @Override
    public void onApplicationEvent(ContextClosedEvent event) {
        System.out.println(">> ContextClosed EVENT");
    }
}

Далее, тестируете ваш контекст в Main и убеждаетесь, что он также работает, и событие отправляется:

//Main.java
void testContext() throws ReflectiveOperationException{
    ApplicationContext applicationContext = new ApplicationContext("com.kciray");
    applicationContext.close();
}

Заключение

Изначально я планировал данную статью для Baeldung на английском, но потом подумал, что аудитория хабры может положительно оценить данный подход к обучению. Если вам понравились мои идеи, обязательно поддержите статью. Если она наберёт рейтинг более 30, то обещаю продолжение. При написании статьи, я старался показать именно те знания Spring Core, которе используются наиболее часто, а также с опорой на Core Spring 5.0 Certification Study Guide. В будущем, с помощью таких туториалов можно покрыть всю сертификацию и сделать спринг более доступным для Java-разработчиков.

Update 10/05/2018

Мне постоянно приходят письма с вопросами «а когда продолжение, мы его ждём». Но вот времени совсем нету, и другие личные проекты в приоритете. Однако, если кому-то из вас действительно понравилась идея, вы можете изучить узкий раздел спринга и написать статью-продолжение. Если у вас нету аккаунта хабры, то я могу опубликовать статью от моего акка или помочь вам получить инвайт.

Распределение тем:
Spring Container — [имя пользователя]
Spring AOP — [имя пользователя]
Spring Web — [имя пользователя]
Spring Cloud — [имя пользователя]

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

Тема для следующей статьи


50.23%
Spring Container, углубляемся ещё больше (@Bean, @Configuration, Context, Prototype, XML)
110


11.42%
Spring AOP, пишем прокси своими руками (@Aspect, @Pointcut)
25


29.68%
Spring Web, веб-сервер с нуля (@Contoller, @RequestMapping)
65

Проголосовали 219 пользователей.

Воздержались 28 пользователей.

Недавно мне пришла мысль, для закрепления своих знаний и, чтобы сделать свой маленький вклад в развитие IT, сделать небольшую серию руководств по различным технологиям.

spring-by-pivotal

Начать я решил с технологии Spring Framework.

Итак, приступим.

Для кого

Это руководство предназначено для Java разработчиков, которые хотят детально понять Spring Framework, его архитектуру и конкретное применение.

Необходимые знания

Для того чтобы Вы могли понимать вещи, которые описаны в этом руководстве, Вам необходимо хорошее понимание Java Core и опыт работы с Intellij Idea.

Введение

Spring один из самых популярных фреймворков для J2EE. Разработчики по всему миру используют Spring для создания надёжных и качественных приложений. Он был разработан в Июне 2003 года Родом Джонсоном.

С помощью Spring можно разработать любое Java приложение.

Внедрение зависимостей (Dependency Injection)

Невозможно понять, что такое Spring без понимания термина Dependency Injection (DI)  – один из видов инверсии управления (Inversion of Control – IoC).

При написании действительно крупных и сложных проектов разработчики сталкиваются с необходимостью делать классы приложения как можно более независимыми друг от друга для возможности повторного использования и юнит-тестирования. Именно DI устанавливает связи между этими классами, при этом сохраняя их независимость друг от друга.

Так что же DI такое?

Это ситуация, когда мы внедряем элемент одного класса в другой (конкретные примеры мы рассмотрим позже). На практике DI осуществляется путём передачи параметров конструктора или с помощью setter-ов.

Другим ключевым компонентом Spring является

Аспекто-ориентированное программирование (Aspect oriented programming – AOP)

Это функции, которые охватывают несколько узлов приложения, называются cross-cutting concerns и эти cross-cutting concerns отделены от непосредственной бизнес-логики приложения.

Примечание: придётся немного потерпеть и почитать пока непонятные термины, но позже, на практике, всё станет существенно яснее.

В ООП ключевой единицей является класс, в то время, как в АОП ключевым элементом является аспект. DI помогает разделить классы приложения на отдельные модули, и АОП – помогает отделить cross-cutting concerns от объектов на которые они влияют. Более подробно АОП будет рассмотрено далее. Крайней вещью, которая будет рассмотрена в этом руководстве будет непосредственно Архитектура Spring Framework. На данный момент Spring разделён на некоторое количество отдельных модулей, что позволяет Вам самим решать, какие из них использовать в Вашем приложении.

spring_architecture

Основной контейнер (Core Container) включает в себя Beans, Core, Context и SpEL (expression language).

Beans отвечает за BeanFactory которая является сложной реализацией паттерна Фабрика (GoF).

Модуль Core обеспечивает ключевые части фреймворка, включая свойства IoC и DI.

Context построен на основе Beans и Core и позволяет получить доступ к любому объекту, который определён в настройках. Ключевым элементом модуля Context является интерфейс ApplicationContext.

Модуль SpEL обеспечивает мощный язык выражений для манипулирования объектами во время исполнения.

Контейнер Data Access/Integration состоит из JDBC, ORM, OXM, JMS и модуля Transatcions.

JDBC обеспечивает абстрактный слой JDBC и избавляет разработчика от необходимости вручную прописывать монотонный код, связанный с соединением с БД.

ORM обеспечивает интеграцию с такими популярными ORM, как Hibernate, JDO, JPA и т.д.

Модуль OXM отвечает за связь Объект/XML – XMLBeans, JAXB и т.д.

Модуль JMS (Java Messaging Service) отвечает за создание, передачу и получение сообщений.

Transactions поддерживает управление транзакциями для классов, которые реализуют определённые методы.

Web

Этот слой состоит из Web, Web-MVC, Web-Socket, Web-Portlet

Модуль Web обеспечивает такие функции, как загрузка файлов и т.д.

Web-MVC содержит реализацию Spring MVC для веб-приложений.

Web-Socket обеспечивает поддержку связи между клиентом и сервером, используя Web-Socket-ы в веб-приложениях.

Web-Portlet обеспечивает реализацию MVC в среде портлетов.

Прочее

Spring также включает в себя ряд других важных модулей, таких как AOP, Aspects, Instrumentation, Messaging и Test

AOP реализует аспекто-ориентированное программирование и позволяет использовать весь арсенал возможностей АОП.

Модуль Aspects обеспечивает интеграцию с AspectJ, которая также является мощным фреймворком АОП.

Instrumentation отвечает за поддержку class instrumentation и class loader, которые используются в серверных приложениях.

Модуль Messaging обеспечивает поддержку STOMP.

И наконец, модуль Test обеспечивает тестирование с использованием TestNG или JUnit Framework.

На этом я завершаю вводную часть нашего руководства по Spring. В следующей части рассмотрим как создать простое Spring приложение с помощью IDE Intellij Idea.

#статьи


  • 0

Разбираемся в модулях фреймворка и в их основных различиях, запускаем на компьютере и создаём первый проект.

Иллюстрация: Colowgee для Skillbox Media

Антон Яценко

Изучает Python, его библиотеки и занимается анализом данных. Любит путешествовать в горах.

Spring — это популярный фреймворк для разработки на Java, который используют для создания корпоративных приложений, например CRM. При этом применять его могут не только Java-разработчики, но и те, кто работает с Kotlin или Groovy.

Иногда Spring называют фреймворком фреймворков, поскольку он состоит из отдельных модулей: Struts, Hibernate, Tapestry, EJB, JSF и других. Каждый модуль — это набор инструментов для решения технических задач, объединённых общей логикой Spring.

Давайте разберёмся, почему появился фреймворк Spring и как с ним работать на примере Java.

Для разработки веб-приложений программисты долго использовали JavaBeans. Это классы в языке Java, написанные по определённым правилам. Они облегчали разработку компонентов пользовательского интерфейса, но были сильно ограничены в своих возможностях. Например, с ними нельзя управлять транзакциями и безопасностью или реализовывать многопоточность, что очень важно для больших приложений.

Чаще всего эти проблемы беспокоили тех, кто разрабатывал корпоративные приложения, направленные на решение конкретной задачи в рамках большой компании. Например, бухгалтерское программное обеспечение, управление биллингом или CRM-систему.

Решить проблемы JavaBeans пытались с помощью Enterprise JavaBeans (EJB), технологии для написания и поддержки серверной части приложений. Её внедрение позволило облегчить работу над приложениями для бизнеса, так как в ней уже из коробки были поддержка многопоточности, распределённые транзакции и другие подходы, которые отсутствовали в JavaBeans.

Но работа с EJB сильно усложняла код из-за необходимости реализации методов обратного вызова жизненного цикла, Home- и Remote-интерфейсов, а также других подходов. Поэтому разработчики не успокоились и продолжали искать другое, более удобное решение для создания корпоративных приложений.

И такое решение появилось в июне 2003 года, когда Род Джонсон выпустил первую версию фреймворка Spring. А уже через год, в марте 2004 года, вышла первая стабильная версия фреймворка — 1.0. На июль 2022 года стабильная версия Spring — 5.3.х. Разберёмся, почему именно Spring стал удачным решением для создания корпоративных приложений.

Spring — это набор взаимосвязанных мини-фреймворков, созданных для работы над разными частями приложения. Подключать их можно по отдельности, в зависимости от задач.

Структура модулей в Spring
Инфографика: Spring Framework

Вот какие популярные модули входят в состав Spring.

Модуль для работы с реляционными и нереляционными базами данных: MySQL, Redis, Microsoft Azure Cosmos DB и другими. Включает в себя набор интерфейсов для работы с данными через JPA Entity. Подробно о возможностях модуля написано в официальной документации.

Позволяет работать в распределённых системах, включая персональный компьютер, PaaS-платформы, центры обработки данных и так далее. Внутри Spring Cloud существуют отдельные модули для конкретных решений — например, Spring Cloud Azure интегрирует Spring со службами Azure.

Кроме непосредственной работы с распределёнными системами Spring Cloud позволяет проводить маршрутизацию, балансировать нагрузку и проводить распределённый обмен сообщениями, что облегчает работу над отдельными задачами. Нюансы работы разобраны в документации к Spring.

Java — объектно-ориентированный язык, но Spring основан на другой парадигме: аспектно-ориентированном программировании (АОП).

Аспектно-ориентированное программирование направлено на повышение модульности программы за счёт разделения задач внутри неё. Для этого обычно не меняют существующий код, а дописывают новый.

Классический пример АОП — применение политики безопасности. С одной стороны, она должна применяться ко всем частям приложения, а с другой стороны — быть самостоятельной сущностью, которую можно развивать отдельно от остального кода. Если работать с политикой безопасности по АОП, то она выносится в отдельный модуль и дальнейшая работа над ней, а также поддержка и рефакторинг проводятся независимо от основного приложения.

Подробнее про АОП в Spring написано в официальной документации.

Транзакция в Java — это последовательность запросов к базе данных, объединённая в один блок. Модуль транзакций в Spring позволяет управлять такими блоками, повышая безопасность и эффективность работы с СУБД. Работать можно с любыми вариантами транзакций: вложенными, локальными и глобальными. Узнать о возможностях модуля и особенностях его работы можно из документации.

Это лишь самые популярные модули, а в Spring существует ещё несколько десятков других модулей, которые подробно разобраны в документации к фреймворку. И лучше всего знакомиться с ними на практике.

Если искать информацию про работу и установку фреймворка Spring, то часто можно встретить упоминание Spring Boot. Spring Boot — это дополнение к Spring, которое облегчает и ускоряет работу с ним. Сам Spring Boot представляет собой набор утилит, автоматизирующих настройки фреймворка. Вот что он берёт на себя:

  • упаковывает зависимости в starter-пакеты;
  • автоматически конфигурирует приложения с помощью jar-зависимостей;
  • создаёт веб-сервер, что позволяет локально запускать на нём приложения.

Для работы с фреймворком Spring предстоит пройти несколько шагов:

  • Подготовить IDE и JDK.
  • Создать новый проект на Spring Boot.
  • Подготовить проект в IDE к работе.
  • Запустить код и увидеть результат.

Для начала работы вам потребуются две вещи:

  • Любая интегрированная среда разработки (IDE). Подойдёт одна из популярных IDE: IntelliJ IDEA, Spring Tools для Eclipse, Visual Studio Code.
  • Средства разработки Java (JDK). Официальный сайт фреймворка Spring рекомендует воспользоваться BellSoft Liberica JDK версии 8 или 11.

Самый простой способ подготовить фреймворк для работы — воспользоваться сайтом start.spring.io для создания веб-проекта.

Важно: в пункте Dependencies не забудьте добавить зависимость Web. После этого нажмите кнопку Generate и скачайте ZIP-архив. Распакуйте его в нужную папку на вашем компьютере, и у вас будет готов каркас будущего проекта. Интерфейс сборки — Spring Boot. Версия — последняя стабильная. На 3 июля 2022 года это 2.7.1.

Скриншот: Spring Framework / Skillbox Media

Проекты, созданные на start.spring.io, уже содержат Spring Boot. Это фреймворк, который делает Spring готовым к работе внутри вашего приложения, но не требует написания большого количества кода или сложного конфигурирования. Spring Boot — самый быстрый и популярный способ запуска Spring-проектов.

Некоторые IDE необходимо подготовить к работе, например Visual Studio Code. Для этого внутри приложения необходимо перейти в раздел «Расширения» и найти расширение Spring Boot Extension Pack. После его установки Visual Studio Code будет готова к работе.

Для работы с Visual Studio Code необходимо установить расширение Spring Boot Extension Pack
Скриншот: Visual Studio Code / Skillbox Media

Если вы используете IntelliJ IDEA, то она уже готова к работе с фреймворком Spring. Откройте установленную IDE и создайте новый проект. Назовите его удобным для себя образом. Рассмотрим следующие шаги на примере IntelliJ IDEA.

Выберите в меню пункт File и команду Open. Найдите файл DemoApplication.java в папке src/main/java/com/example/demo

Открытие файла в интерфейсе IntelliJ IDEA
Скриншот: IntelliJ IDEA / Skillbox Media

Открытие файла в интерфейсе IntelliJ IDEA
Скриншот: IntelliJ IDEA / Skillbox Media

Теперь измените содержимое файла, добавив дополнительный метод hello() и аннотации @SpringBootApplication и @RestController, показанные в приведённом ниже коде. Вы можете просто скопировать и вставить код в текст файла:

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@RestController
public class DemoApplication {
                
                  public static void main(String[] args) {
                  SpringApplication.run(DemoApplication.class, args);
                  }
                  
                  @GetMapping("/hello")
                  public String hello(@RequestParam(value = "name", defaultValue = "World") String name) {
                  return String.format("Hello %s!", name);
                  }
                
              }

Метод hello(), который мы добавили, принимает параметр name с типом String, а затем объединяет этот параметр со словом «Hello» в коде. Это означает, что если вы зададите в запросе имя «Антон», то ответом будет «Hello Антон». Имя прописывается вручную в параметре defaultValue.

Аннотация @RestController сообщает Spring, что этот код описывает конечную точку, которая должна быть доступна через веб. Аннотация @GetMapping («/hello») указывает Spring, что надо использовать наш метод hello() для ответа на запросы, отправленные на адрес http://localhost:8080/hello. Наконец, @RequestParam указывает Spring, что в запросе должно быть значение name, а если его там нет, то использовать по умолчанию строку «World».

Теперь давайте соберём и запустим программу. Так как наша IDE уже готова к работе с фреймворком Spring, а сам проект создан в Spring Boot, который мы скачали с официального сайта, то сделать это просто.

Откройте командную строку (или терминал) и перейдите в папку, где находятся файлы проекта. Мы можем собрать и запустить приложение, выполнив следующую команду:

macOS/Linux:

Windows:

На выходе получим что-то подобное:

Результат запуска кода в терминале
Скриншот: Spring Framework / Skillbox Media

Последние несколько строк говорят нам о том, что Spring запущен. Встроенный в Spring Boot сервер Apache Tomcat работает в качестве веб-сервера и прослушивает запросы на порту localhost 8080. Откройте браузер и в адресной строке введите http://localhost:8080/hello. Вы должны получить такой ответ:

Работа локального сервера
Скриншот: Spring Framework / Skillbox Media

Поздравляем! Вы сделали свой первый проект на фреймворке Spring. Теперь можно углубиться в документацию фреймворка или пойти на специализированный курс по работе со Spring.

На «Хабр Карьере» доступно более 300 вакансий разработчиков со знанием Spring. Для сравнения, количество вакансий для Java-разработчиков — более 1100, а для Node.js-разработчиков — 180. Кроме фреймворка необходимо знать сам язык Java, работать с разными базами данных, пользоваться Git и таск-трекерами типа Jira.

Зарплата зависит от уровня разработчика. Джуниоры получают от 50 тысяч рублей, а сеньоры — от 200 тысяч. Разработчик среднего уровня может рассчитывать на зарплату от 100 до 250 тысяч рублей.

Скриншот: «Хабр Карьера» / Skillbox Media

Фреймворк Spring помогает облегчить разработку приложений на Java с помощью специализированных модулей и аспектно-ориентированного программирования. Углубиться в изучение фреймворка лучше с помощью официальной документации.

Как зарабатывать больше с помощью нейросетей?
Бесплатный вебинар: 15 экспертов, 7 топ-нейросетей. Научитесь использовать ИИ в своей работе и увеличьте доход.

Узнать больше

Spring – это простая в использовании среда Java MVC с открытым исходным кодом, обеспечивающая всестороннюю поддержку для простой и быстрой разработки приложений Java.

Spring – это облегченный фреймворк, который можно рассматривать как фреймворк фреймворков, поскольку он предлагает поддержку различных фреймворков, таких как Hibernate, Struts, Tapestry, JSF и т. д.

поддержка различных фреймворков

Особенности Spring Framework

Вот некоторые наиболее важные особенности Spring Framework:

  • Предопределенные шаблоны
  • облегченный
  • Быстрое развитие
  • Мощная абстракция
  • Предлагает множество ресурсов
  • Декларативная поддержка
  • Предлагает комплексные инструменты

Краткая история

Вот важные ориентиры из истории:

  • Spring Framework был написан Родом Джонсоном и впервые выпущен в июне 2002 года.
  • Spring La с т версия выпуск в марте 2004 года
  • Версия Spring 1.2.6 выпущена в 2006 году
  • Выпуск версии Spring 2.0 в октябре 2006 г.
  • Выпуск версии Spring 2.5 в ноябре 2007 г.
  • Выпуск версии Spring 3 в декабре 2009 г.
  • Выпуск версии Spring 3.1 в декабре 2011 г.
  • Выпуск версии Spring Framework 4 в декабре 2013 года с поддержкой Java 8
  • Spring Framework 4.2.0 версия выпущена в июле 2015 года
  • Spring Framework 4.2.1 версия выпущена в сентябре 2015
  • Версия Spring Framework 4.3 выпущена 10 июня 2016 года
  • Spring Framework 5.0 версия выпущена в июне 2017 года

Spring Framework Architecture

Spring Framework предоставляет 20 модулей, которые можно использовать в зависимости от требований приложения.

Spring Framework предоставляет 20 модулей

Core и Bean обеспечивают фундаментальную часть платформы, включая IoC и DI.

Основной контейнер

Базовый контейнер дополнительно разделен на подкомпоненты, такие как модули Core, Beans, Context и Expression Language.

Давайте рассмотрим каждую из этих моделей в деталях:

Spring Core:

Основной модуль обеспечивает все основные компоненты каркаса пружины. Включает функции IoC (Inversion of Control) и Inpension Injection.

Модуль предлагает BeanFactory, которая представляет собой сложную реализацию фабричного шаблона.

Context

Модуль Context основан на прочной основе, предоставляемой модулями Core и Beans, и является средой, которая помогает вам получить доступ к любым объектам, определенным и настроенным.

Языки весеннего выражения (SpEL):

Этот модуль предлагает язык выражений для изменения и запроса графов объектов во время выполнения.

Доступ к данным и интеграция:

Уровень доступа к данным и интеграции состоит из модулей JDBC, ORM, JDBC, OXM, JMS и Transaction.

  • ORM: модуль ORM обеспечивает согласованность / переносимость кода независимо от технологий доступа к данным. Он будет основан на концепции объектно-ориентированного отображения.
  • Модуль JDBC состоит из уровня абстракции JDBC. Это помогает вам понять необходимость выполнения кодирования, связанного с JDBC.
  • OXM: Object XML Mappers (OCM) помогает конвертировать объекты в формат XML и наоборот.
  • Модуль Java Messaging Service предлагает такие функции, как создание и потребление сообщений.
  • Транзакция: Этот модуль предлагает декларативный и программный метод управления для реализации уникальных интерфейсов и для всех типов POJO (Plain Old Java Object)

Web

Web: в этом модуле используются слушатели сервлетов и контекст веб-ориентированного приложения. Он также предлагает функцию веб-ориентированной интеграции и функциональность для загрузки файлов из нескольких частей.

Веб-сервлет: Этот модуль хранит реализацию на основе MVC для веб-приложений.

Web-Socket: модуль предлагает основанную на WebSocket и двустороннюю связь между клиентом и сервером в веб-приложениях.

Web-портлет: этот модуль также называется Spring-MVC-Portlet module. Он предлагает портлеты на основе Spring и копирует все функциональные возможности модуля Web-сервлетов.

AOP: язык AOP является полезным инструментом, который позволяет разработчикам добавлять корпоративные функциональные возможности в приложение.

Инструментарий: Этот модуль предлагает инструментарий класса и реализации загрузчика. Используется для конкретных серверов приложений.

Тест: Этот модуль поддерживает тестирование компонентов Spring с помощью инструментов TestNG или JUnit. Он предлагает последовательную загрузку Spring ApplicationContexts и кэширование этих контекстов.

Spring – MVC Framework

Spring - MVC Framework

Spring Web MVC Framework предлагает архитектуру модель-представление-контроллер и предлагает компоненты, которые помогают вам быть гибкими и слабо связанными веб-приложениями.

Шаблон MVC позволяет разделять различные аспекты приложения, предлагая слабую связь между этими элементами. Spring MVC также помогает вам создавать гибкие и слабо связанные веб-приложения.

Дизайн MVC также позволяет разделить бизнес-логику, логику представления и логику навигации. Он также предлагает элегантное решение для использования MVC в Spring Framework с помощью DispatcherServlet.

Как работает MVC?

Как работает MVC

  • DispatcherServlet получает запрос.
  • После этого DispatcherServlet связывается с HandlerMapping. Он также отзывает контроллер, связанный с этим конкретным запросом.
  • Контроллер обрабатывает этот запрос, вызывая методы службы и объект ModelAndView, возвращаемый DispatcherServlet.
  • Имя представления отправляется ViewResolver для поиска фактического представления для вызова.
  • После этого DispatcherServlet передается в View для отображения результата.
  • Используя данные модели, представление рендерится и отправляет результат обратно пользователю.

Аспектно-ориентированное программирование

Аспектно-ориентированное программирование позволяет глобальным свойствам программы решать, как она компилируется в исполняемую программу.

Ключевой единицей модульности является аспект, а не класс. Аспектно-ориентированное программирование разбивает логику программы на различные части, известные как проблемы.

Межотраслевая проблема может затронуть все приложение и сосредоточена в одном месте в коде, таком как безопасность транзакций, управление, ведение журналов, аутентификация и т. д.

Аспектно-ориентированное программирование

Его также можно рассматривать как динамический шаблон оформления декоратора. Этот шаблон также предлагает дополнительное поведение, которое будет добавлено к существующему классу, оборачивая исходный класс и дублируя его интерфейс и удаляя исходный.

Основные концепции АОП

В Аспектно-ориентированном программировании есть семь основных концепций.

Основные концепции

Давайте обсудим их подробно:

  • Аспект: Аспект – это класс, который позволяет реализовать приложение JEE. Это касается нескольких классов, таких как управление транзакциями, безопасность и т. Д. Аспекты могут быть типичным классом, настроенным с использованием конфигурации Spring XML, или обычным классом, аннотированным с помощью аннотации @Aspect.
  • Точка соединения: это точка-кандидат в выполнении программы, где аспект может быть подключен. Это может быть метод, вызываемый как выбрасываемое исключение, или даже поле, которое модифицируется.
  • Совет: Совет – это фактические действия, предпринятые для конкретной точки соединения. Этот метод будет выполняться, когда конкретная точка соединения встречает точку сопоставления в приложении.
  • Pointcut: Это выражение, которое можно сопоставить с точками соединения, чтобы проверить, следует ли выполнить этот совет или нет.
  • Целевой объект: на основе целевого объекта применяются устройства. В AOP подкласс создается во время выполнения, где целевой метод должен быть переопределен, и рекомендации включаются в зависимости от их конфигурации.
  • Прокси: этот объект должен быть создан после применения рекомендации к целевому объекту.
  • Плетение: это метод связывания аспекта с другими объектами или типами приложения для создания рекомендованного объекта.

Вот пошаговая информация по установке Java Spring на ваш компьютер:

Шаг 1) Зайдите на сайт www.eclipse.org.

Шаг 2) Загрузите установщик Eclipse Neon и установите его в своей системе Windows.

Установка Java Spring

Шаг 3) Нажмите кнопку «Загрузить 64-разрядную версию».

загрузка

Шаг 4) Перейдите в Eclipse IDE для разработчиков Java и нажмите на ссылку «64-bit».

64-bit

Шаг 5) Нажмите на ссылку «Windows 64-bit».

Windows 64-bit

Шаг 6) Нажмите на кнопку «Загрузить», чтобы загрузить ZIP-файл.

скачивание

Шаг 7) Распакуйте zip-файл для загрузки в определенную папку.

распаковка

Шаг 8) Нажмите кнопку «Обзор», чтобы выбрать каталог рабочей области.

выбор места

Шаг 9) Нажмите «Выбрать папку», чтобы выбрать папку.

выбор папки

Процесс будет отображаться, как показано на следующем экране.

процесс инсталяции

Шаг 10) Открытие клиента Eclipse Marketplace.

Eclipse Marketplace

Шаг 11) Поиск и установка плагина Spring.

установка плагина

Шаг 12) Подтвердите выбранные функции и нажмите кнопку «Подтвердить».

подтверждение

Шаг 13) Принятие условий и установка программного обеспечения.

принятие условий

Появится экран приветствия с ходом установки программного обеспечения.

экран приветствия

Шаг 14) Нажмите кнопку «Перезагрузить сейчас», чтобы перезапустить Eclipse IDE и применить изменения.

перезапустить Eclipse

Будет отображен следующий экран:

запуск

Преимущества Spring Framework

  • Spring позволяет разработчикам разрабатывать приложения корпоративного класса с помощью POJO.
  • Предлагает шаблоны для Hibernate, JDBC, Hibernate, JPA и т. Д., Чтобы уменьшить объем написанного кода.
  • Предоставляет абстракцию для Java Enterprise Edition (JEE).
  • Вы можете организовать по модульному принципу. Так что, если количество пакетов и классов является существенным, вам нужно только об этом и игнорировать все остальное.
  • Он предлагает декларативную поддержку транзакций, форматирования, проверки, кэширования и т. Д.
  • Приложение, разработанное с использованием Spring, является простым, поскольку код, зависящий от среды, перемещен в эту среду.

Недостатки Spring Framework

Вот минусы Spring Framework.

  • Слишком много ограничений.
  • Код общедоступен – это видно всем.
  • Не предлагает пользовательских функций.

Понравилась статья? Поделить с друзьями:
  • Мануалы для всех принтеров
  • Как регулировать пластиковые окна на зиму подробная инструкция
  • Yamaha f100aet инструкция на русском языке
  • Как вязать узел для виселицы инструкция
  • Все руководство роснефти