Pro Spring 4: различия между версиями
FireWolf (обсуждение | вклад) |
FireWolf (обсуждение | вклад) |
||
(не показано 87 промежуточных версий этого же участника) | |||
Строка 24: | Строка 24: | ||
должны создаваться только при их запросе приложением. | должны создаваться только при их запросе приложением. | ||
<nowiki> <beans ... default-lazy-init = "true"> | <nowiki> <beans ... default-lazy-init = "true"> | ||
<bean ... /> | |||
... | |||
</beans></nowiki> | </beans></nowiki> | ||
=== beans profile === | |||
Профиль заставляет Spring конфигурировать только тот контекст ApplicationContext, который определен, когда указанный профиль становится активным. | |||
Активируется опцией -Dspring.profiles.active=activeProfile | |||
Пример профиля: | |||
<nowiki> <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></nowiki> | |||
см. Environment | |||
== context:component-scan == | == context:component-scan == | ||
Строка 39: | Строка 52: | ||
Также можно указать пакет для сканирования через установку атрибута base-package. | Также можно указать пакет для сканирования через установку атрибута base-package. | ||
Еще можно указать исключения через context:exclude-filter. | Еще можно указать исключения через context:exclude-filter. | ||
== context:property-placeholder == | |||
Дескриптор context:property-placeholder для загрузки свойств в Sрring-интерфейс Environment, который помещен в оболочку интерфейса ApplicationContext. Кроме того, мы применяем заполнители для внедрения значений в бин AppProperty. | |||
<nowiki> <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></nowiki> | |||
== bean == | == bean == | ||
Строка 65: | Строка 86: | ||
Пример: | Пример: | ||
<nowiki><property name="map"> | <nowiki><property name="map"> | ||
<map> | |||
<entry key="v1"> | |||
<value>Hello World!</value> | |||
</entry> | |||
<entry key="refToBean"> | |||
<ref local="localBeanId"/> | |||
</entry> | |||
</map> | |||
</property></nowiki> | |||
==== bean/property/set ==== | ==== bean/property/set ==== | ||
<nowiki><property name="set"> | <nowiki><property name="set"> | ||
<set> | |||
<value>Hello World 1 </value> | |||
<ref local="oracle" /> | |||
</set> | |||
</property></nowiki> | |||
==== bean/property/list ==== | ==== bean/property/list ==== | ||
<nowiki><property name="list"> | <nowiki><property name="list"> | ||
<list> | |||
<value>Hello World!</value> | |||
<ref local="localBeanId"/> | |||
</list> | |||
</property></nowiki> | |||
==== bean/property/props ==== | ==== bean/property/props ==== | ||
Строка 119: | Строка 140: | ||
Пример Method Injection: | Пример Method Injection: | ||
<nowiki> <bean id="abstractLookupBean" class="com.a.AЬstractLookupDemoBean"> | <nowiki> <bean id="abstractLookupBean" class="com.a.AЬstractLookupDemoBean"> | ||
<lookup-method name="getMyHelper" bean="helper"/> | |||
</bean></nowiki> | |||
=== bean/replaced-method === | === bean/replaced-method === | ||
<nowiki> <bean id="replacementTarget" class="com.a.ReplacementTarget"> | <nowiki> <bean id="replacementTarget" class="com.a.ReplacementTarget"> | ||
<replaced-method name="formatMessage" replacer="methodReplacer"> | |||
<arg-type>String</arg-type> | |||
</replaced-method> | |||
</bean></nowiki> | |||
=== bean name-алиасы === | === bean name-алиасы === | ||
Через name: | Через name: | ||
Строка 146: | Строка 167: | ||
под названием beanB. | под названием beanB. | ||
<nowiki> <bean id="beanA" class="BeanA" depends-on="beanB"/> | <nowiki> <bean id="beanA" class="BeanA" depends-on="beanB"/> | ||
<bean id="beanB" class="BeanB"/></nowiki> | |||
Во время разработки приложений такого подхода лучше избегать; вместо этого определяйте зависимости с помощью контрактов Setter Injection и Constructor Injection. | Во время разработки приложений такого подхода лучше избегать; вместо этого определяйте зависимости с помощью контрактов Setter Injection и Constructor Injection. | ||
Строка 159: | Строка 180: | ||
Наследование бинов: | Наследование бинов: | ||
<nowiki> <bean id="inheritParent" class="SimpleBean" p:name="Name1" p:age="32"/> | <nowiki> <bean id="inheritParent" class="SimpleBean" p:name="Name1" p:age="32"/> | ||
<bean id="inheritChild" class="SimpleBean" parent="inheritParent" р:аgе="ЗЗ"/></nowiki> | |||
=== bean abstract === | === bean abstract === | ||
Строка 176: | Строка 197: | ||
<nowiki><bean id="dBean" class="BeanClass" destroy-method="destroy"/></nowiki> | <nowiki><bean id="dBean" class="BeanClass" destroy-method="destroy"/></nowiki> | ||
Аналоги: DisposableBean.destroy(), @PreDestroy | Аналоги: DisposableBean.destroy(), @PreDestroy | ||
=== bean factory-bean === | |||
Иногда нужно создавать экземпляры компонентов JavaBean, которые были предоставлены приложением третьей стороны, не поддерживающим Spring. | |||
Вы не знаете, как создавать экземпляр этого класса, но вам известно, что приложение третьей стороны предлагает класс, который можно использовать для получения экземпляра JavaBean, необходимого вашему приложению Spring. | |||
<bean id="defaultDigest" | |||
factory-bean="defaultDigestFactory" | |||
factory-method="createinstance"/> | |||
=== bean factory-method === | |||
см. bean factory-bean | |||
== util == | == util == | ||
Строка 181: | Строка 212: | ||
=== util:map === | === util:map === | ||
<nowiki> <util:map id="map" map-class = "java.util.HashMap"> | <nowiki> <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></nowiki> | |||
=== util:properties === | === util:properties === | ||
<nowiki> <util:properties id="props"> | <nowiki> <util:properties id="props"> | ||
<prop key="firstName">Sasha</prop> | |||
<prop key = "secondName">V.</prop> | |||
</util:properties></nowiki> | |||
=== util:set === | === util:set === | ||
<nowiki> <util: set id="set"> | <nowiki> <util: set id="set"> | ||
<value>Hello World!</value> | |||
<ref bean = "oracle"/> | |||
</util: set></nowiki> | |||
=== util:list === | === util:list === | ||
<nowiki> <util:list id="list"> | <nowiki> <util:list id="list"> | ||
<value>Hello World!</value> | |||
<ref bean="oracle"/> | |||
</util:list></nowiki> | |||
== aop == | |||
aop:aspectj-autoproxy - включение АОП с использованием аннотаций, см. АОП с аннотациями | |||
<syntaxhighlight lang="xml"> | |||
<aop:config> | |||
<aop:pointcut id="fooExecution" expression="execution(* foo*(int))"/> | |||
<aop:aspect ref = "advice"> | |||
<aop:before pointcut-ref="fooExecution" method="simpleBeforeAdvice"/> | |||
</aop:aspect> | |||
</aop:config> | |||
<bean id="advice" class="MyAdvice"/> | |||
<bean id="myDependency" class="MyDependency"/> | |||
<bean id="myBean" class="MyBean"> | |||
<property name="dep" ref="myDependency"/> | |||
</bean> | |||
</syntaxhighlight> | |||
aop:before - до запуска (приоритет выполнения перед arount) | |||
аор:around - вокруг запуска | |||
aop:after-returning - после возврата, работает в случае отсутствия исключения | |||
aop:after - после, работает и в случае отсутствия исключения и в случае наличия исключения | |||
= Кофигурация аннотациями = | = Кофигурация аннотациями = | ||
Строка 242: | Строка 297: | ||
@Component("injectSimpleConfig") | @Component("injectSimpleConfig") | ||
@Service является специализацией @Component, отражающей тот факт, что аннотированный класс предоставляет бизнес-службу другим уровням внутри приложения. | @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 = | = Классы 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 == | == StopWatch == | ||
org.springframework.util.StopWatch - этот класс очень полезный в ситуациях, когда необходимо проводить простые оценки производительности и тестировать разрабатываемые приложения. | org.springframework.util.StopWatch - этот класс очень полезный в ситуациях, когда необходимо проводить простые оценки производительности и тестировать разрабатываемые приложения. | ||
Строка 261: | Строка 378: | ||
ctx.load("classpath:META-INF/spring/app-context-annotation.xml"); | ctx.load("classpath:META-INF/spring/app-context-annotation.xml"); | ||
ctx.registerShutdownHook(); | ctx.registerShutdownHook(); | ||
ctx.refresh (); | ctx.refresh(); | ||
Можно определить бин, который автоматом сделает тоже самое | Можно определить бин, который автоматом сделает тоже самое | ||
<nowiki><bean id="shutdownHook" class="ShutdownHookBean"/></nowiki> | <nowiki><bean id="shutdownHook" class="ShutdownHookBean"/></nowiki> | ||
Строка 280: | Строка 397: | ||
Имеет метод: | Имеет метод: | ||
setApplicationContext(ApplicationContext ctx) throws BeansException | 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. | |||
Пример: | |||
<nowiki> <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></nowiki> | |||
Файлы должны называться 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) представляет собой процесс, посредством которого можно изменить структуру объекта за счет помещения в него дополнительных методов или полей. | |||
[[Файл:Spring-AOP-interfaces.png|безрамки|800x800пкс]] | |||
== 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(), передав ему проверяемый объект совета. | |||
При подмешивании (mixin): | |||
Вызов setOptimize(true) обеспечивает применение CBLIB, чтобы сработало наследование и подмешивание интерфейса. При использовании setOptimize(false) (по умолчанию) используется JDK для создания прокси и тогда применяется только интерфейс смеси. | |||
setFrozen(true) запрещает смену совета (advice) для оптимизации. | |||
exposeProxy ??? | |||
== ProxyFactoryBean == | |||
В АОП, реализованном платформой Spring, класс ProxyFactoryBean предоставляет декларативный способ конфигурирования ApplicationContext (и, следовательно, лежащего в основе BeanFactory) при создании прокси АОП на основе определенных бинов Spring. | |||
Пример декларативного вида для советов: | |||
bean1 - все снабжается советом, т.к. нет никаких срезов. | |||
bean2 - совет снабжается только на метод foo, т.к. есть срез.<syntaxhighlight lang="xml"> | |||
<bean id="myBean1" class="MyBean"> | |||
<property name = "dep"> | |||
<ref bean = "myDependencyl "/> | |||
</property> | |||
</bean> | |||
<bean id="myBean2" class="MyBean"> | |||
<property name="dep"> | |||
<ref bean="myDependency2 "/> | |||
</property> | |||
</bean> | |||
<bean id="myDependencyl" class="org.springframework.aop.framework.ProxyFactoryBean"> | |||
<property name="target"> | |||
<ref bean="myDependencyTarget" /> | |||
</property> | |||
<property name="interceptorNames"> | |||
<list> | |||
<value>advice</value> | |||
</list> | |||
</property> | |||
</bean> | |||
<bean id="myDependency2" class="org.springframework.aop.framework.ProxyFactoryBean"> | |||
<property name="target"> | |||
<ref bean="myDependencyTarget" /> | |||
</property> | |||
<property name="interceptorNames"> | |||
<list> | |||
<value>advisor</value> | |||
</list> | |||
</property> | |||
</bean> | |||
<bean id="advice" class="MyAdvice"/> | |||
<bean id="advisor" class="org.springframework.aop.support.DefaultPointcutAdvisor"> | |||
<property name="advice"> | |||
<ref bean="advice"/> | |||
</property> | |||
<property name="pointcut"> | |||
<bean class="org.springframework.aop.aspectj.AspectJExpressionPointcut"> | |||
<property name="expression "> | |||
<value>execution(* foo*( .. ))</value> | |||
</property> | |||
</bean> | |||
</property> | |||
</bean> | |||
</syntaxhighlight> | |||
Пример декларативного вида для введений: | |||
<syntaxhighlight lang="xml"> | |||
<bean id="bean" class="org.springframework.aop.framework.ProxyFactoryBean"> | |||
<property name="target"> | |||
<bean class="TargetBean"> | |||
<property name="name"> | |||
<value>Sasha V.</value> | |||
</property> | |||
</bean> | |||
</property> | |||
<property name="interceptorNames"> | |||
<list> | |||
<value>advisor</value> | |||
</list> | |||
</property> | |||
<property name="proxyTargetClass"> | |||
<value>true</value> | |||
</property> | |||
</bean> | |||
<bean id="advisor" class="IsModifiedAdvisor"/> | |||
</syntaxhighlight> | |||
== 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) выполняется после завершения выполнения вызова метода в точке соединения и возврата значения. | |||
Учитывая, что метод уже выполнен, переданные ему аргументы модифицировать невозможно | |||
В совете "после возврата" невозможно модифицировать возвращаемое значение. | |||
Несмотря на то что совет "после возврата" не позволяет изменять возвращаемое значение вызова метода, можно сгенерировать исключение, которое будет передано вверх по стеку вместо возвращаемого значения. | |||
void afterReturning(Object returnValue, Method method, Object[] args,Object target) throws Throwble | |||
== AfterAdvice == | |||
Совет "после возврата" выполняется только в случае нормального завершения метода, снабженного советом. | |||
Однако совет "после" (after(finally)) будет выполняться вне зависимости от результата метода, снабженного этим советом. | |||
== Methodinterceptor == | |||
В Spring совет "вокруг" (around) моделируется с использованием стандарта Альянса АОП для nерехватчика метода. | |||
Интерфейс Methodinterceptor - это стандартный интерфейс Альянса АОП для реализации совета "вокруг" для точек соединения вызовов методов. | |||
Object invoke(Methodinvocation invocation) throws Throwable | |||
== ThrowsAdvice == | |||
Совет "перехват" (throws) выполняется после возврата из вызова метода, но только в случае, если во время вызова было сгенерировано исключение. | |||
Первый метод afterThrowing () в классе принимает единственный аргумент типа Exception. | |||
В нем можно указывать любой тип исключения, и этот метод идеально подходит, когда вас не интересует метод, сгенерировавший исключение, или переданные ему аргументы. | |||
void afterThrowing(Exception1 ех) throws Throwable | |||
Во втором методе afterThrowing () мы объявили четыре аргумента для указания метода, сгенерировавшего исключение, аргументов, переданных этому методу, и цели вызова метода. Порядок следования аргументов в этом методе важен, и они должны быть указаны все четыре. | |||
void afterThrowing(Method method, Object[] args, Object target, Exception1 ех) throws Throwable | |||
Exception1 - это конкретный тип исключения и все его подтипы для перехвата. | |||
Spring использует метод, сигнатура которого в наибольшей степени соответствует типу исключения. | |||
В ситуации, когда совет "перехват" имеет дело с двумя методами afterThrowing(), причем оба объявлены с тем самым типом Exception, | |||
но один принимает единственный аргумент, а другой - четыре аргумента, платформа Spring вызывает метод afterThrowing() с четырьмя аргументами. | |||
== IntroductionInterceptor == | |||
Платформа Spring моделирует "введения" (introduction) как специальные типы перехватчиков. Используя перехватчик введения, можно указать реализацию методов, которые должны быть введены советом | |||
== Pointcut == | |||
public interface Pointcut { | |||
ClassFilter getClassFilter (); | |||
Method Мatcher getMethodМatcher(); | |||
} | |||
В версии Spring 4.0 предлагаются восемь реализаций интерфейса Pointcut: | |||
AnnotationМatchingPointcut - Срез, который ищет специфическую Jаvа аннотацию в классе или методе. | |||
AspectJExpressionPointcut - Срез, который использует средство связывания AspectJ для оценки выражения среза, представлен ного с помощью синтаксиса AspectJ | |||
ComposablePointcut - применяется для объединения двух и более срезов с помощью таких операций, как union() и intersection() | |||
ControlFlowPointcut - срез, предназначенный для специального случая, который соответствует всем методам в потоке управления другого метода - т.е . любому методу, который вызван прямо или косвенно в результате выполнения другого метода | |||
DynamicMethodМatcherPointcut - служит базовым классом для построения динамических срезов | |||
JdkRegexpMethodPointcut - позволяет определять срезы с использованием подцержки регулярных выражений JDK 1.4 | |||
NameMatchMethodPointcut - срез, который выполняет простое сопоставление со списком имен методов | |||
StaticMethodМatcherPointcut - служит базовым классом для построения статических срезов | |||
[[Файл:Pointcut-hierarchy.png|безрамки|800x800пкс]] | |||
== DefaultPointcutAdvisor == | |||
Класс DefaultPointcutAdvisor - это просто PointcutAdvisor для связывания одного Pointcut с одним Advice. | |||
== ClassFilter == | |||
boolean matches(Class<?> clazz); | |||
== MethodМatcher == | |||
public interface MethodМatcher { | |||
boolean matches(Method m, Class<?> targetClass); | |||
boolean isRuntime(); | |||
boolean matches(Method m, Class<?> targetClass, Object[J args); | |||
} | |||
Перед использованием MethodMatcher платформа Spring вызывает isRuntime() для выяснения, является ли MethodМatcher статическим, на что указывает возвращенное значение false, или же динамическим, что отражается значением true. | |||
Для статического среза Spring вызывает метод matches(Method, Class<T>) интерфейса MethodMatcher по одному разу для каждого метода целевого объекта, кешируя возвращаемое значение для послед у ющих обращений к этому методу. | |||
Для динамических в дополнении в первому вызову с результатом true платформа Spring проводит дальнейшую проверку для каждого вызова метода, используя matches(Method, Class<T>, Obj ect[]). | |||
<references /> | |||
= АОП с аннотациями = | |||
== Включение АОП с аннотациями в XML == | |||
<nowiki><aop:aspectj-autoproxy/></nowiki> | |||
имеет атрибут proxy-target-class. | |||
По умолчанию он установлен в false, а это означает, что Spring будет создавать стандартные прокси, основанные на интерфейсах, | |||
с использованием динамического прокси JDK. В случае установки proxy-target-class в true платформа Spring будет применять | |||
библиотеку CGLIВ для создания прокси, которые основаны на классах . | |||
== @Aspect == | |||
Применяется к классу совместно с @Component, который будет советом, объявляя его классом аспекта. | |||
== @Pointcut == | |||
Примеры: | |||
@Pointcut("execution(* com..foo*(int)) && args(intValue)") | |||
@Pointcut ( "bean (myDependency*) ") | |||
== @Before == | |||
Определяет метод совета перед. | |||
@Before("fooExecution(intValue) && inMyDependency()") | |||
== @Around == | |||
Определяет метод совета вокруг. | |||
@Around("fooExecution(intValue) && inMyDependency()") | |||
= JDBC = | |||
Настройка конфигурации jdbc в XML: | |||
xmlns:jdbc="http://www.springframework.org/schema/jdbc" | |||
xsi:schemaLocation="http://www.springframework.org/schema/jdЬc http://www.springframework.org/schema/jdbc/spring-jdЬc.xsd" | |||
== JdbcTemplate == | |||
JdbcTemplate - универсальный класс для работы с запросами, отображения из таблиц в коллекции и наоборот. | |||
== JdbcDaoSupport == | |||
Позволяет упростить формирование DAO формируя ссылку на JdbcTemplate. | |||
== DataSource == | |||
Предоставляет и управляет набором реализаций Connection. | |||
Реализация: DriverManagerDataSource | |||
Пример конфигурации: | |||
<bean id = "dataSource" class = "org.springframework.jdЬc.datasource.DriverManagerDataSource" | |||
p:driverClassName="${jdЬc.driverClassName}" | |||
p:url="$ { jdbc. url}" | |||
p:username = "${jdЬc.username}" | |||
p:password = "${jdbc.password}"/> | |||
<context:property-placeholder location = "classpath:META-INF/config/jdbc.properties"/> | |||
jdbc.properties: | |||
jdbc.driverClassName=com.mysql.jdЬc.Driver | |||
jdbc.url = jdbc:mysql://localhost:3306/prospring4 сhб | |||
jdbc.username = prospring4 | |||
jdЬc.password=prospring4 | |||
JNDI до версии 2.5: | |||
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean" | |||
p:jndiName = "java:comp/env/jdbc/prospring4ch6"/> | |||
JNDI с версии 2.5: | |||
<beans xmlns = "http://www.springframework.org/schema/beans" | |||
xmlns:xsi = "http://www.wЗ.org/2001/XMLSchema-instance" | |||
xmlns:jee = "http://www.springframework.org/schema/jee"300 | |||
xsi:schemaLocation = "http://www.springframework.org/schema/beans | |||
http://www.springframework.org/schema/beans/spring-beans.xsd | |||
http://www.springframework.org/schema/jee | |||
http://www.springframework.org/schema/jee/spring-jee.xsd"> | |||
<jee:jndi-lookup jndi-name = "java:comp/env/jdЬc/prospring4ch6"/> | |||
</beans> | |||
Ссыпка на ресурс в файле описателя приложения: | |||
<root-node> | |||
<resource-ref> | |||
<res-ref-name>jdbc/prospring4ch6</res-ref-name> | |||
<res-type>javax.sql.DataSource</res-type> | |||
<res-auth>Container</res-auth> | |||
</resource-ref> | |||
</root-node> | |||
Например, он становится <web-app> в описателе веб-развертывания (WEB-INF /web. xrnl), если приложение представляет собой веб-модуль. | |||
== NamedParameterJdbcTemplate == | |||
Пример применения именованных запросов: | |||
private NamedParameterJdbcTemplate namedParameterJdbcTemplate; | |||
... { | |||
String sql = "select last_name from contact where id = :contactId"; | |||
Map<String, Object> namedParameters = new HashMap<String, Object>(); | |||
namedParameters.put("contactId", id); | |||
return namedParameterJdbcTemplate.queryForObject(sql, namedParameters, String.class); | |||
} | |||
== RowМapper<T> == | |||
Интерфейс для простого способа отображения результирующего набора JDBC на объекты POJO. | |||
private static final class ContactMapper implements RowMapper<Contact> { | |||
public Contact mapRow(ResultSet rs, int rowNum) throws SQLException { | |||
Contact contact = new Contact(); | |||
contact.setid(rs.getLong("id")); | |||
contact.setFirstName(rs.getString("first_name")); | |||
contact.setLastName(rs.getString("last_name") ); | |||
contact.setBirthDate(rs.getDate("Ьirth_date") ); | |||
return contact; | |||
} | |||
} | |||
Объявление класса ContactMapper как статического внутреннего класса позволяет совместно использовать RowMapper<T> множеством методов поиска. | |||
Использование в DAO | |||
String sql = "select id, first_ name, last_ name, Ьirth_date from contact"; | |||
return namedParameterJdЬcTemplate.query(sql, new ContactMapper()); | |||
При работе с Java 8 вместо создания класса ContactMapper, как было показано ранее, можно применить лямбда-выражение: | |||
@Override | |||
public List<Contact> findAll() { | |||
String sql = "select id, first_name, last_name, Ьirth date from contact"; | |||
return namedParameterJdbcTemplate.query(sql, (rs, rowNum) -> { | |||
Contact contact = new Contact(); | |||
contact.setid(rs.getLong("id")); | |||
contact.setFirstName(rs.getString("first_name")); | |||
contact.setLastName(rs.getString("last_name")); | |||
contact.setBirthDate(rs.getDate("Ьirth_date")); | |||
return contact; | |||
}); | |||
} | |||
такое возможно из-за того, что в интерфейсе RowМapper описан 1 метод с 2 параметрами ResultSet rs, int rowNum. | |||
RowMapper<T> подходит только для отображения строки на одиночный объект предметной области. | |||
== ResultSetExtractor == | |||
Для получения связанных объектов реализуем метод extractData() для трансформации результирующего набора в список объектов. | |||
public List<?> extractData(ResultSet rs) throws SQLException,DataAccessException | |||
или лямба выражение | |||
return namedParameterJdbcTemplate.query(sql, (ResultSet rs) -> ( | |||
... | |||
return ArrayList ...; | |||
}); | |||
== jdbc embedded == | |||
Пример встроенной БД: | |||
<jdbc:emЬedded-database id="dataSource" type="H2"> | |||
<jdbc:script location="classpath:META-INF/sql/schema.sql"/> | |||
<jdbc:script location="classpath:META-INF/sql/test-data.sql"/> | |||
</jdЬc:emЬedded-database> | |||
Важен порядок следования: | |||
1. Схема (DDL (Data Definition Language)) - schema.sql, | |||
2. данные (DML (Data Manipulation Language) - test-data.sql. | |||
В атрибуте type задается тип используемой встроенной базы данных. В версии Spring 4.0 поддерживаются типы HSQL (стандартный), Н2 и DERBY. | |||
Вместо указания type и embedded-database просто используйте initialize-database, и сценарии будут выполняться в отношении заданного источника данных, как если бы речь шла о встроенной базе данных. |
Текущая версия на 13:37, 14 февраля 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"/>
bean factory-method
см. bean factory-bean
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>
aop
aop:aspectj-autoproxy - включение АОП с использованием аннотаций, см. АОП с аннотациями
<aop:config>
<aop:pointcut id="fooExecution" expression="execution(* foo*(int))"/>
<aop:aspect ref = "advice">
<aop:before pointcut-ref="fooExecution" method="simpleBeforeAdvice"/>
</aop:aspect>
</aop:config>
<bean id="advice" class="MyAdvice"/>
<bean id="myDependency" class="MyDependency"/>
<bean id="myBean" class="MyBean">
<property name="dep" ref="myDependency"/>
</bean>
aop:before - до запуска (приоритет выполнения перед arount)
аор:around - вокруг запуска
aop:after-returning - после возврата, работает в случае отсутствия исключения
aop:after - после, работает и в случае отсутствия исключения и в случае наличия исключения
Кофигурация аннотациями
@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(), передав ему проверяемый объект совета.
При подмешивании (mixin): Вызов setOptimize(true) обеспечивает применение CBLIB, чтобы сработало наследование и подмешивание интерфейса. При использовании setOptimize(false) (по умолчанию) используется JDK для создания прокси и тогда применяется только интерфейс смеси.
setFrozen(true) запрещает смену совета (advice) для оптимизации.
exposeProxy ???
ProxyFactoryBean
В АОП, реализованном платформой Spring, класс ProxyFactoryBean предоставляет декларативный способ конфигурирования ApplicationContext (и, следовательно, лежащего в основе BeanFactory) при создании прокси АОП на основе определенных бинов Spring.
Пример декларативного вида для советов:
bean1 - все снабжается советом, т.к. нет никаких срезов.
bean2 - совет снабжается только на метод foo, т.к. есть срез.
<bean id="myBean1" class="MyBean">
<property name = "dep">
<ref bean = "myDependencyl "/>
</property>
</bean>
<bean id="myBean2" class="MyBean">
<property name="dep">
<ref bean="myDependency2 "/>
</property>
</bean>
<bean id="myDependencyl" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<ref bean="myDependencyTarget" />
</property>
<property name="interceptorNames">
<list>
<value>advice</value>
</list>
</property>
</bean>
<bean id="myDependency2" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<ref bean="myDependencyTarget" />
</property>
<property name="interceptorNames">
<list>
<value>advisor</value>
</list>
</property>
</bean>
<bean id="advice" class="MyAdvice"/>
<bean id="advisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="advice">
<ref bean="advice"/>
</property>
<property name="pointcut">
<bean class="org.springframework.aop.aspectj.AspectJExpressionPointcut">
<property name="expression ">
<value>execution(* foo*( .. ))</value>
</property>
</bean>
</property>
</bean>
Пример декларативного вида для введений:
<bean id="bean" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<bean class="TargetBean">
<property name="name">
<value>Sasha V.</value>
</property>
</bean>
</property>
<property name="interceptorNames">
<list>
<value>advisor</value>
</list>
</property>
<property name="proxyTargetClass">
<value>true</value>
</property>
</bean>
<bean id="advisor" class="IsModifiedAdvisor"/>
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) выполняется после завершения выполнения вызова метода в точке соединения и возврата значения.
Учитывая, что метод уже выполнен, переданные ему аргументы модифицировать невозможно
В совете "после возврата" невозможно модифицировать возвращаемое значение.
Несмотря на то что совет "после возврата" не позволяет изменять возвращаемое значение вызова метода, можно сгенерировать исключение, которое будет передано вверх по стеку вместо возвращаемого значения.
void afterReturning(Object returnValue, Method method, Object[] args,Object target) throws Throwble
AfterAdvice
Совет "после возврата" выполняется только в случае нормального завершения метода, снабженного советом. Однако совет "после" (after(finally)) будет выполняться вне зависимости от результата метода, снабженного этим советом.
Methodinterceptor
В Spring совет "вокруг" (around) моделируется с использованием стандарта Альянса АОП для nерехватчика метода.
Интерфейс Methodinterceptor - это стандартный интерфейс Альянса АОП для реализации совета "вокруг" для точек соединения вызовов методов. Object invoke(Methodinvocation invocation) throws Throwable
ThrowsAdvice
Совет "перехват" (throws) выполняется после возврата из вызова метода, но только в случае, если во время вызова было сгенерировано исключение.
Первый метод afterThrowing () в классе принимает единственный аргумент типа Exception. В нем можно указывать любой тип исключения, и этот метод идеально подходит, когда вас не интересует метод, сгенерировавший исключение, или переданные ему аргументы.
void afterThrowing(Exception1 ех) throws Throwable
Во втором методе afterThrowing () мы объявили четыре аргумента для указания метода, сгенерировавшего исключение, аргументов, переданных этому методу, и цели вызова метода. Порядок следования аргументов в этом методе важен, и они должны быть указаны все четыре.
void afterThrowing(Method method, Object[] args, Object target, Exception1 ех) throws Throwable
Exception1 - это конкретный тип исключения и все его подтипы для перехвата.
Spring использует метод, сигнатура которого в наибольшей степени соответствует типу исключения.
В ситуации, когда совет "перехват" имеет дело с двумя методами afterThrowing(), причем оба объявлены с тем самым типом Exception, но один принимает единственный аргумент, а другой - четыре аргумента, платформа Spring вызывает метод afterThrowing() с четырьмя аргументами.
IntroductionInterceptor
Платформа Spring моделирует "введения" (introduction) как специальные типы перехватчиков. Используя перехватчик введения, можно указать реализацию методов, которые должны быть введены советом
Pointcut
public interface Pointcut { ClassFilter getClassFilter (); Method Мatcher getMethodМatcher(); }
В версии Spring 4.0 предлагаются восемь реализаций интерфейса Pointcut:
AnnotationМatchingPointcut - Срез, который ищет специфическую Jаvа аннотацию в классе или методе.
AspectJExpressionPointcut - Срез, который использует средство связывания AspectJ для оценки выражения среза, представлен ного с помощью синтаксиса AspectJ
ComposablePointcut - применяется для объединения двух и более срезов с помощью таких операций, как union() и intersection()
ControlFlowPointcut - срез, предназначенный для специального случая, который соответствует всем методам в потоке управления другого метода - т.е . любому методу, который вызван прямо или косвенно в результате выполнения другого метода
DynamicMethodМatcherPointcut - служит базовым классом для построения динамических срезов
JdkRegexpMethodPointcut - позволяет определять срезы с использованием подцержки регулярных выражений JDK 1.4
NameMatchMethodPointcut - срез, который выполняет простое сопоставление со списком имен методов
StaticMethodМatcherPointcut - служит базовым классом для построения статических срезов
DefaultPointcutAdvisor
Класс DefaultPointcutAdvisor - это просто PointcutAdvisor для связывания одного Pointcut с одним Advice.
ClassFilter
boolean matches(Class<?> clazz);
MethodМatcher
public interface MethodМatcher { boolean matches(Method m, Class<?> targetClass); boolean isRuntime(); boolean matches(Method m, Class<?> targetClass, Object[J args); }
Перед использованием MethodMatcher платформа Spring вызывает isRuntime() для выяснения, является ли MethodМatcher статическим, на что указывает возвращенное значение false, или же динамическим, что отражается значением true.
Для статического среза Spring вызывает метод matches(Method, Class<T>) интерфейса MethodMatcher по одному разу для каждого метода целевого объекта, кешируя возвращаемое значение для послед у ющих обращений к этому методу.
Для динамических в дополнении в первому вызову с результатом true платформа Spring проводит дальнейшую проверку для каждого вызова метода, используя matches(Method, Class<T>, Obj ect[]).
АОП с аннотациями
Включение АОП с аннотациями в XML
<aop:aspectj-autoproxy/>
имеет атрибут proxy-target-class. По умолчанию он установлен в false, а это означает, что Spring будет создавать стандартные прокси, основанные на интерфейсах, с использованием динамического прокси JDK. В случае установки proxy-target-class в true платформа Spring будет применять библиотеку CGLIВ для создания прокси, которые основаны на классах .
@Aspect
Применяется к классу совместно с @Component, который будет советом, объявляя его классом аспекта.
@Pointcut
Примеры:
@Pointcut("execution(* com..foo*(int)) && args(intValue)") @Pointcut ( "bean (myDependency*) ")
@Before
Определяет метод совета перед.
@Before("fooExecution(intValue) && inMyDependency()")
@Around
Определяет метод совета вокруг.
@Around("fooExecution(intValue) && inMyDependency()")
JDBC
Настройка конфигурации jdbc в XML:
xmlns:jdbc="http://www.springframework.org/schema/jdbc" xsi:schemaLocation="http://www.springframework.org/schema/jdЬc http://www.springframework.org/schema/jdbc/spring-jdЬc.xsd"
JdbcTemplate
JdbcTemplate - универсальный класс для работы с запросами, отображения из таблиц в коллекции и наоборот.
JdbcDaoSupport
Позволяет упростить формирование DAO формируя ссылку на JdbcTemplate.
DataSource
Предоставляет и управляет набором реализаций Connection. Реализация: DriverManagerDataSource Пример конфигурации:
<bean id = "dataSource" class = "org.springframework.jdЬc.datasource.DriverManagerDataSource" p:driverClassName="${jdЬc.driverClassName}" p:url="$ { jdbc. url}" p:username = "${jdЬc.username}" p:password = "${jdbc.password}"/> <context:property-placeholder location = "classpath:META-INF/config/jdbc.properties"/>
jdbc.properties:
jdbc.driverClassName=com.mysql.jdЬc.Driver jdbc.url = jdbc:mysql://localhost:3306/prospring4 сhб jdbc.username = prospring4 jdЬc.password=prospring4
JNDI до версии 2.5:
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean" p:jndiName = "java:comp/env/jdbc/prospring4ch6"/>
JNDI с версии 2.5:
<beans xmlns = "http://www.springframework.org/schema/beans" xmlns:xsi = "http://www.wЗ.org/2001/XMLSchema-instance" xmlns:jee = "http://www.springframework.org/schema/jee"300 xsi:schemaLocation = "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd"> <jee:jndi-lookup jndi-name = "java:comp/env/jdЬc/prospring4ch6"/> </beans>
Ссыпка на ресурс в файле описателя приложения:
<root-node> <resource-ref> <res-ref-name>jdbc/prospring4ch6</res-ref-name> <res-type>javax.sql.DataSource</res-type> <res-auth>Container</res-auth> </resource-ref> </root-node>
Например, он становится <web-app> в описателе веб-развертывания (WEB-INF /web. xrnl), если приложение представляет собой веб-модуль.
NamedParameterJdbcTemplate
Пример применения именованных запросов:
private NamedParameterJdbcTemplate namedParameterJdbcTemplate; ... { String sql = "select last_name from contact where id = :contactId"; Map<String, Object> namedParameters = new HashMap<String, Object>(); namedParameters.put("contactId", id); return namedParameterJdbcTemplate.queryForObject(sql, namedParameters, String.class); }
RowМapper<T>
Интерфейс для простого способа отображения результирующего набора JDBC на объекты POJO.
private static final class ContactMapper implements RowMapper<Contact> { public Contact mapRow(ResultSet rs, int rowNum) throws SQLException { Contact contact = new Contact(); contact.setid(rs.getLong("id")); contact.setFirstName(rs.getString("first_name")); contact.setLastName(rs.getString("last_name") ); contact.setBirthDate(rs.getDate("Ьirth_date") ); return contact; } }
Объявление класса ContactMapper как статического внутреннего класса позволяет совместно использовать RowMapper<T> множеством методов поиска.
Использование в DAO
String sql = "select id, first_ name, last_ name, Ьirth_date from contact"; return namedParameterJdЬcTemplate.query(sql, new ContactMapper());
При работе с Java 8 вместо создания класса ContactMapper, как было показано ранее, можно применить лямбда-выражение:
@Override
public List<Contact> findAll() { String sql = "select id, first_name, last_name, Ьirth date from contact"; return namedParameterJdbcTemplate.query(sql, (rs, rowNum) -> { Contact contact = new Contact(); contact.setid(rs.getLong("id")); contact.setFirstName(rs.getString("first_name")); contact.setLastName(rs.getString("last_name")); contact.setBirthDate(rs.getDate("Ьirth_date")); return contact; }); }
такое возможно из-за того, что в интерфейсе RowМapper описан 1 метод с 2 параметрами ResultSet rs, int rowNum.
RowMapper<T> подходит только для отображения строки на одиночный объект предметной области.
ResultSetExtractor
Для получения связанных объектов реализуем метод extractData() для трансформации результирующего набора в список объектов.
public List<?> extractData(ResultSet rs) throws SQLException,DataAccessException
или лямба выражение
return namedParameterJdbcTemplate.query(sql, (ResultSet rs) -> ( ... return ArrayList ...; });
jdbc embedded
Пример встроенной БД:
<jdbc:emЬedded-database id="dataSource" type="H2"> <jdbc:script location="classpath:META-INF/sql/schema.sql"/> <jdbc:script location="classpath:META-INF/sql/test-data.sql"/> </jdЬc:emЬedded-database>
Важен порядок следования:
1. Схема (DDL (Data Definition Language)) - schema.sql,
2. данные (DML (Data Manipulation Language) - test-data.sql.
В атрибуте type задается тип используемой встроенной базы данных. В версии Spring 4.0 поддерживаются типы HSQL (стандартный), Н2 и DERBY.
Вместо указания type и embedded-database просто используйте initialize-database, и сценарии будут выполняться в отношении заданного источника данных, как если бы речь шла о встроенной базе данных.