Статьи

Spring Dependency Injection — вводный урок

В этой статье обсуждается внедрение зависимостей в формате учебника. Он охватывает некоторые новые функции Spring DI, такие как аннотации, улучшенная конфигурация XML и многое другое.

Внедрение зависимости

Внедрение зависимостей (DI) относится к процессу предоставления внешней зависимости программному компоненту. Я могу помочь сделать ваш код архитектурно чистым. Он помогает в проектировании через интерфейс, а также в разработке, управляемой тестами, предоставляя согласованный способ внедрения зависимостей. Например, объект доступа к данным (DAO) может зависеть от соединения с базой данных. Вместо того, чтобы искать соединение с базой данных с помощью JNDI, вы можете внедрить его.

Один из способов думать о DI-контейнере, таком как Spring, — думать о JNDI, вывернутом наизнанку. Вместо объекта, ищущего другие объекты, которые ему нужны для выполнения своей работы (зависимости), контейнер DI внедряет эти зависимые объекты. Это так называемый Голливудский принцип: «Не звоните нам» (поиск объектов), «Мы вам позвоним» (ввод объектов).

Если вы работали с картами CRC, вы можете думать о зависимости как о сотруднике, то есть об объекте, которому другой объект должен выполнять свою роль.
Допустим, у вас есть банкомат (банкомат), и ему нужна возможность разговаривать с банком. Для этого он использует то, что он называет транспортным объектом. В этом примере транспортный объект обрабатывает низкоуровневую связь с банком.

Этот пример может быть представлен любым из двух интерфейсов следующим образом:

Интерфейс AutomatedTellerMachine

package com.arcmind.springquickstart;

import java.math.BigDecimal;

public interface AutomatedTellerMachine {
        void deposit(BigDecimal bd);
        void withdraw(BigDecimal bd);
}

 

Интерфейс ATMTransport

package com.arcmind.springquickstart;

public interface ATMTransport {
        void communicateWithBank(byte [] datapacket);
}

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

Реализация AutomatedTellerMachine может выглядеть следующим образом:

Реализация AutomatedTellerMachine:

package com.arcmind.springquickstart;

import java.math.BigDecimal;

public class AutomatedTellerMachineImpl implements AutomatedTellerMachine{

        private ATMTransport transport;

        public void deposit(BigDecimal bd) {
          ...
                transport.communicateWithBank(...);
        }

        public void withdraw(BigDecimal bd) {
          ...
                transport.communicateWithBank(...);
        }

        public void setTransport(ATMTransport transport) {
                this.transport = transport;
        }

}

AutomatedTellerMachineImpl не знает и не заботится о том, как транспорт снимает и вносит деньги в банк. Этот уровень косвенности позволяет нам заменять транспорт различными реализациями, как в следующем примере:

Три примера транспорта: SoapAtmTransport, StandardAtmTransport и SimulationAtmTransport

package com.arcmind.springquickstart;

public class SoapAtmTransport implements ATMTransport {

        public void communicateWithBank(byte[] datapacket) {
           ...
        }

}
package com.arcmind.springquickstart;

public class StandardAtmTransport implements ATMTransport {

        public void communicateWithBank(byte[] datapacket) {
          ...
        }

}



package com.arcmind.springquickstart;

public class SimulationAtmTransport implements ATMTransport {

        public void communicateWithBank(byte[] datapacket) {
                ...
        }

}

 

Обратите внимание на возможные реализации интерфейса ATMTransport. AutomatedTellerMachineImpl не знает и не заботится, какой транспорт он использует. Кроме того, для тестирования и разработки вместо общения с реальным банком обратите внимание, что вы можете использовать SimulationAtmTransport.

Об авторе

— технический директор Mammatus и эксперт по Java и облачным вычислениям . Рик вовлечен в адвокацию Java CDI и Java EE. Реализации CDI — Resin CandiСварка шваApache OpenWebBeans

Концепция DI выходит за рамки Spring. Таким образом, вы можете выполнить DI без Spring следующим образом:

Буду без весны

 

package com.arcmind.springquickstart;

import java.math.BigDecimal;

public class AtmMain {

        public void main (String[] args) {
                AutomatedTellerMachine atm = new AutomatedTellerMachineImpl();
                ATMTransport transport = new SoapAtmTransport();
                /* Inject the transport. */           
                ((AutomatedTellerMachineImpl)atm).setTransport(transport);

                atm.withdraw(new BigDecimal("10.00"));

                atm.deposit(new BigDecimal("100.00"));
        }

}

Тогда внедрение другого транспорта — это просто вызов другого метода установки следующим образом:

Внедрение другой зависимости

                ATMTransport transport = new SimulationAtmTransport();
                ((AutomatedTellerMachineImpl)atm).setTransport(transport);

Чтобы использовать Spring для внедрения зависимости, вы можете сделать следующее:

Использование Spring для управления зависимостями

package com.arcmind.springquickstart;

import java.math.BigDecimal;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AtmMain {

        public static void main (String[] args) {
                ApplicationContext appContext = new ClassPathXmlApplicationContext("classpath:./spring/applicationContext.xml");
                AutomatedTellerMachine atm = (AutomatedTellerMachine) appContext.getBean("atm");

                atm.withdraw(new BigDecimal("10.00"));

                atm.deposit(new BigDecimal("100.00"));
        }

} 

/spring/applicationContext.xml file

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="
                http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

        <bean id="atmTransport" class="com.arcmind.springquickstart.SoapAtmTransport" />


        <bean id="atm" class="com.arcmind.springquickstart.AutomatedTellerMachineImpl">
                <property name="transport" ref="atmTransport" />
        </bean>

</beans>

 

На рисунке 1 показано, как Spring внедряет зависимость, используя метод установки свойств. 

[Img_assist | NID = 5868 | название = | убывание = | ссылка = нет | ALIGN = не определено | ширина = 720 | Высота = 540]

Контекст приложения является центральным интерфейсом контейнера Spring DI. В контексте приложения вы объявляете два bean-компонента, atmTransport и atm, с тегом bean-компонента. Затем вы используете тег свойства, чтобы внедрить bean-компонент atmTransport в свойство транспорта. Это эффективно вызывает метод установки метода транспорта AutomatedTellerMachineImpl (setTransport (…)).

Основные возможности, которые предоставляет контекст приложения, включают (взяты из документации API):


  • Методы фабрики бинов для доступа к компонентам приложения

  • Возможность загрузки файловых ресурсов в общем виде

  • Способность разрешать сообщения, поддерживающие интернационализацию

В центре внимания этой статьи методы фабрики бобов и DI.

Об авторе

— технический директор Mammatus и эксперт по Java и облачным вычислениям . Рик вовлечен в адвокацию Java CDI и Java EE. Реализации CDI — Resin CandiСварка шваApache OpenWebBeans

Использование конструктора вместо сеттера

Другой вариант при использовании Spring — использовать аргументы конструктора вместо методов установки для внедрения зависимостей. Это делает вещи более чистыми с точки зрения объектно-ориентированного проектирования, поскольку объект должен быть создан со всеми его соавторами (так называемыми зависимостями), которые ему необходимы для выполнения своей роли.

Используя конструкторы, внедрение очень похоже на использование методов установки следующим образом:

Контекст приложения для внедрения конструктора

 <bean id="standardTransport" class="com.arcmind.springquickstart.StandardAtmTransport"/>

        <bean id="atm" class="com.arcmind.springquickstart.AutomatedTellerMachineImpl">
                <constructor-arg ref="standardTransport" />
        </bean>

 

Обратите внимание на использование тега constructor-arg. Это подразумевает, что конструктор принимает транспорт в качестве единственного аргумента.

Добавление конструктора в AutomatedTellerMachineImpl

public class AutomatedTellerMachineImpl implements AutomatedTellerMachine{

        private ATMTransport transport;

        public AutomatedTellerMachineImpl (ATMTransport transport) {
                this.transport = transport;
        }

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

[Img_assist | NID = 5869 | название = | убывание = | ссылка = нет | ALIGN = не определено | ширина = 720 | Высота = 540] 

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

Контекст приложения для внедрения конструктора с подсказкой для Spring

        <bean id="atm" class="com.arcmind.springquickstart.AutomatedTellerMachineImpl">
                <constructor-arg index="0" ref="standardTransport" />
        </bean>

При некоторых обстоятельствах вы даже можете указать атрибут типа, который вы хотите, чтобы Spring использовал для разрешения аргумента конструктора в случаях, когда имеется более одного возможного соответствия конструктора. В большинстве случаев вам не нужно указывать индекс или тип. Ваш пробег может варьироваться.

Об авторе

— технический директор Mammatus и эксперт по Java и облачным вычислениям . Рик вовлечен в адвокацию Java CDI и Java EE. Реализации CDI — Resin CandiСварка шваApache OpenWebBeans

Весна и аннотации, управляемые DI

Seam и Guice впервые использовали DI, используя аннотации вместо XML. Spring также добавил эту поддержку и, как правило, Spring делает это гибким неинвазивным способом.

Давайте начнем с простого примера. Допустим, вы неправильно настроили AutomatedTellerMachineImpl и забыли внедрить зависимость следующим образом:
Opps забыл внедрить транспорт

        <bean id="atmTransport" class="com.arcmind.springquickstart.SoapAtmTransport" />


        <bean id="atm" class="com.arcmind.springquickstart.AutomatedTellerMachineImpl">
        </bean>

Вы можете получить такую ​​ошибку:

Типичная ошибка при неправильной настройке bean-компонента


Исключение в потоке «main» java.lang.NullPointerException

        в com.arcmind.springquickstart.AutomatedTellerMachineImpl.withdraw (AutomatedTellerMachineImpl.java:25)

        в com.arcmind.springquickstart.AtmMain.main (atm)

В развернутом приложении эта ошибка может быть довольно загадочной. Если вы использовали аннотацию @Required, вы могли бы попросить Spring сканировать bean-компоненты и искать отсутствующие зависимости следующим образом:

AutomatedTellerMachineImpl с использованием @Required в методе setter свойства transport

import org.springframework.beans.factory.annotation.Required;

public class AutomatedTellerMachineImpl implements AutomatedTellerMachine{

        private ATMTransport transport;

        @Required
        public void setTransport(ATMTransport transport) {
                this.transport = transport;
        }

 

Теперь, когда вы запустите это, забыв настроить транспорт, вы получите следующее сообщение:


Вызывается: org.springframework.beans.factory.BeanInitializationException: свойство ‘transport’ требуется для компонента ‘atm’

Это понятнее и облегчает разработку и отладку приложений. Чтобы включить эту функцию проверки зависимостей, вы должны использовать теги context: component-scan или context: annotation-config. Это обсуждается более подробно позже. Вот последний пример использования context: annotation-config:

Файл контекста приложения, использующий тег annotation-config

<?xml version="1.0" encoding="UTF-8"?>
<beans 
        xmlns="http://www.springframework.org/schema/beans" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="
                http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
                http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">

        <context:annotation-config/>

        <bean id="atmTransport" class="com.arcmind.springquickstart.SoapAtmTransport" />


        <bean id="atm" class="com.arcmind.springquickstart.AutomatedTellerMachineImpl">
                <property name="transport" ref="atmTransport"/>
        </bean>

</beans>

Использование @Autowire для определения транспорта по умолчанию

Вы можете определить транспорт по умолчанию для AutomatedTellerMachine. Вы можете сделать это с аннотациями @Autowire и @Qualifier следующим образом:

Использование аннотаций @Autowire и @Qualifier для создания DI

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

public class AutomatedTellerMachineImpl implements AutomatedTellerMachine{

        @Autowired (required=true)
        @Qualifier ("standardTransport")
        private ATMTransport transport;

 При использовании аннотаций Spring для DI вам больше не нужно иметь методы установки (или специальные конструкторы). Spring может внедрять напрямую в приватные поля, или у вас есть возможность аннотировать методы установки. ApplicationContext для этого примера выглядит следующим образом:

многие транспорты настроены в applicationContext, в XML не указано внедрение

<?xml version="1.0" encoding="UTF-8"?>
<beans 
        xmlns="http://www.springframework.org/schema/beans" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="
                http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
                http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">

        <context:annotation-config/>

        <bean id="soapTransport" class="com.arcmind.springquickstart.SoapAtmTransport" />
        <bean id="standardTransport" class="com.arcmind.springquickstart.StandardAtmTransport" />
        <bean id="simulationTransport" class="com.arcmind.springquickstart.SimulationAtmTransport" />


        <bean id="atm" class="com.arcmind.springquickstart.AutomatedTellerMachineImpl"/>


</beans>

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

[Img_assist | NID = 5870 | название = | убывание = | ссылка = нет | ALIGN = не определено | ширина = 720 | Высота = 540] 

Вы можете переопределить, какой компонент устанавливается, используя стандартную инъекцию Spring. Таким образом, у вас есть значение по умолчанию (standardTransport), которое можно переопределить. Вот пример переопределения с другим транспортом, когда у вас есть метод установки для транспорта.

Переопределение аннотации в файле контекста приложения

        <bean id="soapTransport" class="com.arcmind.springquickstart.SoapAtmTransport" />
        <bean id="standardTransport" class="com.arcmind.springquickstart.StandardAtmTransport" />
        <bean id="simulationTransport" class="com.arcmind.springquickstart.SimulationAtmTransport" />


        <bean id="atm" class="com.arcmind.springquickstart.AutomatedTellerMachineImpl">
                <property name="transport" ref="simulationTransport"/>
        </bean>

Инъекция XML DI имеет приоритет над аннотацией. Поэтому аннотация является «разумным значением по умолчанию», но в файле контекста приложения есть последнее слово.

 

Избегайте аппаратных компонентов напрямую к другим компонентам с помощью тега @Qualifier и квалификатора

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

Использование @Qualifier для дополнительного уровня косвенности

public class AutomatedTellerMachineImpl implements AutomatedTellerMachine{

        @Autowired (required=true)
        @Qualifier ("default")
        private ATMTransport transport;

Использование тега квалификатора в applicationContext.xml

        <bean id="soapTransport" class="com.arcmind.springquickstart.SoapAtmTransport" />
        <bean id="standardTransport" class="com.arcmind.springquickstart.StandardAtmTransport">
                <qualifier value="default"/> 
                <!-- NOTE ADDED THIS QUALIFIER that marks this as default -->
        </bean>
        <bean id="simulationTransport" class="com.arcmind.springquickstart.SimulationAtmTransport" />


        <bean id="atm" class="com.arcmind.springquickstart.AutomatedTellerMachineImpl"/>

С этим дополнительным уровнем косвенности вы не подключаете компоненты напрямую к другим компонентам, и если вы решите, что вам следует использовать новый транспортный объект по умолчанию, вам не нужно переписывать каждый зависимый компонент.
Рисунок 4 иллюстрирует инъекцию с использованием этой техники. 

[Img_assist | NID = 5871 | название = | убывание = | ссылка = нет | ALIGN = не определено | ширина = 720 | Высота = 540]

Об авторе

— технический директор Mammatus и эксперт по Java и облачным вычислениям . Рик вовлечен в адвокацию Java CDI и Java EE. Реализации CDI — Resin CandiСварка шваApache OpenWebBeans

Как избежать ада XML с помощью тега компонента сканирования и аннотаций @Service, @Component, @Repository

Представьте себе приложение с сотнями управляемых объектов и размером файла конфигурации XML. Вы можете управлять объектами с помощью Spring, не помещая их в файлы applicationContext, пометив их @Service, @Component или @Repository и указав Spring, где найти объекты. Затем Spring будет сканировать путь к классам в поисках этих bean-компонентов и затем автоматически управлять их зависимостями.
Для выполнения этого действия необходимо настроить тег context: scan, передавая пакеты, которые вы хотите, чтобы Spring сканировал, следующим образом:

Использование тега component-scan в applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans 
        xmlns="http://www.springframework.org/schema/beans" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="
                http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
                http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">


        <context:component-scan base-package="com.arcmind.springquickstart"/>

</beans>

 

Затем вы помечаете свои компоненты с помощью @Service, @Component или @Repository следующим образом:

класс AutomatedTellerMachine с использованием @Service

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service ("atm")
public class AutomatedTellerMachineImpl implements AutomatedTellerMachine{

        @Autowired (required=true)
        @Qualifier ("default")
        private ATMTransport transport;

 

Три транспорта с использованием @Component

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component("standardTransport")
@Qualifier("default")
public class StandardAtmTransport implements ATMTransport {

        public void communicateWithBank(byte[] datapacket) {
                ...
        }

}

@Component("soapTransport")
public class SoapAtmTransport implements ATMTransport {

        public void communicateWithBank(byte[] datapacket) {
                ...
        }

}

@Component("simulationTransport")
public class SimulationAtmTransport implements ATMTransport {

        public void communicateWithBank(byte[] datapacket) {
                ...
        }

}

 

Обратите внимание, что в StandardAtmTransport используется аннотация @Qualifier, чтобы обозначить его как транспорт по умолчанию для этого приложения. Для новых проектов имеет смысл использовать аннотации для объектов, которые не часто меняют свои зависимости. Избегание XML и использование аннотаций — это новая тенденция в DI; некоторые говорят, что это лучшая практика. Рисунок 5 иллюстрирует инъекцию с использованием этой техники.

[Img_assist | NID = 5872 | название = | убывание = | ссылка = нет | ALIGN = не определено | ширина = 720 | Высота = 540]

Об авторе

— технический директор Mammatus и эксперт по Java и облачным вычислениям . Рик вовлечен в адвокацию Java CDI и Java EE. Реализации CDI — Resin CandiСварка шваApache OpenWebBeans

Конфигурирование объектов

Помимо введения зависимостей, Spring позволяет настраивать объекты с примитивными и базовыми типами. Предположим, что SoapAtmTransport иногда должен работать в областях, где соединение не так велико, поэтому вы решили добавить свойство retries в SoapAtmTransport следующим образом:

SoapAtmTransport с повторными попытками

public class SoapAtmTransport implements ATMTransport {

        private int retries=3;

        public SoapAtmTransport() {
        }

        public SoapAtmTransport(int retries) {
                this.retries = retries;
        }

        public void setRetries(int retries) {
                this.retries = retries;
        }

        public void communicateWithBank(byte[] datapacket) {
                System.out.printf("SOAP Transport retries %d: %s \n", retries, new String(datapacket));
        }

}

Обратите внимание, что вы можете передать повторные попытки в конструктор или вызвать метод установки с указанием номера или повторных попыток следующим образом:

введение количества повторных попыток с помощью метода установки

        <bean id="soapTransport" class="com.arcmind.springquickstart.SoapAtmTransport">
                <property name="retries" value="5"/>
        </bean>

Инъекция количества пенсионеров с помощью конструктора arg

        <bean id="soapTransport" class="com.arcmind.springquickstart.SoapAtmTransport">
                <constructor-arg value="6"/>
        </bean>

 

Рисунок 6 иллюстрирует настройку повторных попыток с использованием метода установки метода. 

[Img_assist | NID = 5873 | название = | убывание = | ссылка = нет | ALIGN = не определено | ширина = 720 | Высота = 540] 

На рисунке 7 показана настройка повторных попыток с использованием аргументов конструктора. 

[img_assist | nid = 5874 | title = | desc = | link = none | align = undefined | width = 720 | height = 540]

Поскольку этот тип конфигурации очень распространен, Spring имеет ярлык для упрощения внедрения значения свойства следующим образом:

Использование пространства имен p в файле applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans 
        xmlns="http://www.springframework.org/schema/beans" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:p="http://www.springframework.org/schema/p" 
        xsi:schemaLocation="
                http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
                http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">


        <bean id="soapTransport" class="com.arcmind.springquickstart.SoapAtmTransport" p:retries="7"/>

        <bean id="atm" class="com.arcmind.springquickstart.AutomatedTellerMachineImpl">
                <constructor-arg index="0" ref="soapTransport" />
        </bean>

</beans>

Обратите внимание, что использование p: retries = «7» гораздо менее многословно, чем в предыдущем примере, в котором для задания значения использовался тег свойства. Если вы используете плагин Spring IDE для Eclipse, вы получите завершение кода для синтаксиса p: property-name-syntax. На рисунке 8 показана настройка повторных попыток с использованием ярлыка ярлыка, добавленного в Spring 2.x. 

[Img_assist | NID = 5875 | название = | убывание = | ссылка = нет | ALIGN = не определено | ширина = 720 | Высота = 540] 

Spring позволяет настраивать все примитивные типы (int, byte, long и т. Д.), А также объекты-оболочки (Integer, Byte, Long и т. Д.) И многие базовые типы (String, URL, Class, File и т. Д.). ).

Об авторе

— технический директор Mammatus и эксперт по Java и облачным вычислениям . Рик вовлечен в адвокацию Java CDI и Java EE. Реализации CDI — Resin CandiСварка шваApache OpenWebBeans

Использование конфигуратора заполнителя свойства

Допустим, для каждой установки банкомата установщику может потребоваться настроить количество повторных попыток. Вы, вероятно, не хотите, чтобы установщик связывался с вашим XML-файлом для контекста приложения, потому что он слишком похож на код и слишком много вещей может пойти не так. Вместо этого, возможно, вы могли бы просто отредактировать файл свойств. Файл свойств может иметь свойства для каждой вещи, которые могут различаться для данной установки AutomatedTellerMachineImpl.

Файл свойств atm.properties


transport.retries = 8

applicationContext.xml с использованием тега свойства-заполнителя

<?xml version="1.0" encoding="UTF-8"?>
<beans 
        xmlns="http://www.springframework.org/schema/beans" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:p="http://www.springframework.org/schema/p" 
        xsi:schemaLocation="
                http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
                http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">

        <context:property-placeholder location="classpath:atm.properties"   />


        <bean id="soapTransport" class="com.arcmind.springquickstart.SoapAtmTransport" p:retries="${transport.retries}"/>

        <bean id="atm" class="com.arcmind.springquickstart.AutomatedTellerMachineImpl">
                <constructor-arg index="0" ref="soapTransport" />
        </bean>

</beans>

Обратите внимание, что свойство-заполнитель загружает файл atm.properties из пути к классам. Затем вы используете transport.retries, определенный в файле atm.properties, следующим образом: p: retries = «$ {transport.retries}».
На рисунке 9 показано использование конфигуратора свойства placeholder. 

[Img_assist | NID = 5876 | название = | убывание = | ссылка = нет | ALIGN = не определено | ширина = 720 | Высота = 540] 

Вы можете загрузить файл свойств из файловой системы, используя file: вместо classpath: в расположении следующим образом:

Загрузка файла свойств из файловой системы с помощью свойства-заполнителя

        <context:property-placeholder location="file:./src/main/resources/atm.properties"   />


        <bean id="soapTransport" class="com.arcmind.springquickstart.SoapAtmTransport" p:retries="${transport.retries}"/>

        <bean id="atm" class="com.arcmind.springquickstart.AutomatedTellerMachineImpl">
                <constructor-arg index="0" ref="soapTransport" />
        </bean>

Об авторе

— технический директор Mammatus и эксперт по Java и облачным вычислениям . Рик вовлечен в адвокацию Java CDI и Java EE. Реализации CDI — Resin CandiСварка шваApache OpenWebBeans

Области применения и жизненный цикл

Spring поддерживает концепцию областей. Если вы знакомы с JSP и сервлетами, вы можете вспомнить, что у них есть области запросов, сеансов и приложений. Объекты, помещенные в область действия запроса, остаются в течение одного запроса. Объекты, помещенные в область действия сеанса, остаются вокруг всего сеанса пользователя (если не уничтожены вручную), в то время как объекты, помещенные в область действия приложения, остаются в течение всего времени, пока выполняется веб-приложение.

Поддержка области Spring очень похожа на поддержку JSP и сервлетов. Spring поддерживает следующие области действия: прототип, синглтон, запрос, сессия и многое другое. Кроме того, вы можете настроить свои собственные обработчики области видимости. За пределами веб-приложения Spring в основном поддерживает две области действия: прототип и синглтон. Объект в одной области видимости является объектом по умолчанию. Это означает, что объект будет оставаться таким же, как и контекст приложения (как правило, очень похоже на область приложения в веб-приложении). Область действия прототипа означает, что каждый раз, когда вы запрашиваете объект, Spring создает новый. Например:

Два банкомата, настроенные на разные области

        <bean id="atm" class="com.arcmind.springquickstart.AutomatedTellerMachineImpl" scope="singleton">
                <constructor-arg index="0" ref="soapTransport" />
        </bean>

        <bean id="atmP" class="com.arcmind.springquickstart.AutomatedTellerMachineImpl" scope="prototype">
                <constructor-arg index="0" ref="soapTransport" />
        </bean>

Если вы дважды посмотрели на банкомат, вы получите один и тот же объект, потому что он находится в одноэлементной области видимости; однако каждый раз, когда вы просматривали atmP, вы получали другой объект, потому что он находится в области действия прототипа. Это демонстрируется следующим примером:

Пример, демонстрирующий прототип против синглтона

                AutomatedTellerMachine atm1 = (AutomatedTellerMachine) appContext.getBean("atm");
                AutomatedTellerMachine atm2 = (AutomatedTellerMachine) appContext.getBean("atm");
                assert atm1 == atm2; //First assert

                AutomatedTellerMachine atmP1 = (AutomatedTellerMachine) appContext.getBean("atmP");
                AutomatedTellerMachine atmP2 = (AutomatedTellerMachine) appContext.getBean("atmP");
                assert atmP1 != atmP2; //Second assert

 

Методы жизненного цикла

Часто требуется, чтобы объект инициализировался после того, как вы установили все зависимости. Spring позволяет указать метод init следующим образом:

Указание метода init с помощью Spring (applicationContext.xml)

        <bean id="atm" class="com.arcmind.springquickstart.AutomatedTellerMachineImpl" scope="singleton" init-method="init">
                <constructor-arg index="0" ref="soapTransport" />
        </bean>

        <bean id="atmP" class="com.arcmind.springquickstart.AutomatedTellerMachineImpl" scope="prototype" init-method="init">
                <constructor-arg index="0" ref="soapTransport" />
        </bean>

Notice the use of the init-method attribute in the bean tag. The name of the method does not have to be init.
Here is the init method defined in Java. (There are also a few more methods for the transport to add to the flavor of the of the example and a shutdown method which the article will discuss in a moment).

Init Method and Shutdown method in Java

public class AutomatedTellerMachineImpl implements AutomatedTellerMachine{


        public void init () {
                System.out.println("INIT");
                transport.connect();
        }

        public void shutdown () {
                System.out.println("SHUTDOWN");
                transport.close();
        }

 

The atm bean’s init method gets called right after your first load the application context (you can change this by setting the lazy-init attribute to «true»). The prototype atmP bean’s init method gets called every time you look it up in the application context.

You can also specify a clean up method using the attribute destroy-method as follows:

Using destroy-method attribute

        <bean id="atm" class="com.arcmind.springquickstart.AutomatedTellerMachineImpl" scope="singleton" 
                init-method="init" destroy-method="shutdown">
                <constructor-arg index="0" ref="soapTransport" />
        </bean>

        <bean id="atmP" class="com.arcmind.springquickstart.AutomatedTellerMachineImpl" scope="prototype" 
                init-method="init" destroy-method="shutdown">
                <constructor-arg index="0" ref="soapTransport" />
        </bean>

 

The destroy method would never get called by Spring on atmP because it does not manage the life cycle of prototype beans after creation. The destroy method on atm would only get called if someone gracefully closed the application context which Spring does for some application contexts (this is beyond the scope of this introductory tutorial). Figure 10 illustrates using lifecycle methods. 

[img_assist|nid=5877|title=|desc=|link=none|align=undefined|width=720|height=540]

Conclusion

DI can help make your code architecturally pure. It aids in using a design-by-interface approach as well as test-driven development by providing a consistent way to inject dependencies. You don’t need Spring to use DI. You could use DI with plain old Java. However, Spring provides a very nice, powerful DI container.
There are other DI containers and frameworks out there such as Plexus, Pico container, JBoss microcontainer, and, more recently, Guice. And, other frameworks allow DI like JSF, Seam and more. But, Spring is the de facto industry standard way to do DI.

What we did not cover is also interesting. We did not cover autowiring using by type or by name or constructor autowiring as these are features that developers just don’t use in a production environments. A future tutorial titled, «DI details», will cover this as well as many other topics related to Spring DI like bean definitions, using lists, maps and sets, FactoryBeans, ApplicationContextAware, and, yes, autowiring.
The next item in this tutorial series will be AOP. Followed by Spring DAO and JPA support.

 

Rick Hightower serves as Chief Technology Officer for ArcMind Inc., a consulting and training firm specializing in Spring, JPA/Hibernate, and JSF. Rick enjoys writing and programming.