スプリングイニシエータ配置設計
67629 ワード
スプリングイニシエータ配置設計
上記のスプリングガイド配置構成部品を使用して、コミュニティサイトに登録されているメンバーの1年後も状態が変わらないメンバーを人間のメンバーに変換するための展開例コードを作成しました.
技術規格は以下の通りである。
展開プロセス全体
ハンドラ
ItemReaderを使用して、
1. build.grade依存性の設定
buildscript {
ext {
springBootVersion = '2.3.0.RELEASE'
gradle_node_version='2.2.4'
}
repositories {
mavenCentral()
maven {
url "https://plugins.gradle.org/m2/"
}
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
subprojects {
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
group = 'com.junyoung'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
repositories {
mavenCentral()
}
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
dependencies {
compile('org.springframework.boot:spring-boot-starter-batch')
runtime('com.h2database:h2')
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
testCompile group: 'junit', name: 'junit', version: '4.12'
testCompile('org.springframework.batch:spring-batch-test')
}
test {
useJUnitPlatform()
}
}
1.ドメインの作成
まず、ヒトメンバーのバッチを処理するドメインを作成します.オブジェクト名はUserで、人間かどうかを識別するためにUserStatus Enumが追加されました.ACTIVEは活動メンバー、INACTIVEは人間関係メンバーです.
UserStatus(会員アクティブ状態)
public enum UserStatus {
ACTIVE, INACTIVE;
}
Grade(会員レベル)
public enum Grade {
VIP, GOLD, FAMILY;
}
ユーザードメインオブジェクト
@NoArgsConstructor
@Entity
@Table
public class User implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long idx;
@Column
private String name;
@Column
private String password;
@Column
private String email;
@Column
private String principle;
@Column
@Enumerated(EnumType.STRING)
private SocialType socialType;
@Column
@Enumerated(EnumType.STRING)
private UserStatus status;
@Column
@Enumerated(EnumType.STRING)
private Grade grade;
@Column
private LocalDateTime createdDate;
@Column
private LocalDateTime updatedDate;
@Builder
public User(String name, String password, String email, String principle,
SocialType socialType, UserStatus status, Grade grade, LocalDateTime createdDate,
LocalDateTime updatedDate) {
this.name = name;
this.password = password;
this.email = email;
this.principle = principle;
this.socialType = socialType;
this.status = status;
this.grade = grade;
this.createdDate = createdDate;
this.updatedDate = updatedDate;
}
public User setInactive() {
status = UserStatus.INACTIVE;
return this;
}
}
ユーザー・レポート・ライブラリ
public interface UserRepository extends JpaRepository<User, Long> {
List<User> findByUpdatedDateBeforeAndStatusEquals(LocalDateTime localDateTime, UserStatus status);
}
findByUpdatedDateBeforeAndStatusEquals()
メソッドは、パラメータ値でLocalDateTime、すなわち1年前の日付値を受信し、現在の標準日付値としてユーザ状態タイプでクエリーを実行します.2.人的資源配置Jobの設置
まず、以下に示すように、スプリングガイドを実行する「Batch Application」ファイルで
@EnableBatchProcessing
を有効にする必要があります.@EnableBatchProcessing
@SpringBootApplication
public class BatchApplication {
public static void main(String[] args) {
SpringApplication.run(BatchApplication.class, args);
}
}
バッチを事前に登録して使用するには、EnableBatchProcessing
を適用する必要があります.以下の@Configurationアクションを使用する設定クラスで、展開情報を空に登録します.
@Slf4j
@RequiredArgsConstructor
@Configuration
public class InactiveUserJobConfig {
private final UserRepository userRepository;
private final JobBuilderFactory jobBuilderFactory;
private final StepBuilderFactory stepBuilderFactory;
@Bean
public Job inactiveUserJob() {
// (1) JobBuilderFactory 주입
return jobBuilderFactory.get("inactiveUserJob3")
// (2) Job의 재실행 방지
.preventRestart()
.start(inactiveJobStep(null))
.build();
}
}
@Slf4j
@RequiredArgsConstructor
@Configuration
public class InactiveUserJobConfig {
@Bean
public Step inactiveJobStep(@Value("#{jobParameters[requestDate]}") final String requestDate) {
log.info("requestDate: {}", requestDate);
// (1) StepBuilderFactory 주입
return stepBuilderFactory.get("inactiveUserStep")
// (2) chunk 사이즈 입력
.<User, User>chunk(10)
// (3) reader, processor, writer를 각각 설정
.reader(inactiveUserReader())
.processor(inactiveUserProcessor())
.writer(inactiveUserWriter())
.build();
}
}
inactiveUserStep
というStep Builderを作成します.3.Chungガイド処理
ここで...Chungって何ですか?
Chunkは、Spring Batchで各コミット間で処理されるローの数を表すブロックです.Chunk処理を使用しない場合、データベースは1000個のデータを読み出してバッチ処理を行う可能性があります.
バッチ処理中に1つのデータが格納されている場合、残りの999個のデータを
rollback
で処理する必要がある.これらの問題を回避するために、Chunk 지향 프로세스
の方法でスプリングガイド上の展開をサポートする.실패하는 경우 해당 Chunk 만큼 롤백이 되고, 이전에 커밋된 트랜잭션 범위까지는 반영이 된다는 것입니다.
は、Chung単位のトランザクションです.Chunkはスプリングガイド配置をより良く使用するために理解しなければならない概念である.
次のサンプルコードは、Javaコードを使用して、
jojoldu님
がこのブログにインポートしたChung向けの処理を表す.for (int i = 0; i < totalSize; i += chunkSize) {
List<Item> items = new ArrayList<> ();
for (int j = 0; j < chunkSize; j++) {
Object item = itemReader.read();
Object processedItem = item.Processor.process(item);
items.add(processedItem);
}
itemWriter.write(items);
}
Chunk単位でreader、process、writerとみなされるため、chunkSizeが10の場合、プロセスまたはwriteに異常が発生すると、すべてロールバックされ、バッチがchunkSizeで処理されます.ブログ参照 4.ItemReaderの実装
インターフェース
ItemReader(데이터를 읽어오는 역할)
.ここでは,ItemReaderインタフェースを実装するQueueItemReader実装に戻る.@Slf4j
@RequiredArgsConstructor
@Configuration
public class InactiveUserJobConfig {
private final UserRepository userRepository;
private final JobBuilderFactory jobBuilderFactory;
private final StepBuilderFactory stepBuilderFactory;
@Bean
@StepScope // (1) Step의 주기에 따라 새로운 빈 생성
public QueueItemReader<User> inactiveUserReader() {
List<User> oldUsers =
userRepository.findByUpdatedDateBeforeAndStatusEquals(
LocalDateTime.now().minusYears(1), UserStatus.ACTIVE);
return new QueueItemReader<>(oldUsers);
}
}
@StepScope
を使用すると、このメソッドはステップサイクルに従って新しい空を作成します.これは、各ステップの実行によって新しい空が作成されることを意味し、지연 생성
を使用することができる.@Step Scopeは、デフォルトのプロキシ・モードのクラス・タイプを参照して返すため、@StepScope를 사용하면 반드시 구현된 반환 타입을 명시해 반환해야 합니다.
の例では、Step ScopeはそれをQueueItemReaderと命名する.findByUpdatedDateBeforeAndStatusEquals()
メソッドは、ユーザのステータス値がACTIVE(現在の日付の1年前の日付値に基づく)であるユーザリストを問合せ、QueItemReaderオブジェクトを作成する際にパラメータとしてQueueに格納する.QueueItemReader
public class QueueItemReader<T> implements ItemReader<T> {
private Queue<T> queue;
public QueueItemReader(List<T> data) {
this.queue = new LinkedList<>(data);
}
@Override
public T read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {
return this.queue.poll();
}
}
上記のコードでは、QueItemReaderを使用してターゲットデータを一度にロードし、キューに入れます.次にread()メソッドを呼び出すと、キューのpoll()メソッドを使用してキューから1つ以上のデータが返されます.
5.ItemProcessorの実装
@Slf4j
@RequiredArgsConstructor
@Configuration
public class InactiveUserJobConfig {
...
public ItemProcessor<User, User> inactiveUserProcessor() {
return new ItemProcessor<User, User>() {
@Override
public User process(User user) throws Exception {
return user.setInactive();
}
};
}
}
ItemReaderから読み込んだユーザを人間の状態に変換するプロセッサメソッドの例を追加します.6.ItemWriterの実装
@Slf4j
@RequiredArgsConstructor
@Configuration
public class InactiveUserJobConfig {
...
public ItemWriter<User> inactiveUserWriter() {
return ((List<? extends User> users) -> userRepository.saveAll(users));
}
}
ヒトメンバー変換デプロイメント処理最終コード
@Slf4j
@RequiredArgsConstructor
@Configuration
public class InactiveUserJobConfig {
private final UserRepository userRepository;
private final JobBuilderFactory jobBuilderFactory;
private final StepBuilderFactory stepBuilderFactory;
@Bean
public Job inactiveUserJob() {
return jobBuilderFactory.get("inactiveUserJob3")
.preventRestart()
.start(inactiveJobStep(null))
.build();
}
@Bean
public Step inactiveJobStep(@Value("#{jobParameters[requestDate]}") final String requestDate) {
log.info("requestDate: {}", requestDate);
return stepBuilderFactory.get("inactiveUserStep")
.<User, User>chunk(10)
.reader(inactiveUserReader())
.processor(inactiveUserProcessor())
.writer(inactiveUserWriter())
.build();
}
@Bean
@StepScope
public QueueItemReader<User> inactiveUserReader() {
List<User> oldUsers =
userRepository.findByUpdatedDateBeforeAndStatusEquals(
LocalDateTime.now().minusYears(1), UserStatus.ACTIVE);
return new QueueItemReader<>(oldUsers);
}
public ItemProcessor<User, User> inactiveUserProcessor() {
return new org.springframework.batch.item.ItemProcessor<User, User>() {
@Override
public User process(User user) throws Exception {
return user.setInactive();
}
};
}
public ItemWriter<User> inactiveUserWriter() {
return ((List<? extends User> users) -> userRepository.saveAll(users));
}
}
ItemWriterが受信したリストタイプはChunk 단위
です.Chunk単位が10に設定されているため、ユーザは10人の人間のメンバーを持ち、saveAll()メソッドを使用して一度にDBに保存します.SQL文を使用したテストデータの注入
SQLクエリーファイルを作成して実行し、実際の配置を実行する前にテストするデータを作成します.
デフォルトでは、/resourcesサブパスをインポートします.sqlファイルを作成すると、スプリングブート(正確にはHypernet)が実行されると、ファイルのクエリーが自動的に実行されます.
insert into user (idx, email, name, password, social_type, status, grade, created_date, updated_date) values (1001, '[email protected]', 'test1', 'test1', 'FACEBOOK', 'ACTIVE', 'VIP', '2016-03-01T00:00:00', '2018-03-01T00:00:00');
insert into user (idx, email, name, password, social_type, status, grade, created_date, updated_date) values (1002, '[email protected]', 'test2', 'test2', 'FACEBOOK', 'ACTIVE', 'VIP', '2016-03-01T00:00:00', '2018-03-01T00:00:00');
insert into user (idx, email, name, password, social_type, status, grade, created_date, updated_date) values (1003, '[email protected]', 'test3', 'test3', 'FACEBOOK', 'ACTIVE', 'VIP', '2016-03-01T00:00:00', '2016-03-01T00:00:00');
insert into user (idx, email, name, password, social_type, status, grade, created_date, updated_date) values (1004, '[email protected]', 'test4', 'test4', 'FACEBOOK', 'ACTIVE', 'GOLD', '2016-03-01T00:00:00', '2016-03-01T00:00:00');
insert into user (idx, email, name, password, social_type, status, grade, created_date, updated_date) values (1005, '[email protected]', 'test5', 'test5', 'FACEBOOK', 'ACTIVE', 'GOLD', '2016-03-01T00:00:00', '2016-03-01T00:00:00');
insert into user (idx, email, name, password, social_type, status, grade, created_date, updated_date) values (1006, '[email protected]', 'test6', 'test6', 'FACEBOOK', 'ACTIVE', 'GOLD', '2016-03-01T00:00:00', '2016-03-01T00:00:00');
insert into user (idx, email, name, password, social_type, status, grade, created_date, updated_date) values (1007, '[email protected]', 'test7', 'test7', 'FACEBOOK', 'ACTIVE', 'FAMILY', '2016-03-01T00:00:00', '2016-03-01T00:00:00');
insert into user (idx, email, name, password, social_type, status, grade, created_date, updated_date) values (1008, '[email protected]', 'test8', 'test8', 'FACEBOOK', 'ACTIVE', 'FAMILY', '2016-03-01T00:00:00', '2016-03-01T00:00:00');
insert into user (idx, email, name, password, social_type, status, grade, created_date, updated_date) values (1009, '[email protected]', 'test9', 'test9', 'FACEBOOK', 'ACTIVE', 'FAMILY', '2016-03-01T00:00:00', '2016-03-01T00:00:00');
insert into user (idx, email, name, password, social_type, status, grade, created_date, updated_date) values (1010, '[email protected]', 'test10', 'test10', 'FACEBOOK', 'ACTIVE', 'FAMILY', '2016-03-01T00:00:00', '2016-03-01T00:00:00');
insert into user (idx, email, name, password, social_type, status, grade, created_date, updated_date) values (1011, '[email protected]', 'test11', 'test11', 'FACEBOOK', 'ACTIVE', 'FAMILY', '2016-03-01T00:00:00', '2016-03-01T00:00:00');
実行結果
Before
After
「ヒトメンバー展開」を実行すると、UPDATE DATE列の値が現在のポイントから1年前に変更され、ステータス値がACTIVEのメンバーのステータス値がINAVTIVEに変更されたことがわかります.
参照:https://jojoldu.tistory.com/331?category=902551、https://github.com/young891221/Spring-Boot-Community-Batch
Reference
この問題について(スプリングイニシエータ配置設計), 我々は、より多くの情報をここで見つけました https://velog.io/@sa1341/스프링-부트-휴먼회원-배치-설계テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol