【初心者のspringboot】springboot初心者が開発現場で必要な知識をみにつけるまで!!
どうも!ヒグッティ(X→ヒグッティ@システムエンジニア)です!
今回は、SpringBootで実際に現場で開発をしたときのことについて書いていきます!誰にでも初めてはありますよね!自分のスキルが増える!でもできるかすごく不安。。そんな不安をこのブログを見た後に少しでも緩和できればと思います!springbootで開発するときに何をすればよいのか?どんなことに気を付ければよいのかなどを書いていきます!springboot初心者目線なので専門的な内容はご理解を、、
過去に私が作成したspringbootについて記載した記事があるので良かったら見てください!
前提とスペック
当時の私は転職したてで、開発案件にアサインされたばかりの状況でした。チームに貢献しないと!無能と思われたくない!などいろいろあり張り切っていました。開発するときの私のスペックです。Java歴10年くらい、AWS歴6年くらい、springboot歴0.1年くらい、その他、今回使わない言語の経験が2年くらい(Javascript,HTML,PHPなど)。
経緯
当時、私が所属していた部署、グループでspringbootでサービスを使ったことがなかったらしい。私はspringbootが使えるようにインフラチームやセキュリティチームといろいろ相談してインフラ構成が決まり、よし、これから開発するぞ!というときに私がアサインされました。実際に触ったことがなかったので不安はありましたが、この年(当時34歳)で新しいスキルを取得できるので前向きになれました!年々、新しいことに取り組むやる気が落ちている悩みが、、それはまた別の機会に!
改修内容
簡単に言うとWebAPIの作成とバッチ処理の作成、2本立てです!ちなみにAWSのコンテナ上で動かす前提ですが、詳細の構成は割愛します。今回はアプリの実装面だけに絞った記事にします。
開発時の状態
インフラチームや私が作成した構成しかない状況。アプリの仕様は、都度、口頭で決まった内容をオンライン会議のドキュメントに記載してメモレベルでしか残っていませんでした。。ほかの部署でspringbootでサービスを作成していたのでソースを参考にさせてもらいました(WebAPI、バッチ両方とも)。これがなかったらマジでやばかった!!
開発の最初にやったこと
今回の案件の特徴としては、既存改修ではなく、新規開発ということでした!この世の中、非常に珍しい。なので既存ソースがない!自分でspringbootのプロジェクトを作成するところからがスタートでしたが、、私は、他の部署で動いているプロジェクトをコピーして中身をほとんど削除してそれをgithubのmasterにマージしましたwww良い子はマネしないで!とはいえ、どのソースを削除すればよいのか?削除しちゃいけないのかを判断するためにいろいろ勉強しました!
これは知っておきたい!現場で使うspringbootの知識前提まとめ
私がspringbootの開発をやるときに知っておけばよかったな~と思ったことを書きます。
springはシングルトン!
はい!これは一番重要!springでは@Componentや@Serviceで登録したクラスを1度だけインスタンス化して、あとはそのクラスが必要になったら使いまわし(共有)する設計になっています。テストに出ます!www
じゃあ、これを意識しないと何が起こるのかを説明します。以下のソースのようにインスタンス変数を持たせて、その値を変更するような操作がある場合です。この場合、同時にこの処理を呼び出したりすると関数の値が不整合を起こします。これさえ気を付ければ大きな問題は起こりません!一時的に変数を保持したい時はローカル変数か引数に持たせると安全です。
@Service
public class YokunaiService {
// ❌ 危険:インスタンス変数(フィールド)を持たせている
private int count = 0;
public int increment() {
// 複数スレッドから同時に呼ばれると、countの値がおかしくなる(スレッドセーフではない)
count++;
return count;
}
}@Autowiredよりもコンストラクタインジェクション!
私もこれは知らなかった。でも常識らしい。@Autowiredは自動でインスタンス化するアノテーションです。
普通にspringbootの本やネット、AIに聞くと以下のような書き方をおすすめして来る時がありますが、これが駄目です!理由は、以下です!
finalが付けられない(不変性の欠如)。
単体テスト(JUnit)が書きにくい。
循環参照(AがBを欲しがり、BもAを欲しがる状態)に気づきにくい。
@Service
public class DamenaService {
@Autowired // ❌ 非推奨になりつつある書き方
private UserRepository userRepository;
@Autowired
private OrderRepository orderRepository;
}私個人としては単体テストがしにくいというのは、かなり身をもって感じました!最近はAIが単体テストしちゃうから関係なくなってきているかも。。寂しい。。ではどんな書き方が良いのかを以下に記載します。
@Service
public class YoiService {
// ⭕ finalを付けて、値が途中で変わらない安全な設計にする
private final UserRepository userRepository;
private final OrderRepository orderRepository;
// コンストラクタインジェクション
public OrderService(UserRepository userRepository, OrderRepository orderRepository) {
this.userRepository = userRepository;
this.orderRepository = orderRepository;
}
}Lombokを使うならさらにすっきりします。重要なのは@RequiredArgsConstructorです!
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor // 👈 これを付けるだけ!
public class LombokwotukattaService {
// final を付けたフィールドを自動で認識して、コンストラクタを裏で生成してくれる
private final UserRepository userRepository;
private final OrderRepository orderRepository;
public void processOrder() {
// 処理...
}
}書き方は違いますが、動きは全部同じです!
以上が現場で使うspringbootの前提知識まとめです!この知識を暗記して同僚と会話するだけで、あなたは少し開発できる人に思われるはず!私は当時知らなかった。。
springbootのWebAPIのソースを読むときにやるべきこと
基本的にJavaはパッケージ(jp.co.example的なドメインを逆にしたやつ)配下にソースを作成するので、どこに何があると断言できません。。なのであくまで一例なのであしからず、、
まず最初に見るべきはcontrollerフォルダの中のソースです!ここはリクエストを受けた時に最初に呼び出されるソースです!正直、WebAPIは、ここが出発なので、あとは処理を順番に追っていけば処理の流れが理解できると思います!
バッチ(springBatch)のソースを読むときにやるべきこと
まずはspringBatchの流れなどを説明しないとですね。springBatchはチャンクモデルとタスクレットモデルの2つありますが今回はチャンクモデルの説明になります。
springBatchはバッチを流すための機能ですが、構成的には、Jobが必ず1つあります。Jobは実行スケジュールやエラー時の再実行の制御を設定できます。実際の現場でJobに色々設定しているのは見たことありません。。次にStepです。Jobの中に複数のStepがあります。Stepを複数作成している現場も見たことありません。。Stepの中には読み込み(Reader)、加工(Processor)、書き込み(Writer)の3つありチャンクを単位にループします!具体的にはテーブルから10件ずつ取得するというときの10件ずつ処理することをチャンク指向というみたいです。

ここでは現場で特に改修が入りやすいと思われるReader、Processer、Writerに特化して説明します。現場でソースを見るときの参考にしてください。
Reader
以下のようなソースが目印です。以下のような、JobとStepを定義している箇所があるはずです。JpaPagingItemReader readerがReaderとして設定されています。あとはJpaPagingItemReaderを見るだけです!Readerは基本的に普通の@Componentなどに登録されたBeanになります。
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
@Configuration
public class BatchJobConfig {
@Bean
public Step userProcessStep(JobRepository jobRepository,
PlatformTransactionManager transactionManager,
JpaPagingItemReader<User> reader,
UserItemProcessor processor,
ItemWriter<UserDto> writer) {
return new StepBuilder("userProcessStep", jobRepository)
.<User, UserDto>chunk(10, transactionManager) // 👈 10件ごとにチャンク処理を実行
.reader(reader)
.processor(processor)
.writer(writer)
.build();
}
@Bean
public Job userImportJob(JobRepository jobRepository, Step userProcessStep) {
return new JobBuilder("userImportJob", jobRepository)
.start(userProcessStep)
.build();
}
}Processor
Processorを探すときは、ItemProcessorが目印です。このクラスをimplementsしている具象クラスを探せば対象が特定できます!
import org.springframework.batch.item.ItemProcessor;
import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Component
public class UserItemProcessor implements ItemProcessor<User, UserDto> {
@Override
public UserDto process(User user) throws Exception {
log.info("Processing user: {}", user.getName());
// 例: 特定の条件に合わないデータは null を返してスキップする
if (user.getEmail() == null || user.getEmail().isEmpty()) {
return null; // このデータはWriterへ渡されない
}
// 加工して新しいDTOに詰める
UserDto dto = new UserDto();
dto.setId(user.getId());
dto.setName(user.getName().trim());
dto.setEmail(user.getEmail().toLowerCase()); // メールアドレスを小文字化
return dto;
}
}Writer
WriterはReaderと同じです。JobとStepの設定している箇所を確認する必要があります。上の例のソースでいえば、ItemWriter writerがWriterに該当します。なのであとはこのクラスを探し出せばOKです!
import org.springframework.batch.item.Chunk;
import org.springframework.batch.item.ItemWriter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import lombok.extern.slf4j.Slf4j;
@Configuration
public class BatchWriterConfig {
@Bean
public ItemWriter<UserDto> writer() {
return new ItemWriter<UserDto>() {
@Override
public void write(Chunk<? extends UserDto> items) throws Exception {
log.info("Writing {} items to database...", items.size());
// items にはチャンクサイズ分のリストがまとめて入っている
for (UserDto dto : items) {
// 実際の保存処理(例: Repositoryを呼ぶなど)
// userRepository.save(...)
log.info("Saved: {}", dto.getEmail());
}
}
};
}
}まとめ
ということで、ここまで現場でspringbootを扱うときに気を付けることや注意を書いてきました!私が特に気づいてよかったことはspringはシングルトン、コンストラクトインジェクション、この2つです!この2つを知っているだけで玄人になれますwww
WebAPIは世の中に資料が多いので多分大丈夫w springBatchは意外と情報が少ないので自分で作って動かすことをおすすめします!でも現場ではそんな悠長なことを言ってられないこともあります!そんな時は、この記事にあるソースと似たような箇所を探してみてください!フレームワークを利用しないでやってきた人ほど、springbootのようなアノテーションや設定、命名に依存する作りに弱くソースを読むことすら難解な気がします。私もそうでした。。しかし、できます!適応力大事です!
関係ないのですがXのアカウントが乗っ取られてしまったので再作成しました。。今はこれです~ヒグッティ@システムエンジニア







