IoC & Dependency Injection
Bu bo‘limda Spring’ning eng asosiy "yuragi"ni tushunamiz: IoC va Dependency Injection. Bu mavzu ApplicationContext, BeanFactory, @Component, @Service, @Repository, @Controller, @Autowired, constructor injection va @Bean/@Configuration mavzularini o‘z ichiga oladi.
1. IoC nima?
IoC - Inversion of Control.
O‘zbekchasiga:
Boshqaruvni teskariga berish.
Oddiy Java’da obyektlarni o‘zing yaratarsak:
UserRepository repository = new UserRepository();
UserService service = new UserService(repository);
UserController controller = new UserController(service);Bu yerda hamma narsani dasturchi o‘zi boshqaryapti:
Kim yaratiladi?
Qachon yaratiladi?
Kimga ulanadi?
Qanday konfiguratsiya qilinadi?Spring’da esa bu ishlarni Spring bajaradi:
Object yaratadi
Objectlarni xotirada saqlaydi
Kerakli joyga inject qiladi
Lifecycle’ni boshqaradiShuning uchun bu IoC deyiladi.
2. Oddiy tushuncha bilan IoC
Tasavvur qil, restoran bor.
Oddiy Java’da:
Biz o‘zimiz oshxonaga kiramiz
O‘zimiz ovqat qilamiz
O‘zimiz stolga olib kelamiz
O‘zimiz idish yuvishimiz ham mumkinSpring’da:
Biz buyurtma beramiz
Restoran tizimi ovqatni tayyorlaydi
Ofitsiant olib keladi
Hammasi tartib bilan ishlaydiYa’ni biz har bir obyektni qo‘lda yaratib yurmaymiz. Spring bizga kerakli obyektni tayyorlab beradi.
3. Dependency nima?
Dependency - class ishlashi uchun kerak bo‘ladigan boshqa class.
Masalan:
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
}Bu yerda UserService ishlashi uchun UserRepository kerak.
Demak:
UserRepository - dependency
UserService - unga bog‘liq class4. Dependency Injection nima?
Dependency Injection - kerakli obyektni class ichiga tashqaridan berish.
Ya’ni class o‘zi obyekt yaratmaydi. Unga tayyor obyekt beriladi.
Yomonroq usul:
public class UserService {
private UserRepository userRepository = new UserRepository();
}Bu yerda UserService UserRepositoryni o‘zi yaratib oldi. Bu qattiq bog‘lanish - tight coupling.
Yaxshiroq usul:
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
}Bu yerda UserRepository tashqaridan beriladi. Bu Dependency Injection.
5. Spring’da Bean nima?
Spring boshqaradigan obyekt Bean deyiladi.
Masalan:
@Service
public class UserService {
}Spring bu classdan obyekt yaratadi va o‘z container’ida saqlaydi.
Oddiy qilib:
Class → loyiha kodi
Object → new orqali yaratilgan obyekt
Bean → Spring yaratgan va boshqaradigan obyekt6. Spring Container nima?
Spring Container - Spring Bean’larni saqlaydigan va boshqaradigan joy.
U quyidagilarni qiladi:
Bean yaratadi
Bean’larni bir-biriga ulaydi
Bean lifecycle’ni boshqaradi
Kerak bo‘lsa bean’ni destroy qiladiSpring container’ning asosiy turlari:
Turi | Vazifasi |
|---|---|
| Eng oddiy container |
| Kengaytirilgan container, Spring Boot’da ko‘p ishlatiladi |
Quyidagini eslab qoling:
Spring Boot’da asosan
ApplicationContextishlaydi. U bean’larni yaratadi, saqlaydi va kerakli joyga beradi.
7. ApplicationContext nima?
ApplicationContext - Spring ilovasining asosiy container’i.
Masalan, Spring Boot ishga tushganda:
SpringApplication.run(DemoApplication.class, args);shu joyda Spring application context yaratiladi.
Ichida quyidagi bean’lar bo‘lishi mumkin:
UserController
UserService
UserRepository
PasswordEncoder
ObjectMapper
DataSource
EntityManagerSpring ularni bir-biriga ulab beradi.
8. @Component nima?
@Component - classni Spring bean qilish uchun ishlatiladi.
@Component
public class SmsSender {
public void send(String phone, String message) {
System.out.println("SMS yuborildi");
}
}Bu classni Spring ko‘radi va container’ga qo‘shadi.
9. @Service, @Repository, @Controller farqi
Bular ham aslida @Componentning maxsus turlari.
Annotation | Qayerda ishlatiladi? | Vazifasi |
|---|---|---|
| Umumiy class | Oddiy Spring bean |
| Service layer | Biznes logika |
| Database layer | DB bilan ishlash |
| MVC controller | View qaytaradigan controller |
| REST API | JSON/text response qaytaradi |
Misol: to‘g‘ri layer structure
controller
└── UserController
service
└── UserService
repository
└── UserRepository10. @Service misol
@Service
public class UserService {
public String getUserName() {
return "Ali";
}
}Bu class biznes logika uchun ishlatiladi.
Masalan:
User yaratish
Userni tekshirish
Parolni encode qilish
Order hisoblash
Payment tekshirish11. @Repository misol
@Repository
public class UserRepository {
public String findUserNameById(Long id) {
return "Ali";
}
}Bu class database bilan ishlash uchun.
Haqiqiy loyihada ko‘pincha Spring Data JPA bilan bunday yoziladi:
public interface UserRepository extends JpaRepository<User, Long> {
}Lekin boshlanishiga class misoli tushunish uchun qulayroq.
12. @RestController misol
@RestController
@RequestMapping("/users")
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@GetMapping("/{id}")
public String getUser(@PathVariable Long id) {
return userService.getUserName(id);
}
}Bu controller HTTP request oladi.
Masalan:
GET /users/1va javob qaytaradi:
Ali13. To‘liq DI misol
Repository
@Repository
public class UserRepository {
public String findUserNameById(Long id) {
return "Ali";
}
}Service
@Service
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public String getUserName(Long id) {
return userRepository.findUserNameById(id);
}
}Controller
@RestController
@RequestMapping("/users")
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@GetMapping("/{id}")
public String getUser(@PathVariable Long id) {
return userService.getUserName(id);
}
}Bu yerda zanjir shunday:
UserController → UserService → UserRepositorySpring bularni o‘zi yaratadi va ulaydi.
14. @Autowired nima?
@Autowired - Spring’dan dependency so‘rash uchun ishlatiladi.
Ya’ni:
Shu classga kerakli bean’ni Spring container’dan olib ber.
Spring’da injection qilishning 3 xil usuli bor:
Field injection
Constructor injection
Setter injection15. Field Injection
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
}Bu ishlaydi, lekin professional loyihalarda tavsiya qilinmaydi.
Sabablari:
Testing qiyinroq
final ishlatib bo‘lmaydi
Dependency yashirin bo‘lib qoladi
Class nimaga bog‘liq ekanini constructor’dan ko‘rib bo‘lmaydi16. Constructor Injection
Eng tavsiya qilinadigan usul:
@Service
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
}Afzalliklari:
Dependency aniq ko‘rinadi
final ishlatish mumkin
Testing oson
Class obyekt yaratilganda dependency majburiy bo‘ladi
Null bo‘lib qolish ehtimoli kamayadiSpring Boot’da bitta constructor bo‘lsa, @Autowired yozish shart emas.
Ya’ni bu kod yetarli:
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}17. Setter Injection
@Service
public class UserService {
private UserRepository userRepository;
@Autowired
public void setUserRepository(UserRepository userRepository) {
this.userRepository = userRepository;
}
}Bu optional dependency bo‘lsa ishlatilishi mumkin.
Lekin odatda constructor injection yaxshiroq.
18. Qaysi injection usulini ishlatish kerak?
Injection turi | Tavsiya |
|---|---|
Field injection | Ishlaydi, lekin tavsiya qilinmaydi |
Setter injection | Optional dependency uchun |
Constructor injection | Eng yaxshi va professional usul |
Asosiy qoida:
Majburiy dependency bo‘lsa - constructor injection ishlat.
19. @Bean nima?
Ba’zan classni o‘zing yozmagansan, lekin uni Spring bean qilish kerak bo‘ladi.
Masalan:
@Bean
public ObjectMapper objectMapper() {
return new ObjectMapper();
}@Bean method qaytargan obyektni Spring container’ga qo‘shadi.
20. @Configuration nima?
@Configuration - bean’lar e’lon qilinadigan configuration class.
@Configuration
public class AppConfig {
@Bean
public SmsSender smsSender() {
return new SmsSender();
}
}Bu yerda smsSender() qaytargan obyekt Spring bean bo‘ladi.
21. @Component vs @Bean
Holat | Nima ishlatamiz? |
|---|---|
Class o‘zimizniki bo‘lsa |
|
Class tashqi library’dan bo‘lsa |
|
Murakkab yaratish logikasi kerak bo‘lsa |
|
Oddiy service class bo‘lsa |
|
Misol:
@Service
public class UserService {
}Bu o‘zimiz yozgan class.
Lekin:
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}Bu tashqi classni bean qilishga o‘xshaydi.
22. Real loyiha misoli
Tasavvur qil: online do‘kon backend.
OrderController
OrderService
PaymentService
OrderRepositoryOrderService quyidagilarga bog‘liq:
OrderRepository
PaymentService
SmsSenderKod:
@Service
public class OrderService {
private final OrderRepository orderRepository;
private final PaymentService paymentService;
private final SmsSender smsSender;
public OrderService(
OrderRepository orderRepository,
PaymentService paymentService,
SmsSender smsSender
) {
this.orderRepository = orderRepository;
this.paymentService = paymentService;
this.smsSender = smsSender;
}
public void createOrder() {
paymentService.pay();
orderRepository.save();
smsSender.send();
}
}Bu yerda OrderService hammasini o‘zi yaratmaydi. Spring tayyor bean’larni olib constructor orqali beradi.
23. Eng ko‘p uchraydigan xato
Xato:
@Service
public class UserService {
private UserRepository userRepository = new UserRepository();
}Nega yomon?
Spring container chetlab o‘tildi
Testing qiyinlashadi
Interface bilan ishlash qiyin
Mock qilish qiyin
Tight coupling paydo bo‘ladiTo‘g‘ri:
@Service
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
}24. No qualifying bean xatosi
Ba’zida bunday xato chiqadi:
No qualifying bean of type 'UserRepository' availableBu nimani anglatadi?
Spring UserRepository bean’ini topa olmadi.
Sabablari:
@Repository yozilmagan
@Component yozilmagan
Class Spring scan qilmaydigan package’da turibdi
Interface implementation yo‘q
@Bean qilib e’lon qilinmagan25. ComponentScan qanday ishlaydi?
Spring Boot asosiy class turgan package’dan boshlab pastga qarab classlarni qidiradi.
Masalan:
uz.jtscorp.demo
├── DemoApplication.java
├── controller
├── service
└── repositoryBu yaxshi.
Lekin bunday bo‘lsa:
uz.jtscorp.demo
└── DemoApplication.java
uz.other.service
└── UserService.javaSpring uz.other.serviceni ko‘rmasligi mumkin.
Shuning uchun asosiy classni yuqori package’da saqlash kerak.
26. IoC va DI farqi
Tushuncha | Ma’nosi |
|---|---|
IoC | Object boshqaruvini Spring’ga berish |
DI | Kerakli dependency’ni class ichiga berish |
Oddiyroq:
IoC - umumiy prinsip
DI - shu prinsipni amalga oshirish usuliYa’ni DI - IoC’ning eng mashhur ko‘rinishi.
27. Interview savol-javob
Savol:
IoC nima?
Javob:
IoC - Inversion of Control. Ya’ni obyektlarni yaratish va boshqarish vazifasi dasturchidan Spring container’ga o‘tadi. Spring bean’larni yaratadi, saqlaydi va kerakli joyga ulaydi.
Savol:
Dependency Injection nima?
Javob:
Dependency Injection - classga kerakli obyektlarni tashqaridan berish usuli. Spring container kerakli bean’ni topib, constructor, setter yoki field orqali inject qiladi. Eng tavsiya qilinadigan usul constructor injection.
28. Java developer uchun xulosa
Bugungi mavzudan eng muhimlari:
IoC - boshqaruv Spring’ga beriladi
DI - kerakli object classga tashqaridan beriladi
Bean - Spring boshqaradigan object
ApplicationContext - bean’lar saqlanadigan container
@Component - oddiy bean
@Service - biznes logika bean
@Repository - database layer bean
@RestController - REST API controller
Constructor injection - eng yaxshi injection usuli
@Bean - method orqali bean yaratish
@Configuration - bean configuration class29. Amaliy mashq
Quyidagi endpointni yozib ko‘r:
GET /products/1Natija:
Product: MacBook ProStructure:
ProductController → ProductService → ProductRepositoryKod:
@Repository
public class ProductRepository {
public String findProductNameById(Long id) {
return "MacBook Pro";
}
}@Service
public class ProductService {
private final ProductRepository productRepository;
public ProductService(ProductRepository productRepository) {
this.productRepository = productRepository;
}
public String getProductName(Long id) {
return productRepository.findProductNameById(id);
}
}@RestController
@RequestMapping("/products")
public class ProductController {
private final ProductService productService;
public ProductController(ProductService productService) {
this.productService = productService;
}
@GetMapping("/{id}")
public String getProduct(@PathVariable Long id) {
return "Product: " + productService.getProductName(id);
}
}