※ 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
- Gradle Plugins - Gradle User Guide Version 2.14.1
- Organizing Build Logic - Gradle User Guide Version 2.14.1
ビルド時に必要な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は、
TaskExecutor
とTaskScheduler
という抽象レイヤを持っている TaskExecutor
はJavaのjava.util.concurrent.Executor
と同じインターフェースをもつ- Executor (Java Platform SE 8)
execute(Runnable task)
メソッドを持つ
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));
}
}
}
以下のようにコードを書く。
- 実行したい
Runnable
インターフェースを実装したクラス(MessagePrinterTask
)を作成する 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のデフォルト値を読み込ませることができる。
SpringApplication
がapplication.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
により指定されたprofile
はSpringApplication
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
}
}
テストの書き方
下記ドキュメントにガイドがある。
とりあえず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でもサポートされていれば、補完がきく
コマンドラインアプリケーションをつくる
下記のように実行可能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