(μ€νλ§) RequestContextHolder
RequestContextHolder λ μμ²λΉ λ°μλλ μ€λ λμ λ°μΈλ©λμ΄ RequestAttributes λ₯Ό key/value μμΌλ‘ κ°μ§κ³ μλ€. κ°λ°μ μΈ μΈ‘λ©΄μμ λ μ΄μ΄μ ꡬλΆμμ΄ μ€νν±νκ² μ κ·Όν μ μλ€. νμ§λ§ λ©μΈμ€λ λλ₯Ό λ²μ΄λ λ³λ μ€λ λνμμ κΊΌλΈ λ€λ₯Έ μ€λ λμμ RequestContextHolder μ μ κ·Όνμ¬ κ°μ κΊΌλ΄λ €κ³ νλ©΄ null μ΄ λμ¨λ€. μ΄λ₯Ό λ°©μ§νκΈ° μν΄μ μΈν°λ·μ μ¬λ¬ λ°©λ²λ€μ΄ μλ κ±Έλ‘ λ³΄μΈλ€. λ€λ§ μ§κ΄μ μ΄λ©΄μ μν₯λλ₯Ό κ°μ₯ μ΅μννλ λ°©λ²μ μ λ¬λλ Param κ°μ²΄μ RequsetAttributes λ΄μ©μ μΈμλ‘ κ°μ΄ λ겨μ μμ λ°λ μ½λμͺ½μ μλμ κ°μ΄ μμ±νλ©΄ ν΄μκ° λλ€.
fun asyncMethod(param: Param) {
// ν λΉ
RequestContextHolder.setRequestAttributes(param.requestAttributes)
// .. logic ..
// λͺ
μμ ν΄μ
RequestContextHolder.resetRequestAttributes()
}
(μ€νλ§) @TransactionalEventListener
μλΉμ€μμ κ°μ²΄μ μνμ λ³κ²½ νΉμ λΉμ¦λμ€ λ‘μ§μΌλ‘ μΈνμ¬ μ½λ°±μ΄λ νΉμ μ΄λ²€νΈ μ νκ° νμν κ²½μ°κ° μλ€. μ΄ λ λ μ΄μ΄κ° λλ©μΈμ μΉ¨λ²νμ§ μκ³ μΆμ λ μ°λ EventListener μ νΈλμμ λ²μ μ΄λ€. νΈλμμ μ΄ μ 곡λμ§ μκ³ νΈλμμ μ μ /νμ λ°λΌμ μ΄λ²€νΈ νΈμΆ μμ μ μ‘°μ ν μ μλ€. μ΄λ²μ μ²μ μ¬μ©ν΄λ³Έκ±΄ @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT) μ΄λ€. μ΄κ±Έ μ¬μ©νλ©΄ νΈλμμ μ λμμ΄ λλκ³ μ΄νμ EventListener κ° λμνλ€. νμ§λ§ ν΄λΉ μ΄λ²€νΈ μμμμ νΈλμμ μνμ μν¬ μ μλ€. μ΅μ§λ‘ μνμν€λ©΄ μλμ κ°μ μλ¬λ₯Ό λ§λλ€.
ERROR 54966 --- [io-48081-exec-1] o.s.t.s.TransactionSynchronizationUtils
: TransactionSynchronization.afterCompletion threw exception
org.springframework.dao.InvalidDataAccessApiUsageException
: no transaction is in progress
νΈλμμ μ λμνκ³ μΆμΌλ©΄ @TransactionalEventListener κ° λΆμ λ©μλμ λ€λ₯Έ μ λ Έν μ΄μ μ λΆμ¬μ£Όμ΄μΌ λμνλ€. λ°©λ²μ λκ°μ§λ€.
(1) @Transactional(propagation = Propagation.REQUIRES_NEW) λ₯Ό κ°μ΄ λΆμ¬μ€λ€.
(2) @Async + @Transactional λ₯Ό κ°μ΄ λΆμ¬μ€λ€.
(1) μ μ κ· νΈλμμ μ λ§λ€μ΄ μ²λ¦¬νλ κ²μ΄κ³ (2) λ λΉλκΈ° μ€λ λνμμ λ€λ₯Έ μ€λ λμμ νΈλμμ μ μ²λ¦¬νλ κ²μ΄λ€. νμμ λ°λΌ μ¬μ©νλλ‘ νλ€. (+ μ΅μ μ νΈλ€λ§μ λΉμ°νκ² νμ.)
(kotlin) νμ₯ν¨μ λ‘κ·Έμμ±
νμ₯ν¨μμμ λ‘κ·Έλ₯Ό μ¨μΌν κ²½μ°κ° μμ μ μμ. ν΄λμ€μ κ²½μ°λ νλκ°μΌλ‘ μ μΈμ²λ¦¬ν μ μμ§λ§ νμ₯ν¨μλ ν΄λμ€λ΄ νλλ‘ μ‘΄μ¬ν μ μλ€. λ°λΌμ κ·Έλ₯ static νκ² μ¬λ €λκ³ μ¨μΌνλ€. μ€νλ§μ΄λ κ°μ΄ μ΄μ©ν λ μ¬μ€ λ‘κΉ κ°μ²΄λ λΉ μμ μ μΈλ ννλ‘ μ°μ΄κΈ° λλ¬Έμ κ·Έκ²λν κ²°κ΅ static νλ€κ³ μκ°νλ€. (μλ μ½λλ₯Ό λμ»΄νμΌνλ©΄ logger κ°μ²΄λ static {} λΈλμμ μ²λ¦¬λμ΄μλ€.)
// kotlin κΈ°μ€.
class CustomExtension
val logger: Logger = LoggerFactory.getLogger(CustomExtension::class.java)
fun Person.toBatMan(): Person {
logger.info("person -> batman")
return this.copy(
name = "batman",
age = 99999
)
}
// λ‘κ·Έλ μλμ κ°μ΄ μΆλ ₯λλ€.
// 00:41:47.496 [main] INFO com.example.springbootbasis.practice.logger.CustomExtension -- person -> batman
(μ΄νν°λΈ μ½νλ¦°) μμ μ± μλ μ½λλ₯Ό λ§λ€κΈ°
require/check/assert λ₯Ό μ΄μ©νμ¬ μμΈλ₯Ό μΌμΌν€κ³ μ½λμ μ νμ λμ. μ¬κΈ°μ assert λ μ μΈνκ³ require/check λ§ λ³΄λ €κ³ νλ€.
require : μκ·λ¨ΌνΈμ μ νμ λκΈ°
- age λΌλ νλκ°μ μμκ° λ μ μλ€κ³ μ νμ λκ³ μμκ° λλ μΌμ΄μ€μ κ²½μ° IllegalArgumentException μλ¬λ₯Ό λ°μμν¨λ€.
fun main() {
Person(age = -1, "νκΈΈλ")
}
data class Person(
val age: Int,
val name: String
) {
init {
require(age >= 0) {
"λμ΄λ μμκ° λ μ μμ΅λλ€. age=$age"
}
}
}
Exception in thread "main" java.lang.IllegalArgumentException: λμ΄λ μμκ° λ μ μμ΅λλ€. age=-1
check : μνκ° μ‘°κ±΄μ νμΈ
- isOrdered μνκ°μ΄ true μΈ κ²½μ°μ IllegalStateException μλ¬λ₯Ό λ°μμν¨λ€.
fun main() {
val order = Order().apply { this.isOrdered = true }
order.ordered()
}
class Order {
var isOrdered: Boolean = true
fun ordered() {
check(isOrdered.not()) {
"μ£Όλ¬Έλ μνμ
λλ€. ordered=$isOrdered"
}
}
}
(μ΄νν°λΈ μ½νλ¦°) μ΄κΈ°νλ₯Ό μ§μ°μν¨λ€λ©΄ λͺ μμ μΌλ‘ μλ¦°λ€.
κΈ°λ³Ένμ μλ Dellgates.notNull() μ μ¬μ©νλ€. κ·Έ μΈ λ νΌλ°μ€μλ lateinit var μ μ¬μ©νλ€. !! μ°μ°μλ₯Ό μ§μνλΌκ³ μ± μμ νλ€. μ μ λΆμλκ΅¬μΈ https://github.com/detekt/detekt μ΄λΌλ μ€νμμ€λ₯Ό μΆμ²ν΄μ€
'Interest > κ°λ°' μΉ΄ν κ³ λ¦¬μ λ€λ₯Έ κΈ
2024-04 κ°λ° : μν¬λ¦¬κΈ°λ‘ (1) | 2024.04.10 |
---|---|
2024-03 κ°λ° : μν¬λ¦¬ κΈ°λ‘ (0) | 2024.03.09 |
2024-01 κ°λ° : μν¬λ¦¬ κΈ°λ‘ (0) | 2024.01.21 |
2023-11-25 κ°λ° : μν¬λ¦¬ κΈ°λ‘ (0) | 2023.11.25 |
2023-11-19 κ°λ° : μν¬λ¦¬ κΈ°λ‘ (0) | 2023.11.19 |