Spring internals quyidagilarni qamrab oladi: Bean lifecycle, BeanPostProcessor, BeanFactoryPostProcessor, @Conditional, auto-configuration, @Import, va bean scopelar.
1. Spring Internals nima?
Spring Internals - bu Spring ichkarida qanday ishlashini tushunish.
Boshlang'ich darajada biz odatda shuni bilamiz:
@Service
public class UserService {
}Spring buni avtomatik topadi, obyekt yaratadi va kerakli joyga inject qiladi.
O'rta darajada savol boshqacha bo‘ladi:
Spring bu classni qayerdan topdi?
Qachon obyekt yaratdi?
Qachon dependency inject qildi?
Qachon proxy yaratdi?
Qachon@Transactional,@Async,@Cacheableishlay boshladi?
Mana shu ichki mexanizmlar Spring Internals deyiladi.
2. Eng asosiy tushuncha: IoC Container
Springning yuragi - IoC Container.
IoC - Inversion of Control.
Oddiy Java’da obyektni o‘zingiz yaratamiz:
UserRepository repository = new UserRepository();
UserService service = new UserService(repository);Spring’da esa obyektlarni Spring yaratadi:
@Service
public class UserService {
private final UserRepository repository;
public UserService(UserRepository repository) {
this.repository = repository;
}
}Bu yerda biz new UserRepository() demadingiz. Spring o‘zi yaratdi va constructor orqali berdi.
Spring containerning vazifalari:
Vazifa | Ma’nosi |
|---|---|
Classlarni topish |
|
Bean yaratish | Obyektlarni o‘zi yaratadi |
Dependency injection | Kerakli dependencylarni ulaydi |
Lifecycle boshqarish | Init/destroy metodlarini ishlatadi |
Proxy yaratish |
|
3. Bean nima?
Bean - Spring container boshqarayotgan obyekt.
Masalan:
@Service
public class PaymentService {
}Bu oddiy Java class emas. Spring uni ko‘rib:
"Bu classni men boshqaraman"
deydi va undan bean yaratadi.
Yana bir misol:
@Configuration
public class AppConfig {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}Bu yerda RestTemplate ham Spring bean bo‘ladi.
4. Bean lifecycle nima?
Bean lifecycle - Spring bean yaratilganidan to yo‘q qilinishigacha bo‘lgan jarayon.
Soddalashtirilgan tartib:
1. Class topiladi
2. BeanDefinition yaratiladi
3. Bean obyekti yaratiladi
4. Dependency injection bo‘ladi
5. Aware interface’lar chaqiriladi
6. BeanPostProcessor oldingi bosqichi ishlaydi
7. Init method ishlaydi
8. BeanPostProcessor keyingi bosqichi ishlaydi
9. Bean tayyor bo‘ladi
10. App yopilganda destroy method ishlaydiKeling, buni tushunarliroq qilamiz.
5. BeanDefinition nima?
Spring avval beanni darrov yaratmaydi. Avval uning rejasini tuzadi.
Bu reja BeanDefinition deyiladi.
BeanDefinition ichida shunday ma’lumotlar bo‘ladi:
Ma’lumot | Misol |
|---|---|
Class nomi |
|
Scope |
|
Lazy yoki eager | darrov yaratiladimi yoki keyinmi |
Constructor argumentlar | qaysi dependencylar kerak |
Init method | qaysi metod ishga tushadi |
Destroy method | qaysi metod yopilishda ishlaydi |
Misol:
@Service
public class UserService {
}Spring buni scan qiladi va ichkarida taxminan shunday reja tuzadi:
beanName = "userService"
beanClass = UserService
scope = singleton
lazyInit = false6. Bean lifecycle oddiy misol
@Component
public class ReportService {
public ReportService() {
System.out.println("1. Constructor ishladi");
}
@PostConstruct
public void init() {
System.out.println("2. Init ishladi");
}
@PreDestroy
public void destroy() {
System.out.println("3. Destroy ishladi");
}
}Natija:
1. Constructor ishladi
2. Init ishladiApplication yopilganda:
3. Destroy ishladiBu nimani anglatadi?
constructor - obyekt yaratilayotgan payt.
@PostConstruct - dependencylar inject qilingandan keyin.
@PreDestroy - Spring container yopilayotganda.
7. Constructor va @PostConstruct farqi
Ko‘pchilik shu joyda adashadi.
Constructor
public ReportService(UserRepository repository) {
this.repository = repository;
}Constructor asosan:
majburiy dependencylarni olish uchun;
obyektni valid holatga keltirish uchun;
oddiy fieldlarni tayyorlash uchun.
@PostConstruct
@PostConstruct
public void init() {
// bean to‘liq tayyor bo‘lgandan keyingi ish
}@PostConstruct:
dependency injection tugagandan keyin ishlaydi;
Spring beanni yaratib bo‘lgandan keyin chaqiriladi;
og‘ir ishlar uchun emas.
Yomon amaliyot:
@PostConstruct
public void init() {
// DB dan 1 million data o‘qish
// tashqi API ga request yuborish
// katta cache warmup qilish
}Bu startupni sekinlashtiradi.
Yaxshi amaliyot:
@PostConstruct
public void validateConfig() {
if (apiKey == null || apiKey.isBlank()) {
throw new IllegalStateException("API key required");
}
}8. BeanPostProcessor nima?
BeanPostProcessor - bean yaratilgandan keyin unga aralashish imkonini beradigan mexanizm.
Spring ichida juda ko‘p narsalar aynan shu orqali ishlaydi.
Masalan:
@Autowired@PostConstructAOP proxy
@Async@Transactional@Cacheable
Soddalashtirilgan ko‘rinish:
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(
Object bean,
String beanName
) {
System.out.println("Before init: " + beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(
Object bean,
String beanName
) {
System.out.println("After init: " + beanName);
return bean;
}
}Bu har bir bean uchun ishlaydi.
9. BeanPostProcessor qayerda ishlatiladi?
Masalan, bizda shunday service bor:
@Service
public class OrderService {
@Transactional
public void createOrder() {
// order yaratish
}
}Spring OrderServiceni oddiy obyekt sifatida ishlatib qo‘ymaydi. Unga proxy o‘raydi.
Taxminan:
OrderService original bean
↓
Transactional proxy
↓
Application ishlatadigan beanShuning uchun @Transactional ishlaydi.
Ya’ni biz chaqiramiz:
orderService.createOrder();Lekin real chaqiruv:
Proxy → transaction start → method → transaction commit/rollbackMana shu proxy yaratish jarayonlarida BeanPostProcessor muhim rol o‘ynaydi.
10. BeanFactoryPostProcessor nima?
BeanPostProcessor bean obyektiga ta’sir qiladi.
BeanFactoryPostProcessor esa bean yaratilishidan oldin, BeanDefinitionlarga ta’sir qiladi.
Farqi:
Mexanizm | Qachon ishlaydi? | Nimaga ta’sir qiladi? |
|---|---|---|
BeanFactoryPostProcessor | Bean yaratilishidan oldin | BeanDefinition |
BeanPostProcessor | Bean yaratilgandan keyin | Bean obyekti |
Misol:
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(
ConfigurableListableBeanFactory beanFactory
) {
System.out.println("Bean definitions count: "
+ beanFactory.getBeanDefinitionCount());
}
}Bu kod beanlar yaratilishidan oldin ishlaydi.
11. @Conditional nima?
@Conditional - ma’lum shart bajarilsagina bean yaratish mexanizmi.
Masalan:
@Bean
@ConditionalOnProperty(
name = "payment.provider",
havingValue = "stripe"
)
public PaymentService stripePaymentService() {
return new StripePaymentService();
}Agar configda shunday bo‘lsa:
payment:
provider: stripeSpring StripePaymentService beanini yaratadi.
Agar:
payment:
provider: clickbo‘lsa, bu bean yaratilmaydi.
12. Spring Boot auto-configuration nima?
Spring Bootning eng kuchli joyi - auto-configuration.
Biz dependency qo‘shamiz:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>Spring Boot shuni ko‘radi va o‘zi taxmin qiladi:
"Demak bu project JPA ishlatyapti. Men EntityManager, DataSource, TransactionManager kerak bo‘lishini bilaman."
Keyin kerakli beanlarni avtomatik yaratadi.
Lekin bu sehr emas. Ichkarida shartlar bor:
@ConditionalOnClass(DataSource.class)
@ConditionalOnMissingBean(DataSource.class)Ma’nosi:
Agar classpathda DataSource bo‘lsa
va user o‘zi DataSource bean yaratmagan bo‘lsa,
Spring Boot default DataSource yaratadi.13. @ConditionalOnMissingBean juda muhim
Bu Spring Boot auto-configurationning asosiy g‘oyasi.
Masalan Spring Boot default ObjectMapper yaratadi.
Lekin biz o‘zinmiz bersak:
@Bean
public ObjectMapper objectMapper() {
return new ObjectMapper()
.findAndRegisterModules();
}Spring Boot aytadi:
"User o‘zi ObjectMapper berdi. Men defaultini yaratmayman."
Shu sabab Spring Boot moslashuvchan.
14. Auto-configuration eski va yangi mexanizmi
Oldin Spring Boot auto-config classlar odatda bu faylda ko‘rsatilardi:
META-INF/spring.factoriesYangi Spring Boot versiyalarida esa:
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.importsO'rta darajada buni bilish muhim, chunki custom starter yozganda kerak bo‘ladi.
15. @Import nima?
@Import - boshqa configuration classni Spring contextga qo‘shish.
Misol:
@Configuration
public class SecurityConfig {
}Buni boshqa joyda import qilish:
@Configuration
@Import(SecurityConfig.class)
public class AppConfig {
}Endi SecurityConfig ichidagi beanlar ham contextga qo‘shiladi.
@Import ko‘pincha:
custom configuration ulashda;
starter yozishda;
framework ichki mexanizmlarida;
modular configlarda ishlatiladi.
16. Bean scope nima?
Scope - bean qancha vaqt yashashini belgilaydi.
Eng ko‘p ishlatiladiganlari:
Scope | Ma’nosi |
|---|---|
singleton | bitta bean, butun app bo‘yicha umumiy |
prototype | har safar yangi obyekt |
request | har HTTP request uchun alohida |
session | har user session uchun alohida |
application | servlet context bo‘yicha bitta |
Default scope - singleton.
17. Singleton scope
@Service
public class UserService {
}Bu default holatda singleton.
Ya’ni Spring bitta UserService obyekt yaratadi va hamma joyda shuni ishlatadi.
Controller A ─┐
Controller B ─┼──> same UserService object
Controller C ─┘Shuning uchun singleton beanda mutable state saqlash xavfli.
Yomon:
@Service
public class OrderService {
private Long currentUserId;
public void createOrder(Long userId) {
this.currentUserId = userId;
}
}Bu productionda bug beradi, chunki bir vaqtning o‘zida ko‘p request keladi.
Yaxshi:
@Service
public class OrderService {
public void createOrder(Long userId) {
// userId local variable sifatida ishlatiladi
}
}18. Prototype scope
@Component
@Scope("prototype")
public class ReportBuilder {
}Har safar so‘ralganda yangi obyekt yaratiladi.
ReportBuilder builder1 = context.getBean(ReportBuilder.class);
ReportBuilder builder2 = context.getBean(ReportBuilder.class);Bu yerda:
builder1 != builder2Lekin muhim joy bor.
Agar prototype bean singleton ichiga inject qilinsa:
@Service
public class ReportService {
private final ReportBuilder reportBuilder;
public ReportService(ReportBuilder reportBuilder) {
this.reportBuilder = reportBuilder;
}
}ReportService singleton bo‘lgani uchun ReportBuilder ham faqat bir marta inject bo‘ladi.
Har safar yangi prototype olish uchun ObjectProvider ishlatiladi:
@Service
public class ReportService {
private final ObjectProvider<ReportBuilder> builderProvider;
public ReportService(ObjectProvider<ReportBuilder> builderProvider) {
this.builderProvider = builderProvider;
}
public void generate() {
ReportBuilder builder = builderProvider.getObject();
}
}19. Request scope
Har HTTP request uchun alohida bean.
@Component
@RequestScope
public class RequestContext {
private String requestId;
public String getRequestId() {
return requestId;
}
public void setRequestId(String requestId) {
this.requestId = requestId;
}
}Bu web applicationlarda foydali:
request id;
user context;
tenant id;
request-specific data.
Lekin ehtiyot bo‘lish kerak. Hamma narsani request scope qilish noto‘g‘ri. Ko‘pincha ThreadLocal, filter, interceptor yoki security context yaxshiroq bo‘ladi.
20. Spring application start bo‘lish jarayoni
Soddalashtirilgan ketma-ketlik:
SpringApplication.run(App.class, args);Ichkarida taxminan:
1. SpringApplication yaratiladi
2. Environment tayyorlanadi
3. ApplicationContext yaratiladi
4. BeanDefinitionlar yuklanadi
5. BeanFactoryPostProcessorlar ishlaydi
6. Singleton beanlar yaratiladi
7. BeanPostProcessorlar ishlaydi
8. Embedded server start bo‘ladi
9. ApplicationReadyEvent chiqadiShuning uchun @PostConstruct paytida application hali to‘liq tayyor bo‘lmasligi mumkin.
Agar app to‘liq ishga tushgandan keyin nimadir qilish kerak bo‘lsa, ko‘pincha bu yaxshiroq:
@Component
public class StartupRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) {
System.out.println("Application started");
}
}Yoki:
@Component
public class ReadyListener {
@EventListener(ApplicationReadyEvent.class)
public void onReady() {
System.out.println("Application is fully ready");
}
}21. Spring Internals real hayotda nimaga kerak?
1. @Transactional nega ishlamayotganini tushunish uchun
Masalan:
@Service
public class UserService {
public void create() {
saveUser();
}
@Transactional
public void saveUser() {
// DB save
}
}Bu yerda @Transactional ishlamasligi mumkin.
Sabab: self-invocation.
create() ichidan saveUser() chaqirilganda proxy chetlab o‘tiladi.
To‘g‘ri yechimlardan biri:
@Service
public class UserFacade {
private final UserService userService;
public UserFacade(UserService userService) {
this.userService = userService;
}
public void create() {
userService.saveUser();
}
}@Service
public class UserService {
@Transactional
public void saveUser() {
// DB save
}
}2. Bean circular dependency muammosini tushunish uchun
Yomon:
@Service
public class AService {
public AService(BService bService) {}
}
@Service
public class BService {
public BService(AService aService) {}
}Bu circular dependency.
AService BServicega muhtoj
BService AServicega muhtojYaxshi yechim - responsibilityni ajratish:
@Service
public class CommonService {
}Yoki arxitekturani qayta ko‘rib chiqish.
3. Startup sekinligini topish uchun
Agar app sekin start bo‘lsa, sabablar:
juda ko‘p eager singleton bean;
@PostConstructichida og‘ir ish;DB/API calllar startupda bajarilishi;
noto‘g‘ri auto-configuration;
classpathda keraksiz starterlar.
22. Java developer bilishi kerak bo‘lgan xulosa
Java Spring developer faqat annotation ishlatmaydi. U annotation ortida nima bo‘layotganini tushunadi.
Mavzu | O'rta darajada bilish kerak bo‘lgan narsa |
|---|---|
Bean lifecycle | Bean qachon yaratiladi, qachon init/destroy bo‘ladi |
BeanPostProcessor | Bean yaratilgandan keyin unga qanday ishlov beriladi |
BeanFactoryPostProcessor | BeanDefinitionlarga qanday ta’sir qilinadi |
@Conditional | Bean shart asosida qanday yaratiladi |
Auto-configuration | Spring Boot default beanlarni qanday qo‘shadi |
@Import | Configurationlarni qanday ulaydi |
Scope | Singleton/prototype/request farqlari |
Proxy |
|
23. Interview savollar
Savol 1: Bean lifecycle qanday?
Javob:
Spring avval classlarni scan qiladi, BeanDefinition yaratadi, keyin bean obyektini yaratadi, dependency injection qiladi, BeanPostProcessorlarni ishlatadi, init methodlarni chaqiradi va bean tayyor bo‘ladi. Application yopilganda destroy callbacklar ishlaydi.
Savol 2: BeanPostProcessor va BeanFactoryPostProcessor farqi nima?
Javob:
BeanFactoryPostProcessor bean yaratilishidan oldin BeanDefinition bilan ishlaydi. BeanPostProcessor esa bean yaratilgandan keyin real obyekt bilan ishlaydi.
Savol 3: @Transactional nega ba’zida ishlamaydi?
Javob:
Chunki Spring
@Transactionalni proxy orqali ishlatadi. Agar method shu class ichidan o‘zini o‘zi chaqirsa, proxy chetlab o‘tiladi va transaction ochilmaydi.
Savol 4: Singleton beanda fieldda request data saqlash mumkinmi?
Javob:
Yo‘q. Singleton bean barcha requestlar uchun bitta obyekt bo‘ladi. Mutable fieldlar race condition va noto‘g‘ri data muammosiga olib keladi.
Savol 5: Auto-configuration qanday ishlaydi?
Javob:
Spring Boot classpath, property va mavjud beanlarga qarab shartli configurationlarni ishga tushiradi. Masalan
@ConditionalOnClass,@ConditionalOnMissingBean,@ConditionalOnPropertyorqali kerakli default beanlarni yaratadi.
24. Amaliy mini-topshiriq
Quyidagi kichik projectda sinab ko‘ring:
@Component
public class DemoBean {
public DemoBean() {
System.out.println("Constructor");
}
@PostConstruct
public void init() {
System.out.println("PostConstruct");
}
@PreDestroy
public void destroy() {
System.out.println("PreDestroy");
}
}Keyin BeanPostProcessor qo‘shing:
@Component
public class LoggingBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
if (beanName.equals("demoBean")) {
System.out.println("Before init: " + beanName);
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (beanName.equals("demoBean")) {
System.out.println("After init: " + beanName);
}
return bean;
}
}Taxminiy natija:
Constructor
Before init: demoBean
PostConstruct
After init: demoBeanBu Spring lifecycle’ni ko‘z bilan ko‘rishga yordam beradi.