Pro Spring 4: различия между версиями
FireWolf (обсуждение | вклад) |
FireWolf (обсуждение | вклад) |
||
Строка 477: | Строка 477: | ||
== AfterReturningAdvice == | == AfterReturningAdvice == | ||
Совет "после возврата" (after returning) выполняется после завершения выполнения вызова метода в точке соединения и возврата значения. | Совет "после возврата" (after returning) выполняется после завершения выполнения вызова метода в точке соединения и возврата значения. | ||
Учитывая, что метод уже выполнен, переданные ему аргументы модифицировать невозможно | |||
== AfterAdvice == | == AfterAdvice == |
Версия 05:34, 12 февраля 2017
Жизненный цикл Spring Bean
InitializingBean
Вызывается метод afterPropertiesSet(), который служит той же цели, что и метод init()
@PostConstruct
Начиная с версии Spring 2.5, поддерживаются также и аннотации JSR-250 для указания метода, который платформа Spring должна вызвать, если соответствующая аннотация, связанная с жизненным циклом бина, существует в классе. Это тот же init-method, только имя метода может быть любым. Для работы необходимо добавить дескриптор context:annotation-config.
DisposableBean
Вызывается метод destroy(), который служит той же цели, что и метод указываемый в атрибуте destroy-metod.
@PreDestroy
Применение аннотации жизненного цикла @PreDestroy, определенной в стандарте JSR-250, которая является противоположностью @PostConstruct. Для работы необходимо добавить дескриптор context:annotation-config.
Конфигурация XML
beans
beans default-lazy-init
Атрибут инструктирует Spring о том, что экземпляры бинов, определенных в конфигурационном файле, должны создаваться только при их запросе приложением.
<beans ... default-lazy-init = "true"> <bean ... /> ... </beans>
beans profile
Профиль заставляет Spring конфигурировать только тот контекст ApplicationContext, который определен, когда указанный профиль становится активным. Активируется опцией -Dspring.profiles.active=activeProfile Пример профиля:
<beans xmlns = "http://www.springframework.org/schema/beans" xmlns:xsi = "http://www.wЗ.org/2001/XМLSchema-instance" xsi:schemaLocation = "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd" profile = "profile1"> ... </beans>
см. Environment
context:component-scan
Дескриптор <context:component-scan> сообщает Spring о необходимости сканирования кода на предмет внедряемых бинов, аннотированных с помощью @Component, @Controller, @Repository и @Service, а также поддерживающих аннотации @Autowired и @Inject в указанном пакете (и всех eгo внутренних па кетах). В дескрипторе <context:component-scan> можно определить множество пакетов, используя в качестве разделителя запятую, точку запятой или пробел. Кроме того, для более детализированного управления этот дескриптор поддерживает включение и исключение сканирования компонентов. Также можно указать пакет для сканирования через установку атрибута base-package. Еще можно указать исключения через context:exclude-filter.
context:property-placeholder
Дескриптор context:property-placeholder для загрузки свойств в Sрring-интерфейс Environment, который помещен в оболочку интерфейса ApplicationContext. Кроме того, мы применяем заполнители для внедрения значений в бин AppProperty.
<context:property-placeholder location="classpath:application.properties"/> <bean id="appProperty" class="AppProperty"> <property name="applicationHome" value="${application.home}"/> <property name="userHome" value="${user.home}"></property> </bean>
bean
bean/property
name - Имя свойства бина value - значение (простой тип)
До версии 2.5:
ref - ссылка на другой бин по id
Применение атрибута local означает, что дескриптор ref всегда просматривает только идентификатор бина и никогда не принимает во внимание его псевдонимы:
<ref local="test"/>
Более того, определение бина должно существовать в том же самом ХМL-файле конфигурации.
Пример ссылки на бин (ссылка текущий, дочерний, родительский контекст)
<ref bean="newBean"/>
Пример ссылки на бин родительского контекста
<ref parent="newBean"/>
С версии 2.5: конфигурировать можно не через property, а в самом bean так:
p:<тут имя свойства>-ref="id другого бина"
или так
p:<тут имя свойства>="простое значение"
Через SpEL:
p:name = "#{injectSimpleConfig.name}"
bean/property/map
Пример:
<property name="map"> <map> <entry key="v1"> <value>Hello World!</value> </entry> <entry key="refToBean"> <ref local="localBeanId"/> </entry> </map> </property>
bean/property/set
<property name="set"> <set> <value>Hello World 1 </value> <ref local="oracle" /> </set> </property>
bean/property/list
<property name="list"> <list> <value>Hello World!</value> <ref local="localBeanId"/> </list> </property>
bean/property/props
Дескриптор <props> позволяет передавать в качестве значений только String, потому что класс Properties разрешает только значения свойств типа String. Пример:
<property name="props"> <props> <prop key="firstName">Sasha</prop> <prop key="secondName">V.</prop> </props> </property>
bean/constructor-arg
До версии 3.1: constructor-arg определяет Constructor Injection. Всегда лучше применять атрибут index, чтобы избежать путаницы между параметрами.
С версии 3.1: можно применять в bean выражение вида c:<свойство>=<значение> или _<digit> - как указание индекса аргумента конструктора
<bean id="message" class="java.lang.String" с:_O="message"/>
Если есть 2 конструктора с одинаковыми именами параметров, то можно указать тип
<constructor-arg type="int"><value>1</value><constructor-arg>
bean/lookup-method
Пример Method Injection:
<bean id="abstractLookupBean" class="com.a.AЬstractLookupDemoBean"> <lookup-method name="getMyHelper" bean="helper"/> </bean>
bean/replaced-method
<bean id="replacementTarget" class="com.a.ReplacementTarget"> <replaced-method name="formatMessage" replacer="methodReplacer"> <arg-type>String</arg-type> </replaced-method> </bean>
bean name-алиасы
Через name:
<bean id="name1" name="name2 name3,name4;name5" class="java.lang.String"/>
Через alias:
<alias name = "namel" alias = "name6"/>
Извлечь список псевдонимов бина можно с помощью вызова метода ApplicationContext.getAliases(String) с передачей ему любого из имен бина или его идентификатора. Этот метод возвращает в виде массива String список псевдонимов, содержащий все псевдонимы кроме указанного при вызове.
bean scope
По умолчанию Spring устанавливает атрибут scope в singleton (одиночный). Область действия на уровне prototype (прототип) заставляет Spring создавать новый экземпляр бина каждый раз, когда он запрашивается приложением. Пример:
<bean id="nonSingleton" class="java.lang.String" scope="prototype" c:_0="Sasha V."/>
bean depends-on
В следующей конфигурации мы утверждаем, что бин по имени beanA зависит от бина под названием beanB.
<bean id="beanA" class="BeanA" depends-on="beanB"/> <bean id="beanB" class="BeanB"/>
Во время разработки приложений такого подхода лучше избегать; вместо этого определяйте зависимости с помощью контрактов Setter Injection и Constructor Injection.
bean autowire
В атрибуте autowire для бина понадобится указать используемый режим автосвязывания. Платформа Spring поддерживает следующие режимы автосвязывания: byName, ЬуТуре, constructor, default и no (автосвязывание отключено; устанавливается по умолчанию).
bean lazy-init
Атрибут lazy-init устанавливается в true, чтобы информировать Spring о необходимости создания экземпляра бина только при первом его запросе, а не во время начальной загрузки.
bean parent
Наследование бинов:
<bean id="inheritParent" class="SimpleBean" p:name="Name1" p:age="32"/> <bean id="inheritChild" class="SimpleBean" parent="inheritParent" р:аgе="ЗЗ"/>
bean abstract
В случае если определение родительского бина не должно быть доступным для поиска из ApplicationContext, к дескриптору bean, объявляющему родительский бин, можно добавить атрибут abstract="true".
bean init-method
Атрибут init-method, который сообщает платформе Spring, что она должна вызвать метод init(), как только завершит конфигурирование бина.
<bean id="iBean" class="BeanClass" init-method="init"/>
Аналоги: InitializingBean.afterPropertiesSet(), @PostConstruct
bean destroy-method
Чтобы назначить метод для вызова во время уничтожения бина, нужно просто указать имя этого метода в атрибуте destroy-method дескриптора <bean> для бина. Платформа Spring вызывает этот метод непосредственно перед уничтожением одиночного экземпляра бина (она не будет вызывать этот метод для бинов с областью действия на уровне прототипа).
<bean id="dBean" class="BeanClass" destroy-method="destroy"/>
Аналоги: DisposableBean.destroy(), @PreDestroy
bean factory-bean
Иногда нужно создавать экземпляры компонентов JavaBean, которые были предоставлены приложением третьей стороны, не поддерживающим Spring. Вы не знаете, как создавать экземпляр этого класса, но вам известно, что приложение третьей стороны предлагает класс, который можно использовать для получения экземпляра JavaBean, необходимого вашему приложению Spring.
<bean id="defaultDigest" factory-bean="defaultDigestFactory" factory-method="createinstance"/>
util
Пространство имен util, предоставляемое Spring, для объявления бинов, хранящих свойства коллекций.
util:map
<util:map id="map" map-class = "java.util.HashMap"> <entry key = "someValue"> <value>Hello World!</value> </entry> <entry key="someBean"> <ref bean="beanId"/> </entry> </util:map>
util:properties
<util:properties id="props"> <prop key="firstName">Sasha</prop> <prop key = "secondName">V.</prop> </util:properties>
util:set
<util: set id="set"> <value>Hello World!</value> <ref bean = "oracle"/> </util: set>
util:list
<util:list id="list"> <value>Hello World!</value> <ref bean="oracle"/> </util:list>
Кофигурация аннотациями
@Autowired
Если указано на setter, то происходит автоматическое связывание.
Если указано на construcor, то происходит автоматическая передача параметра, пример:
@Autowired public NewConstructor (@Value ( "message") String message) { this.message = message; }
Аннотация @Autowired может быть применена только к одному из методов конструкторов.
@Inject
В спринг аналогична автоматическому связыванию (JSR-299).
@Resource
Пример - @Resource (name = "messageProvider") указывается для поддержки автоматического связывания. (JSR-250)
@Value
Предназначена для определения значения, подлежащего внедрению. Свойства:
@Value("32") private int age;
Через SpEL:
@Value("#{injectSimpleConfig.name}")
Жесткое кодирование значения не является удачной идеей, т.к. его изменение влечет за собой перекомпиляцию программы.
@Service
Пример - @Service("messageRenderer") указывает, что этот бин предоставляет службы, которые могут требоваться другим бинам; в качестве параметра аннотации передается имя бина.
@Component
@Component("injectSimpleConfig") @Service является специализацией @Component, отражающей тот факт, что аннотированный класс предоставляет бизнес-службу другим уровням внутри приложения.
@Configuration
Аннотация @Configuration для информирования платформы Spring о том, что это конфигурационный файл, основанный на Java.
После этого для объявления бина Spring и требований DI применяется аннотация @Bean.
@Bean
Аннотация @Bean эквивалентна дескриптору <bean>, а имя метода - атрибуту id дескриптора <bean>.
Другие аннотации
@ImportResource(value = "classpath:META-INF/spring/app-context-xml.xml") - для импортирования конфигурации из ХМL-файлов, что означает возможность совместного применения ХМL и Jаvа-классов конфигурации, хотя поступать подобным образом не рекомендуется.
@PropertySource(value = "classpath:message.properties") применяется для загрузки файлов свойств в ApplicationContext и принимает в качестве арrумента местоположение (допускается указывать более одного местоположения). В ХМL той же самой цели служит дескриптор <context:property-placeholder>.
@ComponentScan(basePackages = {"com.test"})
@EnableTransactionManagement
@Lazy(value = true)
@DependsOn(value = "messageProvider")
@Qualifier
JSR-330
@Named("messageProvider") - применяется для объявления внедряемого бина (аналогично аннотации @Component или @Service в Spring).
@Inject
@Singleton - стандарте JSR-330 по умолчанию бин является неодиночным, что похоже на область действия на уровне прототипа в Spring. Таким образом, если вы хотите, чтобы в среде JSR-330 ваш бин был одиночным, то должны применять аннотацию @Singleton.
Классы Spring
ProtertyEditor
ByteArrayPropertyEditor - String в массив байтов
ClassEditor - полностью определенное имя класса в экземпляр Class
CustomВooleanEditor - в Jаvа-тип Boolean
CustomCollectionEditor - в целевой тип Collection
CustomDateEditor - в значение java.util.Date. Этот редактор с желаемым форматом даты необходимо зарегистрировать в ApplicationContext.
CustomNumberEditor - в числовое значение, которым может быть Integer, Long, Float или Double
FileEditor - в экземпляр File
InputStreamEditor - строковое представление ресурса (например, файлового ресурса вида file: D: /temp/test. txt или classpath:test. txt) в свойство входного потока
LocaleEditor - строковое представление локали, такое как en-GB, в экземпляр java.util.Locale
Pattern - в JDК-объект Pattern или наоборот
PropertiesEditor - строку в формате ключl=значениеl ключ2=значение2 ключn=значениеn в экземпляр java.util.Properties с настройкой соответствующих свойств
StringTrimmerEditor - усечение строковых значений перед внедрением. Этот редактор свойств должен быть явно зарегистрирован в ApplicationContext.
URLEditor - строковое представление URL в экземпляр java.net.URL
CustomEditorConfigurer
В JDK 5 или более новых версиях предлагается класс PropertyEditorSupport, который могут расширять специальные редакторы свойств, оставляя вам реализацию только одного метода setAsText(). Чтобы особый класс редактора можно было применять в приложении, его понадобится зарегистрировать в ApplicationContext с использованием CustomEditorConfigurer.
StopWatch
org.springframework.util.StopWatch - этот класс очень полезный в ситуациях, когда необходимо проводить простые оценки производительности и тестировать разрабатываемые приложения.
StopWatch stopWatch = new StopWatch(); stopWatch.start("demo"); for (int х = О; х < 100000; х++) { MyHelper helper = bean.getMyHelper(); helper.doSomethingHelpful(); } stopWatch.stop(); System. out. println ( "100000 gets took " + stopWatch. getTotalTimeMillis () + " ms");
AbstractApplicationContext
AbstractApplicationContext.registerShutdownHook
registerShutdownHook - создать перехватчик завершения (shutdown hook) - поток, который выполняется непосредственно перед завершением приложения. Это отличный способ вызвать метод destroy () вашего класса AbstractApplicationContext (который расширяется всеми конкретными реализациями ApplicationContext).
Пример для автономного приложения:
ctx.load("classpath:META-INF/spring/app-context-annotation.xml"); ctx.registerShutdownHook(); ctx.refresh();
Можно определить бин, который автоматом сделает тоже самое
<bean id="shutdownHook" class="ShutdownHookBean"/>
где ShutdownHookBean implements ApplicationContextAware с таким методом setApplicationContext:
if (ctx instanceof GenericApplicationContext) { ((GenericApplicationContext)ctx).registerShutdownHook(); }
AbstractApplicationContext.destroy
Единственный недостаток обратных вызовов уничтожения в Spring связан с тем, что они не запускаются автоматически, т.е. перед закрытием приложения нужно не забыть вызвать AbstractApplicationContext.destroy(). Когда приложение выполняется как сервлет, указанный метод destroy() можно вызвать в методе destroy() сервлета. Однако в автономном приложении все не так просто, особенно при наличии множества точек выхода из приложения. К счастью, решение есть. Java позволяет создать перехватчик завершения (shutdown hook). См. AbstractApplicationContext.registerShutdownHook
BeanNameAware
Интерфейс BeanNameAware, который бин может реализовать, чтобы получить свое имя, имеет единственный метод: setBeanName (String)
ApplicationContextAware
Интерфейс ApplicationContextAware, который бин может реализовать, чтобы получить ссылку на контекст ApplicationContext, который их сконфигурировал. Имеет метод: setApplicationContext(ApplicationContext ctx) throws BeansException
FactoryBean
В интерфейсе FactoryBean объявлены три метода: getObject(), getObjectType() и isSingleton(). Реализуя этот интерфейс и добавив в него управляющее свойство, можно создавать бины с соответствующего типа, которые будут возвращаться через getObject(). Пример получения нужного типа объекта:
MessageDigest digest = (MessageDigest)ctx.getBean("shaDigest");
Пример получения фабрики бинов для генерации нужного объекта вручную:
MessageDigestFactoryBean factoryBean = (MessageDigestFactoryBean)ctx.getBean("&shaDigest");
MessageSource
определяет 3 типа вызова getМessage(): getMessage(String, Object[], Locale) getMessage(String, Object[] , String, Locale) getMessage(MessageSourceResolvable, Locale)
Реализации: ApplicationContext, ResourceBundleMessageSource, ReloadableResourceBundleMessageSource и StaticMessageSource.
Реализация StaticMessageSource не должна применяться в производственном приложении, поскольку ее нельзя конфигурировать внешне.
Реализация ResourceBundleMessageSource загружает сообщения с использованием Jаvа-класса ResourceBundle.
Реализация ReloadableResourceBundleMessageSource в основном такая же, но поддерживает запланированную перезагрузку лежащих в основе исходных файлов.
Все три реализации MessageSource также реализуют еще один интерфейс по имени HierarchicalMessageSource, который позволяет вкладывать друг в друга экземпляры MessageSource.
Чтобы задействовать поддержку MessageSource, предоставляемую ApplicationContext, в конфигурации должен быть определен бин типа MessageSource с именем messageSource. Контекст ApplicationContext берет этот MessageSource и вкладывает его внутрь себя самого, разрешая доступ к сообщениям с применением ApplicationContext. Пример:
<bean id = "messageSource" class="org.springframework.context.support.ResourceBundleMessageSource" p:basenames-ref = "basenames"/> <util:list id="basenames"> <value>buttons</value> <value>labels</value> </util:list>
Файлы должны называться labels_en.properties labels_ru.properties и buttons_en.properties buttons_ru.properties.
ApplicationEvent
Событие - это класс, производный от ApplicationEvent, который сам является производным от java.util.EventObject. Любой бин может прослушивать события, реализовав интерфейс ApplicationListener<T>; при этом AppliсаtionContext автоматически регистрирует любой сконфигурированный бин, который реализует данный интерфейс, в качестве прослушивателя.
Публикация события через ApplicationContext:
ApplicationContext ctx = ...; ctx.publishEvent(new ApplicationEvent(...));
Resource
В интерфейсе Resource определены десять самоочевидных методов: contentLength(), exists(), getDescription(), getFile(), getFileName(), getURI(), getURL(), isOpen(), isReadble() и lastModified(). В дополнение к этим десяти методам имеется еще один, не столь самоочевидный: createRelative(). Метод createRelative() создает новый экземпляр Resource, используя путь относительно экземпляра, на котором он вызывается.
В большинстве случаев будет применяться одна из встроенных реализаций для доступа к файлу (класс FileSystemResource), пути классов (класс ClassPathResource) или URL-pecypcaм (класс UrlResource).
Environment
Для установки активного профиля необходимо обратиться к интерфейсу Environment. Этот интерфейс представляет собой уровень абстракции, предназначенный для инкапсуляции среды выполняющегося приложения Spring. Кроме профилей интерфейс Environment инкапсулирует и другие ключевые порuии информаuии - свойства. Свойства служат для сохранения лежащей в основе приложения конфигурации среды, куда входит местоположение папки приложения, параметры подключения к базе данных и т.д. см. beans profile
АОП
Типы АОП
Различают два типа АОП: статическое и динамическое. При статическом АОП, таком как предоставляемое механизмами связывания во время компиляции AspectJ, сквозная функциональность применяется к коду на этапе компиляции, и ее нельзя изменить без модификации кода и повторной компиляции.
Концепция
Joiлpoint: Точка соединения - это четко определенная точка во время выполнения приложения. Типовые примеры точек соединения включают обращение к методу, собственно вызов метода (Method Invocation), инициализацию класса и создание экземпляра объекта.
Advice: Фрагмент кода, который должен выполняться в отдельной точке соединения, представляет собой совет (advice), определенный методом в классе.
Pointcut: Срез (pointcut) - это коллекция точек соединения, которая используется для определения ситуации, когда совет должен быть выполнен.
Aspect: Аспект (aspect) - это комбинация совета и срезов, инкапсулированных в классе.
Weaving: Связывание (weaving) представляет собой процесс вставки аспектов в определенную точку внутри кода приложения.
Target: Цель (target) - это объект, поток выполнения которого изменяется каким-то процессом АОП.
Introduction: Введение (introduction) представляет собой процесс, посредством которого можно изменить структуру объекта за счет помещения в него дополнительных методов или полей.
MethodInvocation
Представляет вызов метода, снабжаемый советом, и с помощью этого объекта мы управляем тем, когда вызову метода разрешено продолжаться.
ProxyFactory
Используется для создания прокси целевого объекта и одновременного его связывания с советом.
Пример:
MessageWriter target = new MessageWriter(); // целевой объект ProxyFactory pf = new ProxyFactory(); pf.addAdvice(new MessageDecorator()); // установка совета pf.setTarget(target); // установка целевого объекта MessageWriter proxy = (MessageWriter) pf.getProxy(); // получение прокси-объекта с советом proxy.writeMessage(); // вызов метода прокти-объекта
Один и тот же экземпляр ProxyFactory можно применять для создания множества прокси, каждый из которых имеет отличающийся аспект. Чтобы помочь в этом, в ProxyFactory предусмотрены методы removeAdvice() и removeAdvisor(), позволяющие удалять из ProxyFactory любой совет или реализации Advisor, которые ранее были добавлены.
Для проверки, имеет ли ProxyFactory конкретный присоединенный к нему совет, вызовите метод adviceincluded(), передав ему проверяемый объект совета.
Advisor
В реализации АОП в Spring аспект представляется экземпляром клacca, который реализует интерфейс Advisor. Платформа Spring предлагает удобные реализации Advisor, которые можно применять в своих приложениях, устраняя необходимость в создании специальных реализаций Advisor. Существуют два подчиненных интерфейса Advisor: IntroductionAdvisor и PointcutAdvisor.
Если необходим дополнительный контроль над созданием Advisor или нужно добавить введение к прокси, создайте реализацию Advisor самостоятельно и используйте метод addAdvisor() класса ProxyFactory.
MethodВeforeAdvice
Совет "перед" (before), можно осущест влять специальную обработку перед входом в точку соединения.
void before(Method method, Object(] args, Object target) throws ThrowaЫe
AfterReturningAdvice
Совет "после возврата" (after returning) выполняется после завершения выполнения вызова метода в точке соединения и возврата значения. Учитывая, что метод уже выполнен, переданные ему аргументы модифицировать невозможно
AfterAdvice
Совет "после возврата" выполняется только в случае нормального завершения метода, снабженного советом. Однако совет "после" (after(finally)) будет выполняться вне зависимости от результата метода, снабженного этим советом.
Methodinterceptor
В Spring совет "вокруг" (around) моделируется с использованием стандарта Альянса АОП для nерехватчика метода.
Интерфейс Methodinterceptor - это стандартный интерфейс Альянса АОП для реализации совета "вокруг" для точек соединения вызовов методов. Object invoke(Methodinvocation invocation) throws Throwable
ThrowsAdvice
Совет "перехват" (throws) выполняется после возврата из вызова метода, но только в случае, если во время вызова было сгенерировано исключение.
IntroductionInterceptor
Платформа Spring моделирует "введения" (introduction) как специальные типы перехватчиков. Используя перехватчик введения, можно указать реализацию методов, которые должны быть введены советом