Сәлеметсіз бе! JavaRush әкімшілігі жаңа деңгейлерде жұмыс істеп жатқанда, мен Spring Framework бойынша оқу мақалалар сериясын бастағым келеді. Иә, мен Интернетте бұл тақырып бойынша көптеген материалдар бар екенін білемін, бірақ тәжірибе көрсеткендей, олардың барлығы Hello World деңгейінде. Мен annotationларды қалай дұрыс орналастыру керектігі туралы емес, оның бәрі «қапшық астында» қалай жұмыс істейтіні туралы айтқым келеді. Мақала осы немесе басқа жолмен осы құрылыммен жұмыс істеген және негізгі ұғымдармен таныс адамдарға арналған.
Мәтінмәнді инициализациялау.
Сонымен, негіздерден бастайық. Менің ойымша, ең маңызды сәттердің бірі - контекст қалай орнатылғанын және бұршақтардың инициализациясын түсіну. Өздеріңіз білетіндей, Spring жұмысын бастамас бұрын оны конфигурациялау керек. Антидилювиялық дәуірде бұл 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>
Жалпы алғанда, бұл бірнеше контроллер жасау және стартапты іске қосу үшін жеткілікті (ол көтерілмейді). Бірақ бұл конфигурация Spring жұмысын қалай жасайды? Міне, бәрі қызық болады. Біздің конфигурациямыз Көктемге түсінікті болуы үшін XmlBeanDefinitionReader
. Бұл xml файлын сканерлейтін (талдайтын) және біз жазғандар негізінде BeanDefinition
'с жасайтын ішкі Spring компоненті. BeanDefinition
бұршақ туралы ақпаратты сақтайтын an object болып табылады. Оған мыналар жатады: ол (бұршақ) қай кластан жасалуы керек; қолдану аясы; жалқау инициализация орнатылған ба; Осы бұршақтың алдында xml-де сипатталған басқа және басқа сипаттарды инициализациялау қажет пе. Барлық алынғандар идентификатор бұршақтың аты (сіз орнатқан немесе Spring тағайындаған) және нысанның өзі болып табылатын параметріне BeanDefinition
қосылады . Барлығы жасалғаннан кейін сахнада жаңа кейіпкер пайда болады - . Бұл нысан s арқылы қайталанады , олардың негізінде бұршақтар жасайды және оларды IoC контейнеріне салады. Мұнда бір нюанс бар, шын мәнінде, қолданба іске қосылғанда, IoC контейнерінде Singleton ауқымы бар бұршақтар болады (әдепкі бойынша орнатылған), ал қалғандары қажет болғанда жасалады (прототип, сұрау, сеанс). Ал енді кішігірім шегініс, тағы бір кейіпкермен танысайық. HashMap
BeanDefinition
BeanDefinition
BeanFactory
HashMap’e
BeanDefinition
BeanPostProcessor-мен танысыңыз. (BPP)
Факті мынада, бұршақ міндетті түрде қолданбаңыз үшін бизнес-логика класы емес. Бұршақты инфрақұрылымдық бұршақ деп те атайды. Қысқаша айтқанда, инфрақұрылымдық бұршақ бизнес логикалық бұршақтарды конфигурациялайтын сынып (иә, тым көп бұршақ). Мен сізге төменде бұл туралы толығырақ айтып беремін, бірақ BPP нақты не конфигурациялайтынын аздап түсіндіру үшін мысал келтіремін. Түйіндеме барлығына таныс па@Autowired
? Сонымен, сіз AutowiredAnnotationBeanPostProcessor
барлық сыныптарыңыздың бір-біріне енгізілгенін қамтамасыз етуге жауаптысыз.
BeanFactory-ге оралайық
HashMap
BPP туралы қазір біле отырып, қайталау кезінде барлық ' s BeanDefinition
алдымен жасалып, бөлек орналастырылатынын (IoC контейнерінде емес) нақтылау қажет BeanPostProcessor
. Осыдан кейін біздің бизнес логикамыздың кәдімгі бұршақтары жасалады, IoC контейнеріне салынады және олардың конфигурациясы бөлек кейінге қалдырылған BPP пайдалана бастайды. Бұл осылай болады, әр BPP-де 2 әдіс бар:
postProcessorBeforeInitialization(Object bean, String beanName);
postProcessorAfterInitialization(Object bean, String beanName);
Біздің жәшіктер арқылы екі рет қайталайды. Бірінші рет әдіс шақырылады postProcessorBeforeInitialization
, ал екінші рет әдіс шақырылады postProcessorAfterInitialization
. Әрине, екі әдіс не үшін қажет деген сұрақ туындады, түсіндірейін. Кейбір annotationларды өңдеу үшін (мысалы @Transactional
, мысалы) біздің бұршақ прокси класымен ауыстырылады. Мұның не үшін жасалғанын түсіну үшін оның қалай жұмыс істейтінін білу керек @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
. - 's бұршақтарын жасайды
BeanDefinition
және оларды IoC контейнеріне орналастырады. - Мұнда BPP келеді және бұл бұршақтарды 2 әдіс арқылы конфигурациялайды.
- Дайын.
GO TO FULL VERSION