Салам! JavaRush администрациясы жаңы деңгээлде иштеп жатканда, мен Жазгы алHow боюнча бир катар окуу макалаларын баштагым келет. Ооба, мен Интернетте бул тема боюнча көптөгөн материалдар бар экенин билем, бирок практика көрсөткөндөй, алардын баары Hello World деңгээлинде. Мен annotationларды кантип туура жайгаштыруу керектиги жөнүндө эмес, мунун баары "капчыктын астында" кантип иштегени жөнүндө айткым келет. Макала буга чейин тигил же бул алHow менен иштеген жана негизги түшүнүктөр менен тааныш болгондор үчүн арналган.
Контекстти баштоо.
Ошентип, келгиле, негизгилерден баштайлы. Менин оюмча, эң маанилүү пункттардын бири - бул контекст кантип түзүлүп, буурчак инициализацияланганын түшүнүү. Белгилүү болгондой, Жаз иштей баштаганга чейин, аны конфигурациялоо керек. Антедилювия доорунда бул xml файлдарын колдонуу менен жасалган (айрым долбоорлордо, негизинен эски долбоорлордо, алар ушул күнгө чейин жасай беришет). Мына ушундай конфигурация файлынын кичинекей мисалы:<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="helloWorld" class="ru.javarush.HelloWorld">
<property name="message" value="Hello World!"/>
</bean>
</beans>
Жалпысынан алганда, бул бир нече контроллерди түзүү жана стартапты ишке киргизүү үчүн жетиштүү (ал ишке ашпайт). Бирок бул конфигурация Жазды кантип ишке ашырат? Жана бул жерде нерселер кызыктуу болот. Биздин конфигурация Жазга түшүнүктүү болушу үчүн, бар XmlBeanDefinitionReader
. Бул ички Spring компоненти, ал xml сканерлейт (талдашат) жана биз ал жерде жазгандардын негизинде BeanDefinition
түзүүчү . BeanDefinition
буурчак жөнүндө маалыматты сактоочу an object болуп саналат. Буга төмөнкүлөр кирет: ал (буурчак) кайсы класстан түзүлүшү керек; чөйрөсү; жалкоо инициализация орнотулганбы; Бул буурчактын алдында xmlде сүрөттөлгөн башка жана башка касиеттерди инициализациялоо керекпи. Бардык кабыл алынгандар BeanDefinition
кошулат HashMap
, мында идентификатор буурчактын аты (сиз койгон же Жаз тарабынан дайындалган) жана BeanDefinition
an objectтин өзү. Баары BeanDefinition
жаралгандан кийин сахнага жаңы баатыр чыгат - BeanFactory
. Бул an object HashMap’e
s үстүнөн кайталанат BeanDefinition
, алардын негизинде буурчактарды түзөт жана аларды IoC контейнерине салат. Бул жерде бир нюанс бар, чындыгында, тиркеме башталганда, IoC контейнеринде Singleton масштабы бар буурчак болот (демейки боюнча коюлган), ал эми калгандары керек болгондо түзүлөт (прототип, сурам, сессия). Ал эми азыр кичине чегинүү, дагы бир каарман менен таанышалы.
BeanPostProcessor менен таанышыңыз. (BPP)
Чындыгында, буурчак сиздин колдонмоңуз үчүн бизнес логикасынын классы эмес. Төө буурчак инфраструктуралык буурчак деп да аталат. Кыскача айтканда, инфраструктуралык буурчак - бул сиздин бизнес логикалык буурчактарды конфигурациялаган класс (ооба, өтө көп буурчак). Мен төмөндө бул жөнүндө кененирээк айтып берем, бирок BPP эмнени конфигурациялай турганын бир аз айкыныраак кылуу үчүн, мен бир мисал келтирейин. Баардыгы кыскача маалымат менен таанышпы@Autowired
? Ошентип, сиз AutowiredAnnotationBeanPostProcessor
бардык класстарыңыздын бири-бирине камтылганын камсыз кылуу үчүн жооптуусуз.
Келгиле, BeanFactoryге кайтып баралы
HashMap
BPP жөнүндө азыр бorп туруп, 's итерациялоодо , BeanDefinition
баары адегенде түзүлүп, өзүнчө жайгаштырылат (IoC контейнеринде эмес) BeanPostProcessor
. Андан кийин, биздин бизнес логикабыздын кадимки буурчактары түзүлүп, IoC контейнерине салынып, алардын конфигурациясы өзүнчө кийинкиге калтырылган BPPлерди колдоно баштайт. Мына ушундай болот, ар бир BPPдин 2 ыкмасы бар:
postProcessorBeforeInitialization(Object bean, String beanName);
postProcessorAfterInitialization(Object bean, String beanName);
Биздин урналарды эки жолу кайталайт. Биринчи жолу ыкма postProcessorBeforeInitialization
, экинчи жолу ыкма деп аталат postProcessorAfterInitialization
. Албетте, эки ыкма эмне үчүн керек деген суроо пайда болду, мен түшүндүрүп берейин. Чындыгында, кээ бир annotationларды иштетүү үчүн (мисалы @Transactional
, ) биздин буурчак прокси класс менен алмаштырылат. Бул эмне үчүн жасалганын түшүнүү үчүн, анын кантип иштээрин бorшиңиз керек @Transactional
жана бул кандай иштейт. Сиз тез арада бул annotation менен белгиленген ыкмага дагы бир нече code саптарын кошушуңуз керек. Муну кандай жасаш керек? Туура, прокси класс түзүү менен, анын ичинде керектүү code талап кылынган методго кошулат. Эми бул жагдайды элестетиңиз, бизде класс бар:
class A {
@Autowired
private SomeClass someClass;
@Transactional
public void method() {
// модификатор доступа обязательно public
}
}
Бул класста 2 annotation @Autowired
жана @Transactional
. Эки annotation тең ар кандай BPP тарабынан иштетилет. Эгерде ал биринчи иштесе AutowiredBPP
, анда баары жакшы болот, бирок жок болсо, анда биз бул көйгөйгө туш болобуз. Прокси класс түзүлгөндө, бардык мета маалымат жоголот. @Autowired
Башкача айтканда, прокси классында annotation жөнүндө маалымат болбойт , ошондуктан AutowiredBPP
ал иштебейт, демек биздин талаа NPEге алып келет деген someClass
мааниге ээ болот . Метод чакырыктарынын ортосунда, эгерде бар болсо, -метод деп аталаарын null
да билүү керек . Бул негизинен экинчи конструктор, бирок айырмасы, учурда биздин баардык көз карандылыктарыбыз класска киргизилген жана биз аларга -методдон кире алабыз . Ошентип, дагы бир жолу контекстти инициализациялоо алгоритми: postProcessorBeforeInitialization
postProcessorAfterInitialization
init
init
XmlBeanDefinitionReader
биздин xml конфигурация файлыбызды сканерлейт.- түзөт
BeanDefinition
жана аларды киргизетHashMap
. - Келип
BeanFactory
, анданHashMap
өзүнчө бардык ' ларды кошотBeanPostProcessor
. - дан буурчак жаратат
BeanDefinition
жана аларды IoC контейнерине салат. - Бул жерде BPP келип, бул буурчактарды 2 ыкма менен конфигурациялайт.
- Даяр.
GO TO FULL VERSION