Spring Boot勉強メモ

Jul 21, 2016 ( Oct 3, 2016 更新 )

※ Spring Bootのバージョンは1.4.0-RC1

Gradle

Getting Started · Building Java Projects with Gradleを参照した。

オプション

  • compile
  • providedCompile
    • JavaServlet APIのように、compileには必要だが実行時には必要ない依存関係
  • testCompile
    • テスト時のみ必要な依存関係

jar section

jar {
  baseName = 'gs-gradle'
  version =  '0.1.0'
}

この場合出力されるJarはgs-gradle-0.1.0.jarになる。

gradle wrapper

gradelには、gradleコマンドがなくても、gradleプロジェクトのビルドができる実行スクリプトを生成する機能がある。 build.gradleには以下のように設定を追記し

task wrapper(type: Wrapper) {
    gradleVersion = '2.3'
}

gradle wrapperを実行する。

warをつくる

To bundle up dependencies requires more thought. For example, if we were building a WAR file, a format commonly associated with packing in 3rd party dependencies, we could use gradle’s WAR plugin. If you are using Spring Boot and want a runnable JAR file, the spring-boot-gradle-plugin is quite handy. At this stage, gradle doesn’t know enough about your system to make a choice. But for now, this should be enough to get started using gradle.

  • warを作るには、すべてのdependeciesを含める必要がある
  • Spring Bootの実行可能jarを作るには、spring-boot-gradle-pluginがあるので便利

plugins

ビルド時に必要なbinary pluginsのdependeciesは以下のように設定することができる。

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath group: 'commons-codec', name: 'commons-codec', version: '1.2'
    }
}

grade buildするとdependecies解決されるので、pluginsが有効になる。

spring-boot-plugin

spring-boot-pluginがやること:

  • classpathのjarを1つにまとめて実行可能なjarにする
  • public static void main()をrunnable clsssにする
  • Spring Bootのdependeciesの自動解決

REST applicationをつくる

package hello;

import java.util.concurrent.atomic.AtomicLong;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class GreetingController {

    private static final String template = "Hello, %s!";
    private final AtomicLong counter = new AtomicLong();

    @RequestMapping("/greeting")
    public Greeting greeting(@RequestParam(value="name", defaultValue="World") String name) {
        return new Greeting(counter.incrementAndGet(),
                            String.format(template, name));
    }
}
  • @RequestMapping(method=GET) でmethodを指定することができる
  • @RequestParamはquery string
  • objectをreturnすると、Spring BootのHTTP Message Supportにより、MappingJackson2HttpMessageConverterが自動で実行されGreetingクラスのinstanceは自動でJSON objectに変換される。

Embded tomcat servblet container

  • Spring BootはTomcatのservlet containerを組み込み、実行可能なHTTP runtimeを作成する

gradlew bootRun

gradlew bootRun

DB操作関連

SQL発行

  • @Repository はJPAの仕様
  • @Query はSpring BootのAnnotation

Spring Data JPA - Reference Documentation

Working with Spring Data Repositories によると、

  • Spring Data Repositoryのコンセプトは以下
    • XMLの namespace declaration と、 typesをJavaのmoduleっぽく扱う?とのこと
  • queryをmethod名で発行できる機能がある。表はここにある

JPA互換method

JPAの仕様どおりに作っていくやり方は以下。

public interface UserRepository extends Repository<User, Long> {

  List<User> findByEmailAddressAndLastname(String emailAddress, String lastname);
}
// findByEmailAddressAndLastname method will execute thisquery:
// select u from User u where u.emailAddress = ?1 and u.lastname = ?2

queryの戻り値の型はSupported query return typesを使うことができる。

戻り値はStrem型を使うこともできる。 try-catchすることもできる。

try (Stream<User> stream = repository.findAllByCustomQueryAndStream()) {
  stream.forEach();
}

Spring Data JPA - Reference Documentation

@Query

Spring Data JPA - Reference Documentation

@Repository
public interface UserRepository extends JpaRepository<User, Long> {

    @Query("SELECT x FROM User x WHERE x.account = :account")
    User findByAccount(@Param("account") String account);

    @Query("SELECT x FROM User x WHERE x.id = :id")
    User findByIdWithRooms(@Param("id") Long id);

}

SpringのDependency Injectionについて

Springのドキュメント中のDependenciesのセクションに説明がある。

@Bean annotationを使う場合

以下のサンプルコードがわかりやすかった。

Spring and Java Thread example

公式ドキュメントのTaskExecutorを使う場合の例ではXMLファイルを使ってthread pool数などの設定をしている。 これと同じことを@Configuration annotation, @Bean annotationでも行うことができる。

以下のように@Configuration annotationをつけたクラスを用意する。

// AppConfig.java
package com.mkyong.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

@Configuration
@ComponentScan(basePackages = "com.mkyong.thread")
public class AppConfig {

    @Bean
    public ThreadPoolTaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor pool = new ThreadPoolTaskExecutor();
        pool.setCorePoolSize(5);
        pool.setMaxPoolSize(10);
        pool.setWaitForTasksToCompleteOnShutdown(true);
        return pool;
    }

}

上記の例では、ThreadPoolTaskExecutorのBeansを宣言している。 poolというThreadPoolTaskExecutorを定義し、corePoolSizeなどをpublic method経由で設定している。

この設定はApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);のようにして呼び出し元から呼び出すことができる。

※ この呼出も、annotationによってSpringがやってくれる気がするので後でやり方がわかったら追記する。

package com.mkyong;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import com.mkyong.config.AppConfig;
import com.mkyong.thread.PrintTask2;

public class App {
  public static void main(String[] args) {

    ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
    ThreadPoolTaskExecutor taskExecutor = (ThreadPoolTaskExecutor) context.getBean("taskExecutor");

    PrintTask2 printTask1 = (PrintTask2) context.getBean("printTask2");
    printTask1.setName("Thread 1");
    taskExecutor.execute(printTask1);

   // 省略
}

@Configuration @ComponentScan(“パッケージ名”) について

@Configuration

@Configuration annotationは、@Beamメソッドが定義されていることを示している。 @BeanメソッドはSpring Containerによって処理され、実行時にbean定義とサービスの登録が行われる。

@ComponentScan(basePackage)というannotationがある。 こちらは、@Configuration annotationと一緒に使われる。 basePackageで指定したパッケージのcomponentをスキャンする。 このannotationはannotation config processing(e.g. @Autowired)と一緒に使われることを想定されている。

@Configuration
@ComponentScan("com.acme.app.services")
public class AppConfig {
// various @Bean definitions ...
}

ComponentScan (Spring Framework 4.3.2.RELEASE API)

@Configuration@Componentを後からannotatedされている。そのため、@Configurationクラスはcomponent-scanningの対象となっている。 そのため、@Autowired/@Injectをfiledやmethodレベルで利用することもある。

@Configurationクラスはcomponent-scanningだけによりbootstrappedされるわけではないdesdes自分自身を設定するために@ComponentScan annotationを使うことができる。(上記コード参照)

以下のようにapplication.propertiesなどの外部ファイルから設定を注入できるようにもなる。

@Configuration
@PropertySource("classpath:/com/acme/app.properties")
public class AppConfig {

    @Inject Environment env;

    @Bean
    public MyBean myBean() {
        return new MyBean(env.getProperty("bean.name"));
    }
}
@Configuration
@PropertySource("classpath:/com/acme/app.properties")
public class AppConfig {

    @Value("${bean.name}") String beanName;

    @Bean
    public MyBean myBean() {
        return new MyBean(beanName);
    }
}

これらの他、いろいろなサンプルは以下のドキュメント中にある。

Configuration (Spring Framework 4.3.2.RELEASE API)

Task executorについて

34. Task Execution and Scheduling

  • Spring frameworkは、TaskExecutorTaskSchedulerという抽象レイヤを持っている
  • TaskExecutorはJavaのjava.util.concurrent.Executorと同じインターフェースをもつ
  • TaskExecutorは、他のSpring componentsにスレッドプールが必要な箇所の抽象化のためにつくられる

TaskExecutorインターフェースについて

TaskExecutorの実装はすでに複数ある。 用途に合わせて用意されている実装を使っていけばよさそう。

以下は使いそうな実装。

  • ThreadPoolTaskExecutor
    • most commonly used oneとのこと
    • java.util.concurrent.ThreadPoolExecutorの設定をbeanでできる
    • 違う種類のjava.util.concurrent.Executorを使いたい場合は下記のConcurrentTaskExecutorを使うことを推奨している
  • ConcurrentTaskExecutor
    • Executorのconfiguration parameterをbeanとして与えられる

以下はTaskExecutorの実行サンプル。 サンプルコード

import org.springframework.core.task.TaskExecutor;

public class TaskExecutorExample {

    private class MessagePrinterTask implements Runnable {

        private String message;

        public MessagePrinterTask(String message) {
            this.message = message;
        }

        public void run() {
            System.out.println(message);
        }

    }

    private TaskExecutor taskExecutor;

    public TaskExecutorExample(TaskExecutor taskExecutor) {
        this.taskExecutor = taskExecutor;
    }

    public void printMessages() {
        for(int i = 0; i < 25; i++) {
            taskExecutor.execute(new MessagePrinterTask("Message" + i));
        }
    }

}

以下のようにコードを書く。

  1. 実行したいRunnableインターフェースを実装したクラス(MessagePrinterTask)を作成する
  2. TaskExecutor.executeを実行するクラス(TaskExecutorExample)を作成する
  • コンストラクタではクラスメンバにTaskExecutorを持つ
  • publicなメソッド(printMessages)を実装する。内部ではTaskExecutor.execute(new RunnableImpl())する

このコードではスレッドプールからスレッドを取得するような実装がない。 スレッドプールをどのように使うかは外部の設定を利用する。 以下はbean propertiesでスレッドプールの設定を書く場合の例。

<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
    <property name="corePoolSize" value="5" />
    <property name="maxPoolSize" value="10" />
    <property name="queueCapacity" value="25" />
</bean>

<bean id="taskExecutorExample" class="TaskExecutorExample">
    <constructor-arg ref="taskExecutor" />
</bean>

daemonのように常時起動させておきたい場合

  • Runnableクラス内でwhile(true)すればよい??

TaskShedulerインターフェースについて

※ threadで実行した処理を待つ処理をFuture (Java Platform SE 8 )を使って書くことができる

Schedule実行できるTaskSchedulerというインターフェースも用意されている。

public interface TaskScheduler {
    // 1度だけ実行
    ScheduledFuture schedule(Runnable task, Date startTime);

    // 繰り返し実行
    ScheduledFuture schedule(Runnable task, Trigger trigger);
    ScheduledFuture scheduleAtFixedRate(Runnable task, Date startTime, long period);
    ScheduledFuture scheduleAtFixedRate(Runnable task, long period);
    ScheduledFuture scheduleWithFixedDelay(Runnable task, Date startTime, long delay);
    ScheduledFuture scheduleWithFixedDelay(Runnable task, long delay);
}

Triggerインターフェース

Triggerインターフェースは以下のようなコンセプト。 詳細はドキュメント参照

  • Triggerは実行時間をあらわす
  • この実行時間は、過去のタスク実行の結果や、任意の条件にもとづく

スケジューリングと非同期実行のためのannotation support

スケジューリングと非同期実行のためのAnnotationが用意されている。 @Sheduled, @Asyncというものがある。これらを有効にするには、@EnableScheduling@EnableAsync@configurationクラスに追加する。

@Scheduledが必要なときは@EnableSchedulingのみ、@Asyncが必要なときは@EnableAsyncのみでよい。

@Configuration
@EnableAsync
@EnableScheduling
public class AppConfig {
}

@Scheduled annotation

@Scheduled annotationはtriggerのmetadataと一緒に指定することができる。

@Scheduled(fixedDelay=5000)
public void doSomething() {
    // something that should execute periodically
}

@Async annotation

@ScheduledメソッドがSpring Bootのコンテナから呼ばれるのに対し、@Asyncメソッドは通常の呼ばれ方(どこか別のモジュールから呼ばれる)をする。 そのため、以下のように引数を取ることができる。

@Async
void doSomething(String s) {
    // this will be executed asynchronously
}

また、@Asyncメソッドはreturnで値を返すこともできる。しかし、非同期処理なのでreturnするtypeはFutureでなければいけない。 このようにすることで、@AsyncメソッドのcallerはFutureのget()を使う前に他のタスクを処理することができる。

@Async
Future<String> returnSomething(int i) {
    // this will be executed asynchronously
}

あまり詳しくないが、SpringではBeanの初期化にlife cycleがあるとのこと。 Beanのinitializerに@PostConcurrentのような、life cycleによって実行するタイミングを変えるためのannotationをつけている場合は、@PostConcurrentメソッド中に実行された@Asyncメソッドも非同期で実行される。

public class SampleBeanImpl implements SampleBean {

    @Async
    void doSomething() {
        // ...
    }

}

public class SampleBeanInitializer {

    private final SampleBean bean;

    public SampleBeanInitializer(SampleBean bean) {
        this.bean = bean;
    }

    @PostConstruct
    public void initialize() {
        bean.doSomething();
    }

}

@AsyncメソッドでExecutorの証明をする

@Asyncメソッドを実行するexecutorのデフォルトは、XML configuration中で指定されるannotation-driven中で設定する。

<task:annotation-driven executor="myExecutor" scheduler="myScheduler"/>
<task:executor id="myExecutor" pool-size="5"/>
<task:scheduler id="myScheduler" pool-size="10"/>

しかしながら、@Async annotation のvalueにExecutorの名前を指定することにより、デフォルト以外のExecutorを使うことも可能。 下記のコードの場合は、othreExecutor beanがSpring Containerに登録されている必要がある。

@Async("otherExecutor")
void doSomething(String s) {
    // this will be executed asynchronously by "otherExecutor"
}

外部ファイル(YAML)に設定を書く

ドキュメントは以下。

24. Externalized Configuration

Spring Bootアプリケーションは、外部ファイルに設定を持つことができる。 設定ファイル中のpropertyには@Value annotationでアクセスすることができる。 この@Value annotationはSpringのEnvironmentという抽象レイヤによりアクセスされる。また、@ConfigurationPropertiesによって[structured object](24. Externalized Configuration http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-typesafe-configuration-properties)に関連づけられる。

Springは(Javaで?)特別なPropertySourceというオーダーを使っている。 これは値のsensible overridingを許すように設計されている。 Propertiesはここの順番の通りに読まれる

例えば、以下のように@Value annotationを設定した場合、上記の順番でpropertyを探しに行く。

import org.springframework.stereotype.*
import org.springframework.beans.factory.annotation.*

@Component
public class MyBean {

    @Value("${name}")
    private String name;

    // ...

}

application.propertiesというファイルをjarのclasspathに持っていると、このファイルからsensibleなpropertyのデフォルト値を読み込ませることができる。 SpringApplicationapplication.propertiesを読み込み、SpringのEnvironmentにloadしている。 application.propertiesのファイルパスはこの順に探される。

application.propertiesという設定ファイル名以外を使いたい場合は、以下のように設定値をコマンドラインから指定することもできる。

$ java -jar myproject.jar --spring.config.name=myproject
$ java -jar myproject.jar --spring.config.location=classpath:/default.properties,classpath:/override.properties

profile specificな設定ファイル

application-{profile}.propertiesという名前のpropertiesファイルを作ることができる。 Environmentはactiveなprofileがない場合はdefaultのpropertiesを読み込む。(application-default.properties

profile specificな設定はapplication.properties内に含めることができる。 ただし、profile-specificなpropertiesファイルは、application.propertiesファイルを上書きする。これは、profile-specificなpropertiesファイルがjarの外にあっても中にあっても同じ。

複数のprofileがある場合は最後の1つが有効になる。 例えば、spring.profiles.activeにより指定されたprofileSpringApplication APIで指定したものより後に追加される。

YAMLでの設定

以下のようにYAMLで設定を書いて、

my:
   servers:
       - dev.bar.com
       - foo.bar.com

@Value("${property}")でpropertyを読み込むやり方は、複数のpropertyを扱ったり、データ構造が階層構造になっている場合には面倒である。 @ConfigurationProperties(prefix="my")で指定のキー以下のpropertyにJavaのオブジェクトとしてアクセスすることができる。

@ConfigurationProperties(prefix="my")
public class Config {

    private List<String> servers = new ArrayList<String>();

    public List<String> getServers() {
        return this.servers;
    }
}

@Valueを使う場合と@ConfigurationPropertiesを使う場合の比較はドキュメントのここで説明されている。 Spring Boot的には@ConfigurationPropertiesを使ったPOJO推奨。

また、@ConfigurationPropertiesを使ってpropertyを定義した場合には、@EnableConfigurationProperties@Config annotationをつけたConfigクラスにつける必要がある。

@Configuration
@EnableConfigurationProperties(ConnectionProperties.class)
public class MyConfiguration {
}

@ConfigurationPropertiesを使うと、以下のように設定をSpring BootのBeanと同様にinjectすることができる。

@Service
public class MyService {

    private final ConnectionProperties connection;

    @Autowired
    public MyService(ConnectionProperties connection) {
        this.connection = connection;
    }

     //...

    @PostConstruct
    public void openConnection() {
        Server server = new Server();
        this.connection.configure(server);
    }

}

relaxed binding

-などで区切ったpropertyのキーもマッチさせることができる。


@ConfigurationProperties(prefix="person")
public class OwnerProperties {

    private String firstName;

    public String getFirstName() {
        return this.firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

}

上記の場合は、以下のproperty keyにマッチする。

  • person.firstName
  • person.first-name
  • person.first_name
  • PERSON_FIRST_NAME
    • 環境変数など

validation

@ConfigurationPropertiesで設定した値に対してJSR-303のvalidationを利用することができる。 nestedなものに対しては、親で@Validをつける必要がある。

@ConfigurationProperties(prefix="connection")
public class ConnectionProperties {

    @NotNull
    @Valid
    private RemoteAddress remoteAddress;

    // ... getters and setters

    public static class RemoteAddress {

        @NotEmpty
        public String hostname;

        // ... getters and setters

    }
}

テストの書き方

下記ドキュメントにガイドがある。

40. Testing

とりあえずspring-boot-starter-testを dependenciesに追加しておけば、よくテストで使うライブラリと一緒にビルドしてくれるので、これだけ書いておけばよさそう。

IntelliJ IDEAの設定

lumbokで動的に追加されたメソッドの参照は以下の設定をする必要がある

  • Build -> annotation processerをenabled
  • lumbokプラグインを有効にする

Lumbokについて

トップページのビデオを見るとわかりやすいが、Lumbokのモチベーション・メリットは以下のように説明できる。

  • Javaでよくあるbeansやデータを表すクラスを作るとき、お決まりのboilerplate patternというものがある
    • class property + getter()/setter()
    • toString()
    • などなど
  • IDEである程度作成コストは削減できるものの、煩雑すぎて作ったクラスを見てもそれがbeansなのか何か特別なクラスなのかひと目でわかりづらい
  • Lumbokのアノテーション(@Dataなど)をつけると、お決まりのメソッドを動的に生成してくれる
    • IDEでもサポートされていれば、補完がきく

@Data

コマンドラインアプリケーションをつくる

下記のように実行可能jarをgradle buildで作成することができる。

Spring batchについて

メモ

  • Sheduledジョブの場合
    • Spring Batchでつくる
    • Scheduledにするかどうかはpropertiesで設定(おそらくコマンドラインからもいれられるはず)
  • daemonジョブの場合
    • ThreadPoolTaskExecutorにより実行
    • 実行は@Autowired AppplicationContext contextしてcontexte.getBean("myService")してmyService.runするイメージ(workman内のファイル参照)

Spring Batchを使った場合の利点

おそらく、以下のutilが用意されているのがいいところっぽい。

  • readerやwriter
    • 大量のデータを少しずつ処理する
  • 上記のtransaction管理
  • 例外発生時の再処理とか(要調査)

Spring Batch Getting Started memo

以下の処理をするバッチジョブを作成する例が載っている。

Getting Started · Creating a Batch Service http://spring.io/guides/gs/batch-processing/

  • CSVファイルを順次読み込み
  • 変換
  • 変換結果をDBに保存

1. データ準備

CSVファイルとDBのCREATE文SQLを用意する。

2. ビジネスクラスの作成

PersonというBeanクラスを作る

3. intermediate processorをつくる

batch processingの範例(paradigm)は以下のとおり

  • データを取得する
  • 変換する
  • 別の場所(処理)へpipeする

以下はnamesをuppercaseに変換するtransfer

package hello;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.batch.item.ItemProcessor;

public class PersonItemProcessor implements ItemProcessor<Person, Person> {

    private static final Logger log = LoggerFactory.getLogger(PersonItemProcessor.class);
    
    @Override
    public Person process(final Person person) throws Exception {
        final String firstName = person.getFirstName().toUpperCase();
        final String lastName = person.getLastName().toUpperCase();
        
        final Person transformedPerson = new Person(firstName, lastName);
        
        log.info("Converting (" + person + ") into (" + transformedPerson + ")");
        
        return transformedPerson;
    }

}

JPA/Spring Data JPAについて

JPAはJava EEで使われているdata wrapper。ORMなどを提供している。

Entity

Entity = tableの対応になる。 @Tableでtable名を指定できるが、省略した場合はクラス名をすべて大文字にしたテーブルへマッピングされる

@Table(name = "user")
class User {
  // ...省略
}

テーブルの関連性

@OneToOneをつけたときに参照されるテーブルのカラム名の規則を知りたい。 とりあえず以下のような関連の記述で動いた。。。

@Data
@Entity
@Table(name="user_settings")
@EqualsAndHashCode( of = {"id"} )
public class UserSettings {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @OneToOne
    private User user;

    @Column(nullable = false)
    private Boolean offlineNotificationEnabled;

    public UserSettings(User user) {
        this.user = user;
        this.offlineNotificationEnabled = true;
    }
}
@Data
@Entity
@Table(name="users")
@EqualsAndHashCode( of = {"id"} )
public class User {

// 省略...

    @OneToOne(mappedBy = "user", cascade = CascadeType.ALL)
    private UserSettings userSettings;

    public User( String account, String passwordHash, String name, String imageUrl ) {
        this.account = account;
        this.passwordHash = passwordHash;
        this.name = name;
        this.imageUrl = imageUrl;

        this.userSettings = new UserSettings(this);
    }
}
CREATE TABLE user_settings
(
    id BIGINT(20) PRIMARY KEY NOT NULL AUTO_INCREMENT,
    user_id BIGINT(20) NOT NULL,
    offline_notification_enabled TINYINT(1) DEFAULT '1' NOT NULL
);
CREATE TABLE users
(
    id BIGINT(20) PRIMARY KEY NOT NULL AUTO_INCREMENT,
    account VARCHAR(32) NOT NULL,
    name VARCHAR(64),
    password_hash VARCHAR(64),
    image_url VARCHAR(256),
    resource_path VARCHAR(256),
    created_at TIMESTAMP DEFAULT 'CURRENT_TIMESTAMP' NOT NULL,
    updated_at TIMESTAMP DEFAULT 'CURRENT_TIMESTAMP' NOT NULL
);

Spring Data JPA

EntityはEntityManagerに管理される。 EntityManagerは、PersistentContextというEntityを管理する領域を持っている。 このPersistentContextは、トランザクション単位で生成される。そのため、別transaction中で処理されているEntityが見えてしまうことはない。 EntityManagerは、Entityへのアクセスを要求されると、このPersistentContextからデータを返却する。 また、EntityManagerは、必要に応じてPersistentContextのEntityとEDBとの同期を取る。 SQLが発行されるのは以下のタイミング:

  • transactionがcommitされた
  • アプリケーションから強制的にflushが呼び出された

雑に解釈すると、RDBのキャッシュ領域のようなものと言える。

Repository

DDDにおけるデータアクセス層、Repositoryをアノテーションとして提供している。

  • Entityを作成する
  • Entityに対応するRepository(インターフェース)を作成する
    • Springが内部でEntityManagerを呼び出す
RoomService -(call)-> RoomRepositoryProxy(Spring Data JPAが生成) -(実装)-> RoomRepository -(継承)-> JpaRepository <-(実装)- SimpleJpaRepositorty -(呼び出し)-> EntityManager

Spring BootじゃなくてJava関連のメモ

  • daemon的なthreadを作りたいときは、単にwhile(true)していても性能問題にはならない
    • ただしwhile内でCPUを使うような処理をしていたら、(当たり前だが)その分CPUを持っていかれる
    • threadなのでブロックしない?IOはブロックする気がする
  • threadの状態を

調べたいこと

  • 常に決まった数だけthreadを立ち上げてwhile(true)で待ち受ける場合はどうするのがいいのか考える
  • TaskExecutorごとに別のthread poolを持てるのか?
    • while(true)でRunnableを常時動かしておきたいTaskExecutorがあるが、これとは別にTaskSchedulerもおり、こちらで使うthread poolのthreadをTaskExecutorに食いつぶされたくない場合

詰まったところメモ

Access to DialectResolutionInfo cannot be null when 'hibernate.dialect' not set

単にDBが落ちてただけだった

テスト実行時にLombokのannotationでcannnot find symbolと言われる

下記のページを参考に、lombokのバージョンを指定

Building with Lombok’s @Slf4j and Intellij: Cannot find symbol log - Stack OverflowBuilding with Lombok’s @Slf4j and Intellij: Cannot find symbol log - Stack Overflow

    compileOnly "org.projectlombok:lombok:${lombokVersion}"

JPA + jacksonで Infinite recursion (StackOverflowError)

java - Infinite Recursion with Jackson JSON and Hibernate JPA issue - Stack Overflow

Retrun to top