Custom Spring extensions - Spring Boot’ni faqat ishlatish emas, balki uni o‘z loyihangiz yoki kompaniya platformangizga moslab kengaytirish demakdir.
Bu maqola quyidagilarni qamrab oladi: custom auto-configuration, custom starter, custom Actuator endpoint, custom annotation + AOP, ApplicationListener, SmartLifecycle.
1. Custom Spring extensions nima?
Oddiy developer Spring Boot’dan tayyor holda foydalanadi:
spring-boot-starter-web
spring-boot-starter-data-jpa
spring-boot-starter-securitySenior developer esa kerak bo‘lsa o‘zi ham shunday reusable extension yozadi:
company-security-starter
company-observability-starter
company-multitenancy-starter
company-kafka-starter
company-audit-starterMaqsad:
Bir xil config va boilerplate kodni har projectda qayta yozmaslik.Masalan, kompaniyada 20 ta microservice bor. Har birida quyidagilar kerak:
JWT security config
Tracing config
Audit logging
Tenant filter
Kafka error handler
Actuator custom endpoint
Common exception handlerBularni har service’da copy-paste qilish yomon. Yaxshiroq yechim:
company-platform-starter2. Qachon custom extension kerak?
Custom extension kerak bo‘ladi:
[+] Bir xil config 3+ projectda takrorlansa
[+] Platform team umumiy standart bermoqchi bo‘lsa
[+] Security/observability/kafka config markazlashtirilsa
[+] Internal library reusable bo‘lishi kerak bo‘lsa
[+] Teamlar bir xil convention bilan ishlashi kerak bo‘lsaKerak emas:
[-] Faqat bitta project uchun bo‘lsa
[-] Oddiy 2-3 ta bean uchun ortiqcha abstraction bo‘lsa
[-] Extension projectni tushunishni qiyinlashtirsa
[-] Team hali Spring internals’ni yaxshi bilmasaSenior qoida:
Abstraction foyda bersa yoziladi. Faqat "chiroyli ko‘rinsin" deb starter yozilmaydi.3. Custom auto-configuration
Auto-configuration nima?
Spring Boot auto-configuration classpath’dagi dependency va mavjud beanlarga qarab avtomatik config qiladi. Rasmiy hujjatda Spring Boot auto-configuration application’ni qo‘shilgan jar dependency’lar asosida avtomatik sozlashga urinishi aytiladi. (Home)
Masalan:
spring-boot-starter-data-jpa bor
↓
DataSource kerak
↓
Hibernate kerak
↓
JpaRepository kerak
↓
Spring Boot ko‘p config’ni o‘zi qiladiCustom auto-configuration ham xuddi shunday:
company-audit-starter dependency qo‘shildi
↓
AuditLogger bean avtomatik yaratildi
↓
AuditAspect avtomatik yoqildiOddiy custom auto-configuration misol
Tasavvur qilamiz, bizda audit logging library bor.
1. Properties class
package uz.company.audit;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "company.audit")
public class AuditProperties {
private boolean enabled = true;
private String applicationName = "unknown-service";
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public String getApplicationName() {
return applicationName;
}
public void setApplicationName(String applicationName) {
this.applicationName = applicationName;
}
}2. Audit service
package uz.company.audit;
public class AuditLogger {
private final AuditProperties properties;
public AuditLogger(AuditProperties properties) {
this.properties = properties;
}
public void log(String action, String userId) {
System.out.printf(
"audit app=%s action=%s userId=%s%n",
properties.getApplicationName(),
action,
userId
);
}
}3. Auto-configuration class
package uz.company.audit.autoconfigure;
import uz.company.audit.AuditLogger;
import uz.company.audit.AuditProperties;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
@AutoConfiguration
@EnableConfigurationProperties(AuditProperties.class)
@ConditionalOnProperty(
prefix = "company.audit",
name = "enabled",
havingValue = "true",
matchIfMissing = true
)
public class AuditAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public AuditLogger auditLogger(AuditProperties properties) {
return new AuditLogger(properties);
}
}Spring Boot custom auto-configuration yaratish bo‘yicha rasmiy hujjatda auto-configuration starter bilan bog‘lanishi, starter esa auto-configuration code va kerakli library’larni olib kelishi tushuntiriladi. (Home)
4. AutoConfiguration.imports
Spring Boot 3'da auto-configuration class’ni e’lon qilish uchun odatda quyidagi file ishlatiladi:
src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.importsIchida:
uz.company.audit.autoconfigure.AuditAutoConfigurationShundan keyin boshqa project dependency qo‘shsa, Spring Boot bu auto-configuration’ni ko‘radi.
5. Conditional annotations
Custom extension yozishda eng muhim narsa - shartli ishlash.
Yomon starter:
Dependency qo‘shilishi bilan hamma narsani majburan yaratadi.Yaxshi starter:
Faqat kerakli class/property/bean bo‘lsa ishlaydi.
User o‘z bean’ini bersa, starter chekinadi.Muhim condition annotationlar
Annotation | Vazifasi |
|---|---|
| Classpath’da class bo‘lsa ishlaydi |
| Class yo‘q bo‘lsa ishlaydi |
| Bean bor bo‘lsa ishlaydi |
| Bean yo‘q bo‘lsa default bean yaratadi |
| Property bo‘yicha yoqadi/o‘chiradi |
| Web app bo‘lsa ishlaydi |
| Web app bo‘lmasa ishlaydi |
Misol:
@Bean
@ConditionalOnMissingBean
public AuditLogger auditLogger(AuditProperties properties) {
return new AuditLogger(properties);
}Bu nima degani?
Agar user o‘zi AuditLogger bean bermagan bo‘lsa,
starter default AuditLogger yaratadi.Bu extension yozishda juda muhim odob:
User override qila olishi kerak.6. Custom starter
Starter nima?
Starter - dependencylarni va auto-configuration’ni bir joyga yig‘adigan library.
Masalan:
<dependency>
<groupId>uz.company</groupId>
<artifactId>company-audit-spring-boot-starter</artifactId>
<version>1.0.0</version>
</dependency>Shuni qo‘shgan project avtomatik quyidagilarga ega bo‘ladi:
AuditProperties
AuditLogger
AuditAspect
Audit actuator endpoint
Audit metricsStarter project structure
company-audit-spring-boot-starter/
src/main/java/
uz/company/audit/
AuditLogger.java
AuditProperties.java
AuditAspect.java
uz/company/audit/autoconfigure/
AuditAutoConfiguration.java
src/main/resources/
META-INF/spring/
org.springframework.boot.autoconfigure.AutoConfiguration.imports
pom.xmlStarter pom.xml
<project>
<groupId>uz.company</groupId>
<artifactId>company-audit-spring-boot-starter</artifactId>
<version>1.0.0</version>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
</dependency>
</dependencies>
</project>spring-boot-configuration-processor foydasi:
application.yml da autocomplete va metadata beradi.Masalan:
company:
audit:
enabled: true
application-name: order-service7. Starter ishlatish
Boshqa microservice’da faqat dependency qo‘shiladi:
<dependency>
<groupId>uz.company</groupId>
<artifactId>company-audit-spring-boot-starter</artifactId>
<version>1.0.0</version>
</dependency>Config:
company:
audit:
enabled: true
application-name: order-serviceService’da:
@Service
@RequiredArgsConstructor
public class OrderService {
private final AuditLogger auditLogger;
public void cancelOrder(Long orderId, String userId) {
auditLogger.log("ORDER_CANCELLED", userId);
}
}Bitta starter bilan 20 ta service’da bir xil audit standard ishlaydi.
8. Custom annotation + AOP
Muammo
Audit logni har joyda qo‘lda chaqirish ham boilerplate:
auditLogger.log("ORDER_CANCELLED", userId);Yaxshiroq:
@Auditable(action = "ORDER_CANCELLED")
public void cancelOrder(Long orderId) {
...
}Custom annotation
package uz.company.audit;
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Auditable {
String action();
}Aspect
package uz.company.audit;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class AuditAspect {
private final AuditLogger auditLogger;
private final CurrentUserProvider currentUserProvider;
public AuditAspect(
AuditLogger auditLogger,
CurrentUserProvider currentUserProvider
) {
this.auditLogger = auditLogger;
this.currentUserProvider = currentUserProvider;
}
@Around("@annotation(auditable)")
public Object audit(
ProceedingJoinPoint joinPoint,
Auditable auditable
) throws Throwable {
String userId = currentUserProvider.getCurrentUserId();
try {
Object result = joinPoint.proceed();
auditLogger.log(auditable.action() + "_SUCCESS", userId);
return result;
} catch (Throwable ex) {
auditLogger.log(auditable.action() + "_FAILED", userId);
throw ex;
}
}
}Auto-config’da aspect qo‘shamiz:
@Bean
@ConditionalOnMissingBean
public AuditAspect auditAspect(
AuditLogger auditLogger,
CurrentUserProvider currentUserProvider
) {
return new AuditAspect(auditLogger, currentUserProvider);
}Ishlatish
@Service
public class OrderService {
@Auditable(action = "ORDER_CANCELLED")
public void cancelOrder(Long orderId) {
// business logic
}
}Natija:
Method success bo‘lsa → ORDER_CANCELLED_SUCCESS
Exception bo‘lsa → ORDER_CANCELLED_FAILED9. Custom annotation yozishda ehtiyot bo‘lish
1. Self-invocation muammosi
Spring AOP proxy orqali ishlaydi.
@Service
public class OrderService {
public void methodA() {
methodB(); // self call
}
@Auditable(action = "METHOD_B")
public void methodB() {
}
}Bu holatda methodB() annotation’i ishlamasligi mumkin, chunki chaqiriq proxy’dan o‘tmaydi.
Yechimlar:
- Annotated methodni boshqa bean’ga chiqarish
- AspectJ weaving ishlatish
- Self-invocation’dan qochish2. Private methodlarga AOP ishlamasligi
Yomon:
@Auditable(action = "PRIVATE")
private void doWork() {
}Spring AOP odatda public/proxy orqali chaqiriladigan methodlarda ishlaydi.
3. Annotation business logic’ni yashirib yubormasin
Annotation juda ko‘payib ketsa:
@Auditable
@Retryable
@Transactional
@Cacheable
@PreAuthorizemethodning real behavior’ini tushunish qiyinlashadi.
Senior qoida:
Annotation abstraction bo‘lsa ham, behavior aniq va predictable bo‘lsin.10. Custom Actuator endpoint
Nima uchun kerak?
Spring Boot Actuator application’ni kuzatish va boshqarish uchun endpointlar beradi; rasmiy hujjatda Actuator ichki endpointlardan tashqari custom endpoint qo‘shish imkonini ham berishi aytiladi. (Home)
Custom endpoint misollar:
/actuator/features
/actuator/tenants
/actuator/build-info
/actuator/kafka-status
/actuator/outboxCustom endpoint misol
package uz.company.platform.actuator;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import java.util.Map;
@Endpoint(id = "features")
public class FeatureFlagsEndpoint {
private final FeatureFlagService featureFlagService;
public FeatureFlagsEndpoint(FeatureFlagService featureFlagService) {
this.featureFlagService = featureFlagService;
}
@ReadOperation
public Map<String, Boolean> features() {
return featureFlagService.getAllFlags();
}
}Auto-config:
@Bean
@ConditionalOnBean(FeatureFlagService.class)
public FeatureFlagsEndpoint featureFlagsEndpoint(
FeatureFlagService featureFlagService
) {
return new FeatureFlagsEndpoint(featureFlagService);
}Config:
management:
endpoints:
web:
exposure:
include: health,info,featuresEndpoint:
GET /actuator/featuresResponse:
{
"paymentV2": true,
"newCheckout": false
}Custom Actuator endpoint xavfsizligi
Actuator endpointlar production’da ehtiyotkorlik bilan ochiladi.
Yomon:
management:
endpoints:
web:
exposure:
include: "*"Yaxshi:
management:
endpoints:
web:
exposure:
include: health,info,prometheus,featuresSecurity config:
@Bean
SecurityFilterChain actuatorSecurity(HttpSecurity http) throws Exception {
return http
.securityMatcher("/actuator/**")
.authorizeHttpRequests(auth -> auth
.requestMatchers("/actuator/health").permitAll()
.requestMatchers("/actuator/prometheus").hasRole("MONITORING")
.anyRequest().hasRole("ADMIN")
)
.build();
}Senior qoida:
Actuator endpoint operational data beradi. Uni public ochmang.11. Custom HealthIndicator
Agar sizda muhim dependency bo‘lsa, custom health indicator yozish mumkin.
Masalan, payment provider status:
@Component
public class PaymentProviderHealthIndicator implements HealthIndicator {
private final PaymentProviderClient client;
public PaymentProviderHealthIndicator(PaymentProviderClient client) {
this.client = client;
}
@Override
public Health health() {
try {
boolean ok = client.ping();
if (ok) {
return Health.up()
.withDetail("provider", "payment-provider")
.build();
}
return Health.down()
.withDetail("provider", "payment-provider")
.build();
} catch (Exception ex) {
return Health.down(ex).build();
}
}
}Lekin ehtiyot:
Har dependency’ni liveness ichiga qo‘shmang.
Critical dependency readiness’da bo‘lishi mumkin.12. Application events
Spring ichida event publish/listen qilish mumkin.
Event class
public record OrderCreatedEvent(
Long orderId,
Long userId
) {}Publish qilish
@Service
@RequiredArgsConstructor
public class OrderService {
private final ApplicationEventPublisher eventPublisher;
@Transactional
public void createOrder(CreateOrderRequest request) {
Order order = saveOrder(request);
eventPublisher.publishEvent(
new OrderCreatedEvent(order.getId(), order.getUserId())
);
}
}Listen qilish
@Component
public class OrderCreatedListener {
@EventListener
public void handle(OrderCreatedEvent event) {
System.out.println("Order created: " + event.orderId());
}
}13. Transactional event listener
Oddiy @EventListener transaction ichida darhol ishlashi mumkin.
Agar eventni faqat DB commit bo‘lgandan keyin ishlatmoqchi bo‘lsangiz:
@Component
public class OrderCreatedListener {
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void handle(OrderCreatedEvent event) {
// DB commit bo‘lgandan keyin ishlaydi
}
}Bu muhim.
Yomon flow:
Order save qilindi
Event publish qilindi
Listener notification yubordi
Keyin DB transaction rollback bo‘ldiNatija:
User notification oldi, lekin order DB’da yo‘q.Yaxshi:
DB commit
↓
AFTER_COMMIT listener
↓
Notification14. @Async event listener
Event listener’ni async qilish mumkin:
@Component
public class OrderCreatedListener {
@Async("eventExecutor")
@EventListener
public void handle(OrderCreatedEvent event) {
// background processing
}
}Executor:
@Configuration
@EnableAsync
public class AsyncConfig {
@Bean
public Executor eventExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(20);
executor.setQueueCapacity(1000);
executor.setThreadNamePrefix("event-");
executor.initialize();
return executor;
}
}Ehtiyot:
Async event transaction boundary va error handlingni murakkablashtiradi.Agar event juda muhim bo‘lsa:
Spring event emas, outbox + Kafka ishlating.15. ApplicationListener
@EventListener o‘rniga class-based listener ham yozish mumkin.
@Component
public class OrderCreatedApplicationListener
implements ApplicationListener<OrderCreatedEvent> {
@Override
public void onApplicationEvent(OrderCreatedEvent event) {
System.out.println("Order created: " + event.orderId());
}
}Qachon kerak?
- Framework-level extension yozilganda
- Generic listener kerak bo‘lsa
- Starter ichida explicit contract kerak bo‘lsa16. Spring Boot lifecycle events
Spring Boot application start paytida turli eventlar chiqaradi.
Ko‘p ishlatiladiganlari:
Event | Qachon ishlaydi |
|---|---|
| Juda erta |
| Environment tayyor |
| Context tayyorlanmoqda |
| Context refresh bo‘ldi |
| App request qabul qilishga tayyor |
| Startup fail bo‘ldi |
Masalan:
@Component
public class StartupLogger {
@EventListener(ApplicationReadyEvent.class)
public void onReady() {
System.out.println("Application is ready");
}
}ApplicationReadyEvent - warmup yoki startup tugaganidan keyingi ishlar uchun qulay.
Lekin og‘ir ishni shu yerda sync bajarish ham app readiness’ga ta’sir qilishi mumkin.
17. SmartLifecycle
Nima?
SmartLifecycle - Spring context start/stop jarayonida komponentni boshqarish uchun ishlatiladi.
Masalan:
Kafka consumerni custom start qilish
Background worker boshlash
Scheduler-like processor ishga tushirish
External connection ochish
Graceful shutdown’da to‘xtatishSpring Framework SmartLifecycle interface’i Lifecycle'ni kengaytiradi va auto-startup, phase kabi imkoniyatlar beradi. (Home)
SmartLifecycle misol
@Component
public class OutboxWorkerLifecycle implements SmartLifecycle {
private final OutboxWorker worker;
private volatile boolean running = false;
public OutboxWorkerLifecycle(OutboxWorker worker) {
this.worker = worker;
}
@Override
public void start() {
worker.start();
running = true;
}
@Override
public void stop() {
worker.stop();
running = false;
}
@Override
public boolean isRunning() {
return running;
}
@Override
public boolean isAutoStartup() {
return true;
}
@Override
public int getPhase() {
return 100;
}
}getPhase() nima?
Phase start/stop tartibini boshqaradi.
Kichik phase → oldin start
Katta phase → keyin start
Stop paytida aksincha:
Katta phase → oldin stop
Kichik phase → keyin stopMasalan:
Database connection manager phase=0
Outbox worker phase=100Start:
DB avval
Worker keyinStop:
Worker avval
DB keyinBu graceful shutdown uchun juda foydali.
18. Custom BeanPostProcessor
Nima?
BeanPostProcessor bean yaratilgandan keyin uni o‘zgartirish yoki tekshirish imkonini beradi.
Bu advanced Spring internals mavzusi.
Misol: @Sensitive annotationli beanlarni startup’da tekshirish.
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface SensitiveComponent {
}Processor:
@Component
public class SensitiveBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(
Object bean,
String beanName
) throws BeansException {
if (bean.getClass().isAnnotationPresent(SensitiveComponent.class)) {
System.out.println("Sensitive bean registered: " + beanName);
}
return bean;
}
}Ehtiyot:
BeanPostProcessor noto‘g‘ri yozilsa, butun application context behavior’i buzilishi mumkin.Buni faqat haqiqiy zaruratda ishlating.
19. Custom annotation for validation
Spring extension faqat AOP emas. Bean Validation uchun ham custom annotation yoziladi.
Annotation
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = PhoneNumberValidator.class)
public @interface ValidUzPhone {
String message() default "Invalid Uzbekistan phone number";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}Validator
public class PhoneNumberValidator
implements ConstraintValidator<ValidUzPhone, String> {
private static final Pattern PATTERN =
Pattern.compile("^\\+998\\d{9}$");
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (value == null || value.isBlank()) {
return true;
}
return PATTERN.matcher(value).matches();
}
}Ishlatish
public record RegisterRequest(
@NotBlank String name,
@ValidUzPhone String phone
) {}20. Custom meta-annotation
Ba’zida bir nechta annotationni bitta annotationga yig‘ish mumkin.
Masalan:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@PreAuthorize("hasAuthority('SCOPE_orders.write')")
@Transactional
@Auditable(action = "ORDER_WRITE")
public @interface OrderWriteOperation {
}Ishlatish:
@OrderWriteOperation
public void cancelOrder(Long orderId) {
...
}Ehtiyot:
Meta-annotation behaviorni yashirib yuborishi mumkin.
Team buni yaxshi tushunsa ishlating.21. Custom starter uchun test
Starter yozsangiz, uni albatta test qilish kerak.
Spring Boot’da ApplicationContextRunner custom auto-configuration testlari uchun juda qulay.
class AuditAutoConfigurationTest {
private final ApplicationContextRunner contextRunner =
new ApplicationContextRunner()
.withConfiguration(
AutoConfigurations.of(AuditAutoConfiguration.class)
);
@Test
void shouldCreateAuditLoggerByDefault() {
contextRunner.run(context -> {
assertThat(context).hasSingleBean(AuditLogger.class);
});
}
@Test
void shouldDisableAuditWhenPropertyFalse() {
contextRunner
.withPropertyValues("company.audit.enabled=false")
.run(context -> {
assertThat(context).doesNotHaveBean(AuditLogger.class);
});
}
@Test
void shouldBackOffWhenUserProvidesAuditLogger() {
contextRunner
.withBean(AuditLogger.class, () -> new CustomAuditLogger())
.run(context -> {
assertThat(context).hasSingleBean(AuditLogger.class);
});
}
}Test qilinadigan narsalar:
[ ] Default bean yaratiladimi?
[ ] Property orqali o‘chadimi?
[ ] User custom bean bersa back off qiladimi?
[ ] Kerakli class yo‘q bo‘lsa ishlamayaptimi?
[ ] Web/non-web context farqi to‘g‘rimi?22. Versioning va compatibility
Internal starter ham product kabi versionlanadi.
Yomon:
company-starter:latestYaxshi:
company-starter:1.4.2Semantic versioning:
Version | Ma’nosi |
|---|---|
| Bug fix |
| Backward-compatible feature |
| Breaking change |
Senior qoida:
Starter yangilanishi 20 ta service’ni buzmasligi kerak.23. Real example: company observability starter
Kompaniyada har microservice’da bir xil observability kerak:
traceId loglarda
common MDC filter
custom metrics
standard actuator exposure
correlation id
exception metricsStarter:
company-observability-starterIchida:
CorrelationIdFilter
MdcLoggingFilter
CommonTagsCustomizer
CustomHealthIndicator
Actuator endpoint
AutoConfiguration
PropertiesService’da faqat:
<dependency>
<groupId>uz.company</groupId>
<artifactId>company-observability-starter</artifactId>
<version>1.0.0</version>
</dependency>Config:
company:
observability:
correlation-id-header: X-Correlation-Id
service-name: order-serviceNatija:
Hamma service bir xil log format
Hamma service bir xil metrics tag
Hamma service bir xil correlation id handlingBu custom Spring extension’ning haqiqiy foydasi.
24. Common mistakes
1. Starter juda ko‘p ish qiladi
Yomon:
company-platform-starter
security
kafka
database
redis
actuator
tracing
exception
migration
cacheBunday starter juda og‘ir bo‘ladi.
Yaxshiroq:
company-security-starter
company-kafka-starter
company-observability-starter
company-multitenancy-starter2. Override qilish imkoni yo‘q
Yomon:
@Bean
public AuditLogger auditLogger() {
return new AuditLogger();
}Yaxshi:
@Bean
@ConditionalOnMissingBean
public AuditLogger auditLogger() {
return new AuditLogger();
}3. Property bilan o‘chirib bo‘lmaydi
Har starterda disable option bo‘lsin:
company:
audit:
enabled: false4. Internal API documentation yo‘q
Starterda README bo‘lishi kerak:
- Nima qiladi?
- Qanday dependency qo‘shiladi?
- Qanday config bor?
- Default behavior nima?
- Qanday override qilinadi?
- Qanday troubleshoot qilinadi?5. Auto-config haddan tashqari agressiv
Starter user project’da kutilmagan bean yaratmasligi kerak.
25. Custom Spring extensions checklist
[ ] Extension haqiqatan reusablemi?
[ ] Auto-configuration shartli ishlaydimi?
[ ] @ConditionalOnMissingBean ishlatilganmi?
[ ] Property orqali enable/disable bormi?
[ ] ConfigurationProperties bor-mi?
[ ] Metadata/autocomplete uchun configuration processor bormi?
[ ] AutoConfiguration.imports to‘g‘ri yozilganmi?
[ ] Actuator endpointlar secure qilinganmi?
[ ] AOP self-invocation muammosi hisobga olinganmi?
[ ] Lifecycle start/stop tartibi aniqmi?
[ ] ApplicationContextRunner bilan test qilinganmi?
[ ] Versioning strategy bormi?
[ ] README va config example bormi?
[ ] Breaking change release’da aniq yozilganmi?26. Senior interview javob
Suhbatda so‘rasa:
Custom Spring starter yoki auto-configuration yozganmisiz? Qanday ishlaydi?
Javob:
Custom Spring starter umumiy platform config’ni reusable qilish uchun yoziladi.
Masalan, company-observability-starter yoki company-security-starter.
Starter ichida auto-configuration class bo‘ladi, u @AutoConfiguration bilan belgilanadi va
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports file orqali Spring Boot’ga tanitiladi.
Auto-configuration majburan bean yaratmasligi kerak. Shuning uchun @ConditionalOnClass,
@ConditionalOnProperty, @ConditionalOnMissingBean kabi condition annotationlar ishlatiladi.
User o‘z bean’ini bersa, starter back off qilishi kerak.
ConfigurationProperties orqali application.yml’dan type-safe config olinadi.
Agar kerak bo‘lsa custom annotation + AOP, custom Actuator endpoint, HealthIndicator,
ApplicationListener yoki SmartLifecycle qo‘shiladi.
Bunday starter ApplicationContextRunner bilan test qilinadi:
default bean yaratilishi, property bilan disable bo‘lishi, user custom bean bersa override ishlashi tekshiriladi.27. Qisqa xulosa
Custom Spring extensions Senior developer uchun Spring ekotizimini chuqur tushunishni ko‘rsatadi.
Qisqa xulosa qilsak:
Custom extension - takrorlanadigan platform kodni reusable, configurable va override qilinadigan Spring module’ga aylantirish.Eng muhim tushunchalar:
Mavzu | Esda qoladigan qoida |
|---|---|
Auto-configuration | Dependency/property/bean asosida avtomatik config |
Custom starter | Dependency + auto-config + common code |
| Spring Boot 3 auto-config registration |
| User override qila olsin |
| Type-safe config |
Custom annotation + AOP | Cross-cutting concern uchun |
Custom Actuator endpoint | Operational visibility uchun |
| Spring eventlarga javob berish |
| Start/stop tartibini boshqarish |
| Starter testlari uchun |