-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: 쿼리 카운터 적용 #445
feat: 쿼리 카운터 적용 #445
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package zipgo.aspect; | ||
|
||
import org.springframework.web.context.request.RequestContextHolder; | ||
|
||
import java.lang.reflect.InvocationHandler; | ||
import java.lang.reflect.Method; | ||
|
||
public class ConnectionProxyHandler implements InvocationHandler { | ||
|
||
private static final String QUERY_PREPARE_STATEMENT = "prepareStatement"; | ||
|
||
private final Object connection; | ||
private final QueryCounter queryCounter; | ||
|
||
public ConnectionProxyHandler(Object connection, QueryCounter queryCounter) { | ||
this.connection = connection; | ||
this.queryCounter = queryCounter; | ||
} | ||
|
||
@Override | ||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { | ||
countQuery(method); | ||
return method.invoke(connection, args); | ||
Comment on lines
+21
to
+23
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 한 가지.. 제가 잘 모르는 상태에서 봐서 아쉬웠던 점이 있는데요..! countQuery 메서드로 분리되어서, invoke 메서드만 봤을 때는 이상 InvocationHandler 처음 본 인간의 하소연이었습니다.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. method.invoke가 원래 메서드가 발동하는 곳이고 countQuery는 부가적으로 넣은 것이라 후에 부가적으로 몇개 들어가게된다면 분리해주는 게 좋을 것 같아서 분리시켜놨습니다! 지금은 사실 딱히 분리 안 시켜줘도 상관은 없긴한데 고치면 approve가 다 풀릴거 같아서 이대로 가겠습니당 |
||
} | ||
|
||
private void countQuery(Method method) { | ||
if (isPrepareStatement(method) && isRequest()) { | ||
queryCounter.increaseCount(); | ||
} | ||
} | ||
|
||
private boolean isPrepareStatement(Method method) { | ||
return method.getName().equals(QUERY_PREPARE_STATEMENT); | ||
} | ||
|
||
private boolean isRequest() { | ||
return RequestContextHolder.getRequestAttributes() != null; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 리뷰하며 공부하기
오오! 그래서 isRequest()라는 이름이 붙었구나. |
||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package zipgo.aspect; | ||
|
||
import lombok.Getter; | ||
import org.springframework.stereotype.Component; | ||
import org.springframework.web.context.annotation.RequestScope; | ||
|
||
@Getter | ||
@Component | ||
@RequestScope | ||
public class QueryCounter { | ||
|
||
private int count; | ||
|
||
public void increaseCount() { | ||
count++; | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package zipgo.aspect; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
import org.aspectj.lang.ProceedingJoinPoint; | ||
import org.aspectj.lang.annotation.Around; | ||
import org.aspectj.lang.annotation.Aspect; | ||
import org.springframework.stereotype.Component; | ||
|
||
import java.lang.reflect.Proxy; | ||
|
||
@Aspect | ||
@Component | ||
@RequiredArgsConstructor | ||
public class QueryCounterAop { | ||
|
||
private final QueryCounter queryCounter; | ||
|
||
@Around("execution(* javax.sql.DataSource.getConnection(..))") | ||
public Object getConnection(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { | ||
Object connection = proceedingJoinPoint.proceed(); | ||
|
||
return Proxy.newProxyInstance( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 리뷰하며 공부하기 |
||
connection.getClass().getClassLoader(), | ||
connection.getClass().getInterfaces(), | ||
new ConnectionProxyHandler(connection, queryCounter) | ||
); | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package zipgo.common.interceptor; | ||
|
||
import jakarta.servlet.http.HttpServletRequest; | ||
import jakarta.servlet.http.HttpServletResponse; | ||
import lombok.RequiredArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.stereotype.Component; | ||
import org.springframework.web.servlet.HandlerInterceptor; | ||
import zipgo.aspect.QueryCounter; | ||
|
||
@Slf4j | ||
@Component | ||
@RequiredArgsConstructor | ||
public class LoggingInterceptor implements HandlerInterceptor { | ||
|
||
private static final String QUERY_COUNT_LOG = "METHOD: {}, URL: {}, STATUS_CODE: {}, QUERY_COUNT: {}"; | ||
private static final String QUERY_COUNT_WARN_LOG = "쿼리가 {}번 이상 실행되었습니다!!!"; | ||
private static final int WARN_QUERY_COUNT= 8; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. WARN_QUERY_COUNT가 8인 이유가 궁금합니다요! 🤓 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 딱히 큰 이유는 없고, 5번과 10번중 고민하다 사이 값으로 했습니다! |
||
|
||
private final QueryCounter queryCounter; | ||
|
||
@Override | ||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, | ||
Object handler, Exception ex) { | ||
int queryCount = queryCounter.getCount(); | ||
log.info(QUERY_COUNT_LOG, request.getMethod(), request.getRequestURI(), response.getStatus(), queryCount); | ||
if (queryCount >= WARN_QUERY_COUNT) { | ||
log.warn(QUERY_COUNT_WARN_LOG, WARN_QUERY_COUNT); | ||
} | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,32 +2,26 @@ | |
|
||
import com.epages.restdocs.apispec.MockMvcRestDocumentationWrapper; | ||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
import java.nio.charset.StandardCharsets; | ||
import java.util.List; | ||
import org.junit.jupiter.api.DisplayNameGeneration; | ||
import org.junit.jupiter.api.DisplayNameGenerator; | ||
import org.junit.jupiter.api.Nested; | ||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.api.extension.ExtendWith; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs; | ||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; | ||
import org.springframework.boot.test.mock.mockito.MockBean; | ||
import org.springframework.http.MediaType; | ||
import org.springframework.mock.web.MockMultipartFile; | ||
import org.springframework.restdocs.mockmvc.RestDocumentationResultHandler; | ||
import org.springframework.test.context.junit.jupiter.SpringExtension; | ||
import org.springframework.test.web.servlet.MockMvc; | ||
import zipgo.admin.application.AdminQueryService; | ||
import zipgo.admin.application.AdminService; | ||
import zipgo.admin.dto.BrandCreateRequest; | ||
import zipgo.admin.dto.PetFoodCreateRequest; | ||
import zipgo.auth.presentation.AuthInterceptor; | ||
import zipgo.auth.presentation.JwtMandatoryArgumentResolver; | ||
import zipgo.auth.support.JwtProvider; | ||
import zipgo.common.acceptance.MockMvcTest; | ||
import zipgo.image.application.ImageService; | ||
import zipgo.petfood.domain.fixture.PetFoodFixture; | ||
|
||
import java.nio.charset.StandardCharsets; | ||
import java.util.List; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 민무 idea 설정 바뀐듯 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. import 패키지 이렇게 분리되는게 맞지 않나 |
||
|
||
import static com.epages.restdocs.apispec.RestAssuredRestDocumentationWrapper.resourceDetails; | ||
import static org.mockito.Mockito.when; | ||
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.multipart; | ||
|
@@ -37,19 +31,12 @@ | |
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; | ||
import static zipgo.brand.domain.fixture.BrandFixture.무민_브랜드_생성_요청; | ||
|
||
@AutoConfigureRestDocs | ||
@ExtendWith(SpringExtension.class) | ||
@SuppressWarnings("NonAsciiCharacters") | ||
@WebMvcTest(controllers = AdminController.class) | ||
@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) | ||
class AdminControllerMockTest { | ||
class AdminControllerMockTest extends MockMvcTest { | ||
|
||
@Autowired | ||
private ObjectMapper objectMapper; | ||
|
||
@Autowired | ||
private MockMvc mockMvc; | ||
|
||
@MockBean | ||
private ImageService imageService; | ||
|
||
|
@@ -59,12 +46,6 @@ class AdminControllerMockTest { | |
@MockBean | ||
private AdminQueryService adminQueryService; | ||
|
||
@MockBean | ||
private JwtProvider jwtProvider; | ||
|
||
@MockBean | ||
private AuthInterceptor authInterceptor; | ||
|
||
@MockBean | ||
private JwtMandatoryArgumentResolver argumentResolver; | ||
|
||
|
@@ -102,7 +83,9 @@ class AdminControllerMockTest { | |
partWithName("brandCreateRequest").description("브랜드 생성 요청").attributes( | ||
key("contentType").value("application/json") | ||
))); | ||
} | ||
}{ | ||
} | ||
|
||
|
||
@Nested | ||
class 식품_생성 { | ||
|
@@ -145,4 +128,4 @@ class 식품_생성 { | |
|
||
} | ||
|
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package zipgo.common.acceptance; | ||
|
||
import org.junit.jupiter.api.DisplayNameGeneration; | ||
import org.junit.jupiter.api.DisplayNameGenerator; | ||
import org.junit.jupiter.api.extension.ExtendWith; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs; | ||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; | ||
import org.springframework.boot.test.mock.mockito.MockBean; | ||
import org.springframework.test.context.junit.jupiter.SpringExtension; | ||
import org.springframework.test.web.servlet.MockMvc; | ||
import zipgo.aspect.QueryCounter; | ||
import zipgo.auth.support.JwtProvider; | ||
|
||
@WebMvcTest | ||
@AutoConfigureRestDocs | ||
@ExtendWith(SpringExtension.class) | ||
@SuppressWarnings("NonAsciiCharacters") | ||
@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) | ||
public class MockMvcTest { | ||
|
||
@Autowired | ||
protected MockMvc mockMvc; | ||
|
||
@MockBean | ||
protected JwtProvider jwtProvider; | ||
|
||
@MockBean | ||
protected QueryCounter queryCounter; | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
리뷰하며 공부하기
메서드를 실행하기 전에 쿼리 카운트를 한답.