📌 موضوع Scope Beanها و تفاوت Singleton و Prototype در Spring
سلام دوستان عزیز
در ادامهی آشنایی با Beanها، در این پیام به بررسی Scope یا محدودهی عمر Beanها در Spring میپردازیم. درک این مفهوم به ما کمک میکند بفهمیم هر شیء چه زمانی ساخته میشود و چند بار مورد استفاده قرار میگیرد.
۱) مفهوم Scope در Spring
«اسکوپ» مشخص میکند که از یک Bean چند نمونه ساخته شود و طول عمر آن چگونه باشد. به طور پیشفرض، Spring برای هر Bean فقط یک نمونه میسازد؛ اما این رفتار قابل تغییر است. انتخاب Scope مناسب تأثیر مستقیم بر عملکرد و منطق برنامه دارد.
۲) Singleton Scope (پیشفرض)
«سینگلتون» رایجترین و پیشفرضترین Scope در Spring است. در این حالت، تنها یک نمونه از Bean در کل برنامه ساخته میشود و همهی بخشها از همان نمونه استفاده میکنند.
مثال:
در این مثال، اگر این سرویس در چند کنترلر تزریق شود، همگی به یک شیء مشترک اشاره میکنند.
این نوع Scope برای سرویسها و منطقهای عمومی بسیار مناسب است.
۳) Prototype Scope
«پروتوتایپ» به این معناست که هر بار که یک Bean درخواست شود، یک نمونهی جدید ساخته میشود. این Scope برای مواقعی کاربرد دارد که هر استفاده نیازمند وضعیت (State) جداگانه باشد.
مثال:
در این حالت، هر بار که ReportGenerator تزریق یا دریافت شود، یک شیء جدید ایجاد میشود.
۴) مقایسه عملی Singleton و Prototype
«مقایسه» این دو Scope را میتوان با یک مثال ساده درک کرد.
اگر یک سرویس پردازش کاربران داشته باشیم، استفاده از Singleton منطقی است؛ زیرا منطق مشترک است.
اما اگر کلاسی برای ساخت گزارش لحظهای داشته باشیم که اطلاعات خاص هر درخواست را نگه میدارد، Prototype گزینهی بهتری است.
۵) رفتار Spring Container با Scopeها
«رفتار» Spring Container در مورد Singleton این است که Bean در زمان بالا آمدن برنامه ساخته میشود.
اما در Prototype، Bean فقط زمانی ساخته میشود که واقعاً درخواست شود و Spring مسئول نابودی آن نخواهد بود.
این تفاوت مهمی است که در طراحی سیستمهای بزرگ باید به آن توجه شود.
۶) چرا بیشتر Beanها Singleton هستند؟
«دلیل» اصلی استفاده گسترده از Singleton این است که Spring به صورت Stateless طراحی شده است. سرویسها معمولاً وضعیت داخلی ندارند و میتوانند به صورت مشترک استفاده شوند. این موضوع باعث مصرف کمتر حافظه و عملکرد بهتر برنامه میشود.
۷) جمعبندی پیام
«نتیجه» این است که Scope مشخص میکند از هر Bean چند نمونه ساخته شود. Singleton برای اغلب سرویسها انتخاب مناسبی است و Prototype فقط در شرایط خاص استفاده میشود. در پیام بعدی وارد مبحث بسیار مهم تزریق وابستگی (Dependency Injection) و انواع آن در Spring خواهیم شد.
سلام دوستان عزیز
در ادامهی آشنایی با Beanها، در این پیام به بررسی Scope یا محدودهی عمر Beanها در Spring میپردازیم. درک این مفهوم به ما کمک میکند بفهمیم هر شیء چه زمانی ساخته میشود و چند بار مورد استفاده قرار میگیرد.
۱) مفهوم Scope در Spring
«اسکوپ» مشخص میکند که از یک Bean چند نمونه ساخته شود و طول عمر آن چگونه باشد. به طور پیشفرض، Spring برای هر Bean فقط یک نمونه میسازد؛ اما این رفتار قابل تغییر است. انتخاب Scope مناسب تأثیر مستقیم بر عملکرد و منطق برنامه دارد.
۲) Singleton Scope (پیشفرض)
«سینگلتون» رایجترین و پیشفرضترین Scope در Spring است. در این حالت، تنها یک نمونه از Bean در کل برنامه ساخته میشود و همهی بخشها از همان نمونه استفاده میکنند.
مثال:
@Service
public class UserService {
}
در این مثال، اگر این سرویس در چند کنترلر تزریق شود، همگی به یک شیء مشترک اشاره میکنند.
این نوع Scope برای سرویسها و منطقهای عمومی بسیار مناسب است.
۳) Prototype Scope
«پروتوتایپ» به این معناست که هر بار که یک Bean درخواست شود، یک نمونهی جدید ساخته میشود. این Scope برای مواقعی کاربرد دارد که هر استفاده نیازمند وضعیت (State) جداگانه باشد.
مثال:
@Component
@Scope("prototype")
public class ReportGenerator {
}
در این حالت، هر بار که ReportGenerator تزریق یا دریافت شود، یک شیء جدید ایجاد میشود.
۴) مقایسه عملی Singleton و Prototype
«مقایسه» این دو Scope را میتوان با یک مثال ساده درک کرد.
اگر یک سرویس پردازش کاربران داشته باشیم، استفاده از Singleton منطقی است؛ زیرا منطق مشترک است.
اما اگر کلاسی برای ساخت گزارش لحظهای داشته باشیم که اطلاعات خاص هر درخواست را نگه میدارد، Prototype گزینهی بهتری است.
۵) رفتار Spring Container با Scopeها
«رفتار» Spring Container در مورد Singleton این است که Bean در زمان بالا آمدن برنامه ساخته میشود.
اما در Prototype، Bean فقط زمانی ساخته میشود که واقعاً درخواست شود و Spring مسئول نابودی آن نخواهد بود.
این تفاوت مهمی است که در طراحی سیستمهای بزرگ باید به آن توجه شود.
۶) چرا بیشتر Beanها Singleton هستند؟
«دلیل» اصلی استفاده گسترده از Singleton این است که Spring به صورت Stateless طراحی شده است. سرویسها معمولاً وضعیت داخلی ندارند و میتوانند به صورت مشترک استفاده شوند. این موضوع باعث مصرف کمتر حافظه و عملکرد بهتر برنامه میشود.
۷) جمعبندی پیام
«نتیجه» این است که Scope مشخص میکند از هر Bean چند نمونه ساخته شود. Singleton برای اغلب سرویسها انتخاب مناسبی است و Prototype فقط در شرایط خاص استفاده میشود. در پیام بعدی وارد مبحث بسیار مهم تزریق وابستگی (Dependency Injection) و انواع آن در Spring خواهیم شد.
#Spring
🆔 @javapro_ir
🆔 @group_javapro
👍7❤2
سوال یکی از کاربران جاواپرو
برای مصاحبه نیاز به یادگیری هایبرنیت دارم، در بین دوره های جاواپرو دوره ای هست که ی ذره هایبرنیت رو بررسی کرده باشه؟
یکی از اهداف دوره Spring Core همین است. و بسیار زیاد هایبرنیت بررسی شده.
سرفصل های هایبرنیت آکادمی جاواپرو کامله و جایی این مباحث رو پیدا نمیکنید که تدریس شده باشه
مشاهده جزییات و ثبت نام
برای مصاحبه نیاز به یادگیری هایبرنیت دارم، در بین دوره های جاواپرو دوره ای هست که ی ذره هایبرنیت رو بررسی کرده باشه؟
یکی از اهداف دوره Spring Core همین است. و بسیار زیاد هایبرنیت بررسی شده.
سرفصل های هایبرنیت آکادمی جاواپرو کامله و جایی این مباحث رو پیدا نمیکنید که تدریس شده باشه
مشاهده جزییات و ثبت نام
آکادمی جاواپرو
دوره طلایی Spring Core
این دوره به شما کمک میکند تا با مبانی Spring Boot آشنا شوید و مهارتهای لازم برای توسعهی برنامههای کاربردی مبتنی بر این فریمورک محبوب جاوا را کسب کنید.
❤2
برنامه نویسی جاوا | جاواپرو
📌 موضوع Scope Beanها و تفاوت Singleton و Prototype در Spring سلام دوستان عزیز در ادامهی آشنایی با Beanها، در این پیام به بررسی Scope یا محدودهی عمر Beanها در Spring میپردازیم. درک این مفهوم به ما کمک میکند بفهمیم هر شیء چه زمانی ساخته میشود و چند بار…
📌 موضوع: Dependency Injection و روشهای تزریق وابستگی در Spring Boot
سلام دوستان عزیز
در این پیام به یکی از بنیادیترین مفاهیم Spring Boot میپردازیم؛ مفهومی که تقریباً در تمام بخشهای پروژههای حرفهای استفاده میشود و نقش کلیدی در تمیزی معماری دارد. این مفهوم چیزی نیست جز تزریق وابستگی یا Dependency Injection.
۱) مفهوم Dependency Injection
«تزریق» وابستگی به این معناست که یک کلاس، اشیای موردنیاز خود را **خودش نسازد**، بلکه آنها را از بیرون دریافت کند. در Spring Boot این کار توسط Spring Container انجام میشود.
این رویکرد باعث کاهش وابستگی مستقیم بین کلاسها و افزایش تستپذیری و انعطافپذیری برنامه میشود.
به بیان ساده، کلاسها فقط اعلام میکنند به چه چیزی نیاز دارند و Spring آن را فراهم میکند.
۲) مشکل ساخت مستقیم اشیا
«مشکل» روش سنتی این است که کلاسها به هم وابستگی شدید پیدا میکنند. مثال زیر یک روش نامناسب است:
در این حالت OrderService به پیادهسازی EmailSender قفل شده است و تغییر یا تست آن بسیار دشوار میشود.
۳) تزریق وابستگی با Constructor Injection
«تزریق» از طریق سازنده بهترین و توصیهشدهترین روش در Spring است. در این روش وابستگیها از طریق سازنده کلاس دریافت میشوند.
در این مثال، Spring به صورت خودکار Bean مربوط به EmailSender را ساخته و تزریق میکند. این روش امن، شفاف و قابل تست است.
۴) تزریق وابستگی با Field Injection
«تزریق» فیلدی با استفاده از @Autowired انجام میشود. هرچند این روش سادهتر به نظر میرسد، اما توصیه نمیشود.
این روش تستپذیری را کاهش میدهد و وابستگیها را مخفی میکند.
۵) تزریق وابستگی با Setter Injection
«تزریق» از طریق Setter برای مواقعی استفاده میشود که وابستگی اختیاری باشد.
در این حالت میتوان وابستگی را بعداً تغییر داد، اما برای وابستگیهای اصلی توصیه نمیشود.
۶) استفاده از Interface در DI
«استفاده» از Interface باعث میشود وابستگیها به پیادهسازی خاصی قفل نشوند.
در این ساختار میتوان به راحتی پیادهسازیها را تغییر داد.
۷) جمعبندی پیام
«نتیجه» این است که Dependency Injection هستهی اصلی Spring Boot محسوب میشود. استفاده از Constructor Injection به همراه Interfaceها باعث تولید کدی تمیز، قابل تست و حرفهای میشود. در پیام بعدی وارد مبحث Configuration، فایل application.properties و مدیریت تنظیمات پروژه خواهیم شد.
سلام دوستان عزیز
در این پیام به یکی از بنیادیترین مفاهیم Spring Boot میپردازیم؛ مفهومی که تقریباً در تمام بخشهای پروژههای حرفهای استفاده میشود و نقش کلیدی در تمیزی معماری دارد. این مفهوم چیزی نیست جز تزریق وابستگی یا Dependency Injection.
۱) مفهوم Dependency Injection
«تزریق» وابستگی به این معناست که یک کلاس، اشیای موردنیاز خود را **خودش نسازد**، بلکه آنها را از بیرون دریافت کند. در Spring Boot این کار توسط Spring Container انجام میشود.
این رویکرد باعث کاهش وابستگی مستقیم بین کلاسها و افزایش تستپذیری و انعطافپذیری برنامه میشود.
به بیان ساده، کلاسها فقط اعلام میکنند به چه چیزی نیاز دارند و Spring آن را فراهم میکند.
۲) مشکل ساخت مستقیم اشیا
«مشکل» روش سنتی این است که کلاسها به هم وابستگی شدید پیدا میکنند. مثال زیر یک روش نامناسب است:
public class OrderService {
private EmailSender emailSender = new EmailSender();
}
در این حالت OrderService به پیادهسازی EmailSender قفل شده است و تغییر یا تست آن بسیار دشوار میشود.
۳) تزریق وابستگی با Constructor Injection
«تزریق» از طریق سازنده بهترین و توصیهشدهترین روش در Spring است. در این روش وابستگیها از طریق سازنده کلاس دریافت میشوند.
@Service
public class OrderService {
private final EmailSender emailSender;
public OrderService(EmailSender emailSender) {
this.emailSender = emailSender;
}
}
در این مثال، Spring به صورت خودکار Bean مربوط به EmailSender را ساخته و تزریق میکند. این روش امن، شفاف و قابل تست است.
۴) تزریق وابستگی با Field Injection
«تزریق» فیلدی با استفاده از @Autowired انجام میشود. هرچند این روش سادهتر به نظر میرسد، اما توصیه نمیشود.
@Service
public class OrderService {
@Autowired
private EmailSender emailSender;
}
این روش تستپذیری را کاهش میدهد و وابستگیها را مخفی میکند.
۵) تزریق وابستگی با Setter Injection
«تزریق» از طریق Setter برای مواقعی استفاده میشود که وابستگی اختیاری باشد.
@Service
public class OrderService {
private EmailSender emailSender;
@Autowired
public void setEmailSender(EmailSender emailSender) {
this.emailSender = emailSender;
}
}
در این حالت میتوان وابستگی را بعداً تغییر داد، اما برای وابستگیهای اصلی توصیه نمیشود.
۶) استفاده از Interface در DI
«استفاده» از Interface باعث میشود وابستگیها به پیادهسازی خاصی قفل نشوند.
public interface MessageSender {
void send(String message);
}
@Component
public class EmailSender implements MessageSender {
public void send(String message) {
System.out.println(message);
}
}
@Service
public class NotificationService {
private final MessageSender messageSender;
public NotificationService(MessageSender messageSender) {
this.messageSender = messageSender;
}
}
در این ساختار میتوان به راحتی پیادهسازیها را تغییر داد.
۷) جمعبندی پیام
«نتیجه» این است که Dependency Injection هستهی اصلی Spring Boot محسوب میشود. استفاده از Constructor Injection به همراه Interfaceها باعث تولید کدی تمیز، قابل تست و حرفهای میشود. در پیام بعدی وارد مبحث Configuration، فایل application.properties و مدیریت تنظیمات پروژه خواهیم شد.
#Spring
🆔 @javapro_ir
🆔 @group_javapro
👍7❤1
اتوماسیون انتقال داده از CSV به دیتابیس با Spring Boot و Spring Batch
من اخیراً یک پروژه با Spring Batch پیادهسازی کردم که وظیفهاش پردازش دادهها از یک فایل CSV و ذخیره آنها در دیتابیس بود.
این پروژه کل جریان استاندارد Reader → Processor → Writer → Job → Listener را بهصورت کامل پوشش میدهد.
در ادامه، اجزای اصلی این پروژه را مرحلهبهمرحله بررسی میکنیم 👇
📂 ۱. Reader (FlatFileItemReader)
این بخش فایل sample-data.csv را میخواند و هر سطر را به یک شیء از نوع Person نگاشت میکند.
🛠 ۲. Processor (ItemProcessor)
در این مرحله، دادهها قبل از ذخیرهسازی تغییر داده میشوند.
در این مثال، نام و نام خانوادگی هر شخص به حروف بزرگ (UPPERCASE) تبدیل میشود.
💾 ۳. Writer (JdbcBatchItemWriter)
این بخش دادههای پردازششده را در جدول people دیتابیس درج میکند.
⚙️ ۴. Job و Step
در این قسمت، Job و Step تعریف میشوند.
اندازه chunk برابر با ۳ است؛ یعنی:
۳ رکورد خوانده میشود
پردازش انجام میگیرد
در دیتابیس ذخیره میشود
این چرخه تا پایان فایل تکرار میشود
📊 ۵. Listener (JobExecutionListener)
پس از اتمام Job، این Listener اجرا میشود تا صحت درج دادهها در دیتابیس بررسی شود.
✨ چرا کار روی این پروژه جذاب بود؟
✔️ مدیریت بهینه دیتاستهای حجیم با استفاده از پردازش Chunk
✔️ پیادهسازی یک خط لوله تمیز ETL (استخراج → تبدیل → بارگذاری)
✔️ تفکیک شفاف مسئولیتها بین Reader، Processor و Writer
این پروژه تجربه عملی بسیار خوبی از استفاده واقعی Spring Boot و Spring Batch برای اتوماسیون پردازش دادهها فراهم کرد.
من اخیراً یک پروژه با Spring Batch پیادهسازی کردم که وظیفهاش پردازش دادهها از یک فایل CSV و ذخیره آنها در دیتابیس بود.
این پروژه کل جریان استاندارد Reader → Processor → Writer → Job → Listener را بهصورت کامل پوشش میدهد.
در ادامه، اجزای اصلی این پروژه را مرحلهبهمرحله بررسی میکنیم 👇
📂 ۱. Reader (FlatFileItemReader)
این بخش فایل sample-data.csv را میخواند و هر سطر را به یک شیء از نوع Person نگاشت میکند.
@Bean
public FlatFileItemReader<Person> reader() {
return new FlatFileItemReaderBuilder<Person>()
.name("personItemReader")
.resource(new ClassPathResource("sample-data.csv"))
.delimited()
.names("firstName", "lastName")
.targetType(Person.class)
.build();
}
🛠 ۲. Processor (ItemProcessor)
در این مرحله، دادهها قبل از ذخیرهسازی تغییر داده میشوند.
در این مثال، نام و نام خانوادگی هر شخص به حروف بزرگ (UPPERCASE) تبدیل میشود.
public class PersonItemProcessor implements ItemProcessor<Person, Person> {
@Override
public Person process(Person person) {
return new Person(
person.firstName().toUpperCase(),
person.lastName().toUpperCase()
);
}
}💾 ۳. Writer (JdbcBatchItemWriter)
این بخش دادههای پردازششده را در جدول people دیتابیس درج میکند.
@Bean
public JdbcBatchItemWriter<Person> writer(DataSource dataSource) {
return new JdbcBatchItemWriterBuilder<Person>()
.sql("INSERT INTO people (first_name, last_name) VALUES (:firstName, :lastName)")
.dataSource(dataSource)
.beanMapped()
.build();
}
⚙️ ۴. Job و Step
در این قسمت، Job و Step تعریف میشوند.
اندازه chunk برابر با ۳ است؛ یعنی:
۳ رکورد خوانده میشود
پردازش انجام میگیرد
در دیتابیس ذخیره میشود
این چرخه تا پایان فایل تکرار میشود
@Bean
public Step step1(
JobRepository jobRepository,
DataSourceTransactionManager transactionManager,
FlatFileItemReader<Person> reader,
PersonItemProcessor processor,
JdbcBatchItemWriter<Person> writer) {
return new StepBuilder("step1", jobRepository)
.<Person, Person>chunk(3, transactionManager)
.reader(reader)
.processor(processor)
.writer(writer)
.build();
}
📊 ۵. Listener (JobExecutionListener)
پس از اتمام Job، این Listener اجرا میشود تا صحت درج دادهها در دیتابیس بررسی شود.
@Override
public void afterJob(JobExecution jobExecution) {
if (jobExecution.getStatus() == BatchStatus.COMPLETED) {
jdbcTemplate
.query(
"SELECT first_name, last_name FROM people",
new DataClassRowMapper<>(Person.class)
)
.forEach(person ->
log.info("Found <{}> in the database.", person)
);
}
}
✨ چرا کار روی این پروژه جذاب بود؟
✔️ مدیریت بهینه دیتاستهای حجیم با استفاده از پردازش Chunk
✔️ پیادهسازی یک خط لوله تمیز ETL (استخراج → تبدیل → بارگذاری)
✔️ تفکیک شفاف مسئولیتها بین Reader، Processor و Writer
این پروژه تجربه عملی بسیار خوبی از استفاده واقعی Spring Boot و Spring Batch برای اتوماسیون پردازش دادهها فراهم کرد.
🆔 @javapro_ir
🆔 @group_javapro