Spring internals

01.07.2026 | Muallif: Jaxongir a.k.a | Kategoriya: Spring Boot | 19 daqiqa o'qish

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, @Cacheable ishlay 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

@Component, @Service, @Repositorylarni scan qiladi

Bean yaratish

Obyektlarni o‘zi yaratadi

Dependency injection

Kerakli dependencylarni ulaydi

Lifecycle boshqarish

Init/destroy metodlarini ishlatadi

Proxy yaratish

@Transactional, AOP, Security kabi mexanizmlar uchun


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 ishlaydi

Keling, 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

UserService.class

Scope

singleton

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 = false

6. 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 ishladi

Application yopilganda:

3. Destroy ishladi

Bu 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

  • @PostConstruct

  • AOP 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 bean

Shuning uchun @Transactional ishlaydi.

Ya’ni biz chaqiramiz:

orderService.createOrder();

Lekin real chaqiruv:

Proxy → transaction start → method → transaction commit/rollback

Mana 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: stripe

Spring StripePaymentService beanini yaratadi.

Agar:

payment:
  provider: click

bo‘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.factories

Yangi Spring Boot versiyalarida esa:

META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

O'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 != builder2

Lekin 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 chiqadi

Shuning 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 muhtoj

Yaxshi 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;

  • @PostConstruct ichida 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

@Transactional, AOP, cache qanday ishlaydi


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, @ConditionalOnProperty orqali 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: demoBean

Bu Spring lifecycle’ni ko‘z bilan ko‘rishga yordam beradi.