Skip to content
This repository has been archived by the owner on Feb 1, 2023. It is now read-only.

기사 등록 기능 추가 #20

Merged
merged 4 commits into from Feb 8, 2021
Merged

기사 등록 기능 추가 #20

merged 4 commits into from Feb 8, 2021

Conversation

HwangWonGyu
Copy link
Owner

@HwangWonGyu HwangWonGyu commented Jan 27, 2021

ArticleDTO.java

  • 주요 필드의 목적

    • id : 게시판 번호 표시
    • createTime, modificateTime : 기사입력, 최종수정 날짜/시간 표시에 활용
      (MySQL에서 각각 CURRENT_TIMESTAMP, CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP 적용)
      Article LocalDateTime Example - Naver News
    • sectionId, companyId : 뉴스 분야별, 언론사별 기사 조회 및 표시에 활용
    • editorId : 기자 id를 통한 기자 정보 조회 후 표시에 활용
  • title, content 필드에 대한 유효성 검사

ArticleMapper.xml

  • insert문 실행 테스트 결과
        INSERT INTO article (title, content, sectionId, companyId, editorId)
        VALUES (#{title}, #{content}, #{sectionId}, #{companyId}, #{editorId})

image

@HwangWonGyu HwangWonGyu self-assigned this Jan 27, 2021
@HwangWonGyu HwangWonGyu changed the title 기사 생성 추가 기사 등록 기능 추가 Jan 27, 2021
@HwangWonGyu HwangWonGyu added the Work In Progress Currently working on label Jan 27, 2021
Copy link
Collaborator

@junshock5 junshock5 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

전반적으로 코드가 많이 깔끔해졌네
이번 브랜치 PR은 목적의식도 뚜렷하고 노력한 결과가 보였어
특히 PR 처음에 기사 스크린샷으로 어떤 작업을 명시한건지가 좋았어

리뷰 한 내용부터 우선순위를 높게해서 회신주면 확인해볼께~

@RestController
public class ArticleController {

private final ArticleService articleService;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

final 키워드를 사용한 의도가 무엇일까?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

final 키워드 적용된 타입의 빈이 생성됨과 동시에 주입되는 것을 보장해서
NPE를 방지하는것과 immutable한 필드를 만드는 의도가 있어

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

articleService를 final키워드로 만들면 안되는 상황,
articleService를 immutable하게 하지않으면 발생하는 상황 예시를 구체적으로 들어주라.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

articleService를 final키워드로 만들면 안되는 상황,

필드 주입 방식과 setter 주입 방식인 경우 final 키워드로 만들면 안돼

선택적 빈 주입의 경우(공식문서는 optional dependencies라고 표현)
final 키워드가 없으니 null 체크를 해주면 사용할 수 있겠네

실사용 예시는
애플리케이션 모니터링 API인 JMX에서 설정을 관리하는 리소스인 Mbean(Managed Bean)이 있어
설정 변경이 가능하게 getter, setter를 두고 Setter Injection을 하는거야

public interface HelloMBean { 
 
    public void sayHello(); 
    public int add(int x, int y); 
    
    public String getName(); 
     
    public int getCacheSize(); 
    public void setCacheSize(int size); 
} 

JMX 예제 코드setCacheSize 메서드가 그 예시겠네

이 내용은 내가 JMX 모니터링 실습까지 해보진 못해서 이해도가 낮은점 참고해줘
그래서 다른 분이 진행한 실습 결과를 가져와봤어

image

위의 private int cacheSizepublic synchronized void setCacheSize(int size) 덕분에 동적 설정이 가능해

image

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

articleService를 immutable하게 하지않으면 발생하는 상황 예시를 구체적으로 들어주라.

immutable 하지 않아서 null로 변경 가능하게 되고
비즈니스 로직상에서 NPE가 발생할 상황이 생기게 돼

image

위 코드를 예시로 setService(Service service) 로 아직 주입을 하지 않은 상태에서
아래처럼 Service 메서드인 doSomething의 호출이 가능하게 되고 이때 NPE가 발생하게 돼

controller.setService(new Service() {
    @Override
    public void doSomething() {
        System.out.println("Anonymous class is doing something");
    }
});

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

articleService를 final키워드로 만들면 안되는 상황,

필드 주입 방식과 setter 주입 방식인 경우 final 키워드로 만들면 안돼

선택적 빈 주입의 경우(공식문서는 optional dependencies라고 표현)
final 키워드가 없으니 null 체크를 해주면 사용할 수 있겠네

실사용 예시는
애플리케이션 모니터링 API인 JMX에서 설정을 관리하는 리소스인 Mbean(Managed Bean)이 있어
설정 변경이 가능하게 getter, setter를 두고 Setter Injection을 하는거야

public interface HelloMBean { 
 
    public void sayHello(); 
    public int add(int x, int y); 
    
    public String getName(); 
     
    public int getCacheSize(); 
    public void setCacheSize(int size); 
} 

JMX 예제 코드setCacheSize 메서드가 그 예시겠네

이 내용은 내가 JMX 모니터링 실습까지 해보진 못해서 이해도가 낮은점 참고해줘
그래서 다른 분이 진행한 실습 결과를 가져와봤어

image

위의 private int cacheSizepublic synchronized void setCacheSize(int size) 덕분에 동적 설정이 가능해

image

내용은 맞는거같은데, 저 이해한 실습 자체를 복붙하는건 안좋은거같에
말로 풀어서 상대방이 이해하기 쉽게 말해주면 더 좋을거같에.

}

@Value("${spring.webservice.newsHome}")
private String newsHomeURL;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이런 config성 설정값들은 Controller 클래스보단
config class를 따로 만들어서 첫 로드시에 설정되게 하는게 가독성 유지보수성 면에서 더좋아~

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 내용은 'URLPatternConfig 클래스 생성' 이슈 #22 로 분리해서 반영할게

@PostMapping("/articles")
public String addArticle(@Valid @RequestBody ArticleDTO article, BindingResult result) {
if (result.hasErrors()) {
return "articles/createOrUpdateArticleForm";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BindingResult 클래스에 hasErrors가 true가 되는 조건은 무엇일까??

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BindingResult 파라미터 바로 앞에 오는 Valid 어노테이션이 적용된 클래스의 필드들을
JSON HTTP 메시지 바디에 있는 각각의 'Key-Value'와 바인딩하는 도중
유효성 검사 어노테이션이 적용된 필드의 애트리뷰트 조건과 비교해 맞지 않으면
MethodArgumentNotValidException 예외가 발생하면서
BindingResult 의 hasErrors가 true가 돼

테스트
image
예외 발생 테스트로 위 JSON 데이터 중 content key의 value값이 "가나다"로 3글자인데 최소 10글자가 되도록 @Length를 적용했어

@Length(min = 10, max = 10000, message = "기사 내용은 {min} ~ {max}자로 작성해야 합니다.")
@NotBlank(message = "기사 내용을 입력해주세요.")
private String content;

image
그래서 위처럼 content 필드와 관련된 메시지가 List<ObjectError> errors 에 담겨져 오는걸 볼 수 있어

Copy link
Collaborator

@junshock5 junshock5 Feb 1, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 피드백 회신은 지금까지 작성한것중에서 가장 명확하고 정확하고 깔끔하네!

}

@GetMapping("/articles/{id}")
public ArticleDTO findArticleById(@PathVariable long id) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@PathVariable 가 http 통신시에 어떻게 동작하는지 최대한 자세하게 설명 요망

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

자세한 설명을 위해서 디버깅 스택 트레이스를 참고했고 중심 코드라고 판단한 부분만 가져와봤어

  1. 우선 HTTP 통신의 첫 처리를 DispatcherServlet.doService()에서 DispatcherServlet.doDispatch()로 위임하고
    Handler에 Request를 전달하기 위해서
    Request(GET /articles/3), Response, Handler(ArticleController.findArticleById(long)) 로 handle()을 호출해
    image
    image

  2. 그럼 RequestMappingHandlerAdapter에서는 실행할 Handler 메서드에 Request를 지정(Adapt)하고
    image

  3. InvocableHandlerMethod에서는 getMethodArgumentValues()에서 HandlerMethodArgumentResolver를 활용해
    argument(3)를 가져와서 바인딩해
    image

  4. doInvoke()를 모두 거치면 Handler(ArticleController.findArticleById(@PathVariable long id))의 파라미터에
    '3'이 전달된 후 컨트롤러 단 로직이 실행돼

결국 조사해보니 3. 에서 언급한 HandlerMethodArgumentResolver@PathVariable 파라미터 바인딩의 핵심 역할을 하는거였네

Strategy interface for resolving method parameters into argument values in the context of a given request.
해석 : 주어진 Request 컨텍스트에서 메서드 parameter(정의)에 argument(실제 값)를 적용하기 위한 전략을 갖는 인터페이스입니다.

이해가 잘 안되는 부분이 있다면 회신해줘

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HTTP 통신의 첫 처리를 DispatcherServlet.doService()에서 한다고 했는데
대상 클라이언트의 ip port정보나 패킷처리 정보는 설명이 부족한거같네.
@PathVariable 설명은 HandlerMethodArgumentResolver가 @PathVariable 파라미터 바인딩의 핵심 역할한다고
잘찾은거같에 추가적으로 설명 부탁해~

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HTTP 통신의 첫 처리를 DispatcherServlet.doService()에서 한다고 했는데
대상 클라이언트의 ip port정보나 패킷처리 정보는 설명이 부족한거같네.

위 코멘트의 설명 첫부분의 이전 단계까지 추가적으로 보완해서 과정을 설명해볼게

우선 서버로 온 URL 요청(Request)으로 서블릿 컨테이너(Spring Boot니까 Embedded Tomcat)에 의해
Request, Response 객체가 생성되고 DispatcherServlet 실행을 시도하게돼

메모리에 Servlet 인스턴스가 있는지 먼저 확인하고
만약 컨테이너에 DispatcherServlet의 객체가 없다면, 즉 처음 실행한다면
HttpServlet에서 Override한 Init 메서드를 호출해 객체를 생성하고 초기화해

이제 Request는 웹 컨테이너의 스레드 풀로부터 하나의 스레드를 할당받아서
DispatcherServletHttpServletservice(ServletRequest, ServletResponse) 메서드를 호출하게돼

테스트
아래의 Request 예시는 UserControllerfindUserById 메서드를 호출하기 위한 URI야
image

service(ServletRequest, ServletResponse) 메서드 에서
대상 클라이언트의 IP, Port 정보를 포함한 HTTP GET Request 정보와 Response 정보를 받아서
image

service(HttpServletRequest, HttpServletResponse) 메서드에서 doGet 메서드를 호출해
image

그러면 FrameworkServlet 클래스의 processRequest 메서드에서
DispatcherServlet이 Request를 실제로 핸들링 할 수 있게 doService 추상 메서드를 호출하면
image

FrameworkServlet를 상속한 DispatcherServlet
Request 정보를 실제 핸들러에 위임하기 위해서 doDispatch 메서드를 호출해
image

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@PathVariable 설명은 HandlerMethodArgumentResolver가 @PathVariable 파라미터 바인딩의 핵심 역할한다고
잘찾은거같에 추가적으로 설명 부탁해~

HandlerMethodArgumentResolver 동작원리 핵심

아래 args 정보는 getMethodArgumentValues 메서드로 가져오는데
image

내부의 resolversHandlerMethodArgumentResolverComposite 타입으로

private HandlerMethodArgumentResolverComposite resolvers = new HandlerMethodArgumentResolverComposite();
(생략)
// resolver이 지원하지 않는 파라미터면 예외처리
if (!this.resolvers.supportsParameter(parameter)) {
    throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
}
try {
    // resolver에서 값을 바인딩
    args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
}

HandlerMethodArgumentResolver 구현체들 루프돌면서 파라미터 체킹하는 방식이야
image

image

image

if(article != null)
return article;
else
return null;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return null; 을 하면 클라이언트 입장에서
해당값이 에러가 있는건지 정상동작을 한건지
이해하지 못하지 않을까?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이해하지 못한다면 어떻게해야 이해할 수 있을까?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

연동된 서비스에 맞게 Model에다가 View에 사용할 데이터를 전달하고,
반환값으로 ViewResolve가 가능하도록 View 이름을 전달하고,
로직에 따른 HTTP 상태 코드, HTTP 엔티티 헤더/바디를 전달해야해

그래야 어떤 에러가 있는지, 정상동작을 한건지 알고 처리할 수 있어

ResponseEntity<T> 로 구현할 수 있겠네

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그러면 ResponseEntity 로 변경해야겠네~


@Override
public String toString() {
return "ArticleDTO{" +
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

toString() 메서드를 쓰는 이유에대해서 말해주라~

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

후에 기사 정보에 대한 파일 출력, 디버깅에 사용하려면
결국 사람이 해석해서 활용 가능한 데이터로 표시해야한다고 생각했어

toString()을 Override하지 않으면 '클래스명@16진수 해시코드' 형식으로 표시되는데,
이 형식만 가지고는 특정 기사에 대한 데이터를 얻지 못해서야


private final ArticleMapper articleMapper;

@Autowired
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Autowired 어노테이션 사용시
spring이 bean을 주입하는 동작원리를 최대한 상세히 설명 요함

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

자세한 설명을 위해서 디버깅 스택 트레이스를 참고했고 중심 코드라고 판단한 부분만 가져와봤어

  1. DefaultListableBeanFactory 클래스의 preInstantiateSingletons 메서드에서
    생성자 타입인 articleServiceImpl 빈의 이름을 토대로 빈을 생성하고
    image

  2. AbstractAutowireCapableBeanFactory 클래스의 createBeanInstance 메서드에서
    determineConstructorsFromBeanPostProcessors 메서드로
    Autowire DI 대상이 될 수 있는 생성자 정보(생성자 클래스 ArticleServiceImpl, 파라미터 ArticleMapper)를 받아 반환하고
    image

  3. ConstructorResolver 클래스의 autowireConstructor 메서드에서
    생성자 정보를 토대로 빈을 생성하고 설정해두면
    image

  4. 후에 리플렉션 기반으로 생성자 인스턴스를 생성(newInstance)해서
    ArticleServiceImpl 생성자에 ArticleMapper 를 DI 해주는거야

AbstractAutowireCapableBeanFactory 를 조사해보니 여기서 생성자 기반 빈 생성, 생성자 autowiring 을 제공하는거였어
아래 설명 3번째 문단과 4번째 문단에 내용에서 찾아볼 수 있었어

Abstract bean factory superclass that implements default bean creation,
with the full capabilities specified by the RootBeanDefinition class.
해석 : 기본 빈 생성을 구현하는 추상 빈 팩토리 상위클래스이며,
RootBeanDefinition 클래스에서 지정한 모든 기능을 사용할 수 있다. 

Implements the AutowireCapableBeanFactory interface
in addition to AbstractBeanFactory's createBean(java.lang.Class<T>) method.
해석 : AutowireCapableBeanFactory 인터페이스를 구현하며
빈 생성을 담당하는 메서드인  AbstractBeanFactory 클래스의 createBean 메서드가 있다.

Provides bean creation (with constructor resolution), property population,
wiring (including autowiring), and initialization.
해석 : 어떤 생성자 기반의 빈 생성을 할지, 엔티티에서 프로퍼티 설정은 어떻게 할지,
빈 간의 관계 설정(자동설정 포함)과 초기화에 대한 기능을 제공한다.

Handles runtime bean references, resolves managed collections, calls initialization methods, etc.
Supports autowiring constructors, properties by name, and properties by type.
해석 : 런타임 빈 참조, 스프링에서 관리되는 컬렉션 타입 선택, 초기화 메서드 호출 등을 다룬다.
생성자 autowiring, 이름에 의한 프로퍼티 설정, 타입에 의한 프로퍼티 설정을 지원한다.

그리고 이게 가능했던 이유 중 가장 핵심이 되는 인터페이스인 SmartInstantiationAwareBeanPostProcessor도 알게됐어

구글링하면 사람들이 BeanPostProcessor 가 Autowiring을 해준다고 설명하던데
이건 애플리케이션 단에서 구현할 때의 얘기고
내가 알아낸 이 인터페이스는 스프링 프레임워크 단에서 Autowiring을 제공해주는 거였어
아래 설명 2번째 문단에서 애플리케이션 단 구현 부분이 있다는 정보를,
1번째 문단에서 프레임워크 단 구현 부분이 있다는 정보를 찾아볼 수 있었어

NOTE: This interface is a special purpose interface,
mainly for internal use within the framework.
해석 : 이 인터페이스는 특별한 목적의 인터페이스이며,
주로 프레임 워크 내부에서 사용된다.

In general, application-provided post-processors
should simply implement the plain BeanPostProcessor interface
or derive from the InstantiationAwareBeanPostProcessorAdapter class.
해석 : 일반적으로, 애플리케이션 단에서 제공되는 post processor는
BeanPostProcessor 인터페이스를 구현하는 클래스거나
InstantiationAwareBeanPostProcessorAdapter 클래스를 상속하는 클래스다.

New methods might be added to this interface even in point releases.
해석 : 부수적인 릴리즈 버전에서도 새 메서드가 추가될 수 있다.

결국 2. 에서 언급한 AbstractAutowireCapableBeanFactory
후에 언급한 SmartInstantiationAwareBeanPostProcessor -> ⚠이 코멘트에서 정정
@Autowired 생성자 DI의 핵심 역할을 하는거였네

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. 리플렉션 기반으로 생성자 인스턴스를 생성(newInstance)해서 ArticleServiceImpl 생성자에 ArticleMapper 를 DI 해주는거야
    -> 이부분 리플렉션이 어떻게 DI해주는지 조금더 자세히 설명 부탁해

  2. SmartInstantiationAwareBeanPostProcessor 이 인터페이스가 어떤 과정으로 Autowiring 해주는건데?
    Note나 공식 도큐먼트를 통쨰로 가져오기 보단 너가 이해한걸 한글로 풀어쓰는게 리뷰어를 배려한다고 생각해.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. 리플렉션 기반으로 생성자 인스턴스를 생성(newInstance)해서 ArticleServiceImpl 생성자에 ArticleMapper 를 DI 해주는거야
    -> 이부분 리플렉션이 어떻게 DI해주는지 조금더 자세히 설명 부탁해

위 코멘트에 이어서 설명할게

  1. 우선 앞서 받은 생성자 정보에는 생성자 타입과 파라미터 타입 정보가 있으므로
    ConstructorResolver 클래스의 Instantiate 메서드에서 리플렉션 기반의 빈 생성을 시도해
    image

  2. 그러면 빈 생성 헬퍼 클래스인 BeanUtilsinstantiateClass 메서드에서 생성자 정보를 받아
    생성자 클래스인 ConstructorT newInstance 메서드를 호출하고
    image

  3. 생성자 파라미터 ArticleMapper, 생성자 타입 ArticleServiceImpl 정보를
    sun.reflect.ConstructorAccessor 에서 제공하는 newInstance 메서드에 넘겨줘서
    빈을 생성하는 네이티브 메서드를 호출하게해
    image

  4. 이렇게 리플렉션을 통해 빈이 생성됐다면
    그 빈을 읽어들이고 컨텍스트들의 검증하고 합친 다음 빈 간의 의존관계를 트리 형태로 관리해
    빈 정보에는 생성자와 빈 간의 의존관계가 있으니
    이걸 Dependency Injection 단계에서 최종적으로 ArticleServiceImpl 빈을 생성하고 ArticleMapper 빈을 DI 해줄 수 있겠네
    image

위 코드의 설명 순서들은 생성자 주입 방식의 동작과정과 연관돼있어
먼저 빈을 생성하는게 아니라 생성자로 객체를 생성하는 시점에 필요한 빈을 주입해

좀 더 자세히 말하자면
먼저 생성자 파라미터에 사용되는 빈을 찾거나 빈 팩토리에서 빈을 만들고,
그 후에 찾은 파라미터 빈으로 DI 빈의 생성자를 호출하는 구조인거지

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note나 공식 도큐먼트를 통쨰로 가져오기 보단 너가 이해한걸 한글로 풀어쓰는게 리뷰어를 배려한다고 생각해.

내가 이해한 내용이 들어있는 부분만 요약해서 가져온건데 실수로 번역을 안해뒀네
번역이랑 해석한 문단 위치까지 반영해뒀어

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. SmartInstantiationAwareBeanPostProcessor 이 인터페이스가 어떤 과정으로 Autowiring 해주는건데?

😰 우선 Autowiring 과정 설명 전에 내가 이전 코멘트에서
SmartInstantiationAwareBeanPostProcessor가 생성자 DI 핵심 역할이라 정리한건 정정해야겠어

결국 2. 에서 언급한 AbstractAutowireCapableBeanFactory와
후에 언급한 SmartInstantiationAwareBeanPostProcessor가
@Autowired 생성자 DI의 핵심 역할을 하는거였네

왜냐하면 인터페이스 계층구조를 보니 결국엔 BeanPostProcessor 인터페이스를 상속하므로
역시 Autowiring에는 BeanPostProcessor 인터페이스가 핵심이라고 말하는게 맞는것 같아!

image

BeanPostProcessor의 구현체인 AutowiredAnnotationBeanPostProcessor가 빈의 초기화 라이프 사이클 이전,
즉 빈이 생성되기 전에 @Autowired가 붙어있으면 해당하는 빈을 찾아서 주입해주는 작업을 하는거야
아래 참고 이미지에서는 11번 단계가 되겠네
image

다시 SmartInstantiationAwareBeanPostProcessor Autowiring 과정으로 돌아와서
테스트 대상 클래스인 ArticleServiceImplSmartInstantiationAwareBeanPostProcessor 메서드로
Autowiring 된게 아니지만 과정을 최대한 적어봤어

  1. DefaultListableBeanFactory 클래스에 저장중인 모든 빈 정보들 중 doGetBeanNamesForType 메서드로
    Autowiring될 빈을 탐색하는 과정중에 타입으로 빈 이름을 찾는 단계가 있어

image

  1. AbstractFactoryBeanisTypeMatch 메서드로 해당 타입을 검사해서 예측되는 빈 타입이 있다면

image

  1. AbstractAutowireCapableBeanFactory 클래스의 predictBeanType 메서드에서
    캐싱해둔 AutowiredAnnotationBeanPostProcessor
    SmartInstantiationAwareBeanPostProcessor 인터페이스의 predictBeanType 메서드를 호출해

image

  1. articleServiceImpl 이름을 가진 빈의 경우 3. 에서 설명한 메서드에서 예측되지 않아서
    AbstractAutowireCapableBeanFactory 클래스의 determineTargetType 메서드에서
    팩토리 메서드로 타입을 찾을건지, 빈에 담긴 클래스 타입으로 찾을건지 검사해서 얻은 타입을 사용하게 됐어
    articleServiceImpl 의 경우는 클래스 타입(ArticleServiceImpl)으로 검사해서 타입을 얻었네

image
image

  1. 찾아낸 ArticleServiceImpl 타입으로
    java.lang.reflect.Type을 캡슐화한 리플렉션 타입인 ResolvableTypeisAssignableFrom 메서드로
    해당 타입이 할당가능한지 여부를 판단했더니 false가 나왔어

그래서 DefaultListableBeanFactory 클래스의 doGetBeanNamesForType 메서드 결과값 List에는
해당 타입을 추가할 수 없었어...

image
image

Copy link
Collaborator

@junshock5 junshock5 Feb 8, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

음 이자료는 훌륭한거같에

@HwangWonGyu HwangWonGyu added Review wanted review comment is needed and removed Work In Progress Currently working on labels Feb 3, 2021
@junshock5 junshock5 self-requested a review February 8, 2021 06:02
Copy link
Collaborator

@junshock5 junshock5 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

머지해도 좋을것같네
고생했어~

@RestController
public class ArticleController {

private final ArticleService articleService;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

articleService를 final키워드로 만들면 안되는 상황,

필드 주입 방식과 setter 주입 방식인 경우 final 키워드로 만들면 안돼

선택적 빈 주입의 경우(공식문서는 optional dependencies라고 표현)
final 키워드가 없으니 null 체크를 해주면 사용할 수 있겠네

실사용 예시는
애플리케이션 모니터링 API인 JMX에서 설정을 관리하는 리소스인 Mbean(Managed Bean)이 있어
설정 변경이 가능하게 getter, setter를 두고 Setter Injection을 하는거야

public interface HelloMBean { 
 
    public void sayHello(); 
    public int add(int x, int y); 
    
    public String getName(); 
     
    public int getCacheSize(); 
    public void setCacheSize(int size); 
} 

JMX 예제 코드setCacheSize 메서드가 그 예시겠네

이 내용은 내가 JMX 모니터링 실습까지 해보진 못해서 이해도가 낮은점 참고해줘
그래서 다른 분이 진행한 실습 결과를 가져와봤어

image

위의 private int cacheSizepublic synchronized void setCacheSize(int size) 덕분에 동적 설정이 가능해

image

내용은 맞는거같은데, 저 이해한 실습 자체를 복붙하는건 안좋은거같에
말로 풀어서 상대방이 이해하기 쉽게 말해주면 더 좋을거같에.

if(article != null)
return article;
else
return null;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그러면 ResponseEntity 로 변경해야겠네~


private final ArticleMapper articleMapper;

@Autowired
Copy link
Collaborator

@junshock5 junshock5 Feb 8, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

음 이자료는 훌륭한거같에

@HwangWonGyu HwangWonGyu removed the Review wanted review comment is needed label Feb 8, 2021
@HwangWonGyu HwangWonGyu merged commit e256769 into develop Feb 8, 2021
@HwangWonGyu HwangWonGyu linked an issue Feb 18, 2021 that may be closed by this pull request
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

기사 등록 기능 구현
2 participants