Skip to content

Instantly share code, notes, and snippets.

@irof
Last active March 18, 2023 01:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save irof/3906f3d4c4929440fb5b7ecd4f82f425 to your computer and use it in GitHub Desktop.
Save irof/3906f3d4c4929440fb5b7ecd4f82f425 to your computer and use it in GitHub Desktop.
自身をインジェクションして `@Transactional` を動作させるサンプル
package me.irof.suburi;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
@Component
class SuburiComponentObjectProvider {
private static final Logger logger = LoggerFactory.getLogger(SuburiComponentObjectProvider.class);
final ObjectProvider<SuburiComponentObjectProvider> selfProvider;
SuburiComponentObjectProvider(ObjectProvider<SuburiComponentObjectProvider> selselfProviderf) {
// ここで selfProvider.getObject() しちゃうと循環参照で起動エラーになってしまうので、ObjectProviderのまま持っておく。
// 同様にApplicationContextとかインジェクションしてgetBeanなどでも可。
this.selfProvider = selfProvider;
}
@Transactional
void method(String param) {
logger.info("method {}", param);
}
@EventListener
void context(ApplicationStartedEvent event) {
logger.info("event lister start: {}", event);
method("call direct");
selfProvider.getObject().method("call via ObjectProvider");
logger.info("event listener finish: {}", event);
}
}
package me.irof.suburi;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS) // これがポイント
@Component
class SuburiComponentProxy {
private static final Logger logger = LoggerFactory.getLogger(SuburiComponentProxy.class);
final SuburiComponentProxy self;
SuburiComponentProxy(SuburiComponentProxy self) {
this.self = self;
}
@Transactional
void method(String param) {
logger.info("method {}", param);
}
@EventListener
void context(ApplicationStartedEvent event) {
logger.info("event lister start: {}", event);
method("call direct");
self.method("call via Proxy");
logger.info("event listener finish: {}", event);
}
}
直接呼び出しのログの前後には何も出ていませんが、 `self` 経由のログの前後には `JdbcTransactionManager` のログが出ているのが見えます。
( `logging.level.org.springframework.jdbc.support.JdbcTransactionManager=debug` で起動)
トランザクション開始時にコネクションが取得されるため、HikariPoolの起動ログも初めてトランザクションを起動するここで出ています。(サンプルとしてはノイズだけどそのまま載せておきます。)
2023-03-17T21:22:15.835+09:00 INFO 82291 --- [ main] m.i.s.SuburiComponentObjectProvider : event lister start: org.springframework.boot.context.event.ApplicationStartedEvent[source=org.springframework.boot.SpringApplication@6b4fc2d1]
2023-03-17T21:22:15.836+09:00 INFO 82291 --- [ main] m.i.s.SuburiComponentObjectProvider : method call direct
2023-03-17T21:22:15.838+09:00 DEBUG 82291 --- [ main] o.s.jdbc.support.JdbcTransactionManager : Creating new transaction with name [me.irof.suburi.SuburiComponentObjectProvider.method]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
2023-03-17T21:22:15.839+09:00 INFO 82291 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2023-03-17T21:22:15.922+09:00 INFO 82291 --- [ main] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Added connection conn0: url=jdbc:h2:mem:bc222894-2aae-462e-b7fc-8cf879eaa94d user=SA
2023-03-17T21:22:15.922+09:00 INFO 82291 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
2023-03-17T21:22:15.924+09:00 DEBUG 82291 --- [ main] o.s.jdbc.support.JdbcTransactionManager : Acquired Connection [HikariProxyConnection@1872767282 wrapping conn0: url=jdbc:h2:mem:bc222894-2aae-462e-b7fc-8cf879eaa94d user=SA] for JDBC transaction
2023-03-17T21:22:15.925+09:00 DEBUG 82291 --- [ main] o.s.jdbc.support.JdbcTransactionManager : Switching JDBC Connection [HikariProxyConnection@1872767282 wrapping conn0: url=jdbc:h2:mem:bc222894-2aae-462e-b7fc-8cf879eaa94d user=SA] to manual commit
2023-03-17T21:22:15.926+09:00 INFO 82291 --- [ main] m.i.s.SuburiComponentObjectProvider : method call via ObjectProvider
2023-03-17T21:22:15.926+09:00 DEBUG 82291 --- [ main] o.s.jdbc.support.JdbcTransactionManager : Initiating transaction commit
2023-03-17T21:22:15.926+09:00 DEBUG 82291 --- [ main] o.s.jdbc.support.JdbcTransactionManager : Committing JDBC transaction on Connection [HikariProxyConnection@1872767282 wrapping conn0: url=jdbc:h2:mem:bc222894-2aae-462e-b7fc-8cf879eaa94d user=SA]
2023-03-17T21:22:15.926+09:00 DEBUG 82291 --- [ main] o.s.jdbc.support.JdbcTransactionManager : Releasing JDBC Connection [HikariProxyConnection@1872767282 wrapping conn0: url=jdbc:h2:mem:bc222894-2aae-462e-b7fc-8cf879eaa94d user=SA] after transaction
2023-03-17T21:22:15.928+09:00 INFO 82291 --- [ main] m.i.s.SuburiComponentObjectProvider : event listener finish: org.springframework.boot.context.event.ApplicationStartedEvent[source=org.springframework.boot.SpringApplication@6b4fc2d1]
2023-03-17T21:22:15.929+09:00 INFO 82291 --- [ main] me.irof.suburi.SuburiComponentProxy : event lister start: org.springframework.boot.context.event.ApplicationStartedEvent[source=org.springframework.boot.SpringApplication@6b4fc2d1]
2023-03-17T21:22:15.929+09:00 INFO 82291 --- [ main] me.irof.suburi.SuburiComponentProxy : method call direct
2023-03-17T21:22:15.929+09:00 DEBUG 82291 --- [ main] o.s.jdbc.support.JdbcTransactionManager : Creating new transaction with name [me.irof.suburi.SuburiComponentProxy.method]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
2023-03-17T21:22:15.929+09:00 DEBUG 82291 --- [ main] o.s.jdbc.support.JdbcTransactionManager : Acquired Connection [HikariProxyConnection@1274036206 wrapping conn0: url=jdbc:h2:mem:bc222894-2aae-462e-b7fc-8cf879eaa94d user=SA] for JDBC transaction
2023-03-17T21:22:15.929+09:00 DEBUG 82291 --- [ main] o.s.jdbc.support.JdbcTransactionManager : Switching JDBC Connection [HikariProxyConnection@1274036206 wrapping conn0: url=jdbc:h2:mem:bc222894-2aae-462e-b7fc-8cf879eaa94d user=SA] to manual commit
2023-03-17T21:22:15.929+09:00 INFO 82291 --- [ main] me.irof.suburi.SuburiComponentProxy : method call via Proxy
2023-03-17T21:22:15.929+09:00 DEBUG 82291 --- [ main] o.s.jdbc.support.JdbcTransactionManager : Initiating transaction commit
2023-03-17T21:22:15.929+09:00 DEBUG 82291 --- [ main] o.s.jdbc.support.JdbcTransactionManager : Committing JDBC transaction on Connection [HikariProxyConnection@1274036206 wrapping conn0: url=jdbc:h2:mem:bc222894-2aae-462e-b7fc-8cf879eaa94d user=SA]
2023-03-17T21:22:15.929+09:00 DEBUG 82291 --- [ main] o.s.jdbc.support.JdbcTransactionManager : Releasing JDBC Connection [HikariProxyConnection@1274036206 wrapping conn0: url=jdbc:h2:mem:bc222894-2aae-462e-b7fc-8cf879eaa94d user=SA] after transaction
2023-03-17T21:22:15.929+09:00 INFO 82291 --- [ main] me.irof.suburi.SuburiComponentProxy : event listener finish: org.springframework.boot.context.event.ApplicationStartedEvent[source=org.springframework.boot.SpringApplication@6b4fc2d1]

SuburiComponentProxy.java@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS) を指定しない場合、循環依存でエラーが出ます。

2023-03-17T21:19:16.514+09:00 ERROR 82100 --- [           main] o.s.b.d.LoggingFailureAnalysisReporter   : 

***************************
APPLICATION FAILED TO START
***************************

Description:

The dependencies of some of the beans in the application context form a cycle:

┌──->──┐
|  suburiComponentProxy defined in file [/xxx/build/classes/java/main/me/irof/suburi/SuburiComponentProxy.class]
└──<-──┘
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment