[java] @PostConstruct를 사용하는 이유는 무엇입니까?

관리 Bean @PostConstruct에서 일반 Java 오브젝트 생성자 후에 호출됩니다.

@PostConstruct일반 생성자 대신 Bean을 사용 하여 초기화하는 이유는 무엇 입니까?



답변

  • 생성자가 호출 될 때 Bean이 아직 초기화되지 않았기 때문에 종속성이 주입되지 않기 때문입니다. 에서 @PostConstruct방법 빈은 완전히 초기화 당신은 종속성을 사용할 수 있습니다.

  • 이는이 메소드가 Bean 라이프 사이클에서 한 번만 호출되도록 보장하는 계약이기 때문입니다. 내부 작업에서 컨테이너가 Bean을 여러 번 인스턴스화 할 가능성은 있지만 (아마도) @PostConstruct한 번만 호출 될 수 있습니다.


답변

주요 문제는 다음과 같습니다

생성자에서 종속성 주입이 아직 발생하지 않았습니다. *

* 생성자 주입은 분명히 제외


실제 예 :

public class Foo {

    @Inject
    Logger LOG;

    @PostConstruct
    public void fooInit(){
        LOG.info("This will be printed; LOG has already been injected");
    }

    public Foo() {
        LOG.info("This will NOT be printed, LOG is still null");
        // NullPointerException will be thrown here
    }
}

중요 :
@PostConstruct@PreDestroy 완전히 된 자바 (11)에서 제거 .

계속 사용하려면 종속성에 javax.annotation-api JAR을 추가해야합니다 .

메이븐

<!-- https://mvnrepository.com/artifact/javax.annotation/javax.annotation-api -->
<dependency>
    <groupId>javax.annotation</groupId>
    <artifactId>javax.annotation-api</artifactId>
    <version>1.3.2</version>
</dependency>

그래들

// https://mvnrepository.com/artifact/javax.annotation/javax.annotation-api
compile group: 'javax.annotation', name: 'javax.annotation-api', version: '1.3.2'


답변

클래스가 생성자에서 모든 초기화를 수행하는 경우 @PostConstruct실제로 중복됩니다.

그러나 클래스에 setter 메소드를 사용하여 의존성이 주입 된 경우 클래스 생성자가 객체를 완전히 초기화 할 수 없으며 때로는 모든 setter 메소드를 호출 한 후 일부 초기화를 수행해야하므로 유스 케이스입니다 @PostConstruct.


답변

다음 시나리오를 고려하십시오.

public class Car {
  @Inject
  private Engine engine;  

  public Car() {
    engine.initialize();  
  }
  ...
}

필드 주입 전에 Car를 인스턴스화해야하므로 생성자 실행 중에 주 입점 엔진이 여전히 null이므로 NullPointerException이 발생합니다.

이 문제는 Java 생성자 주입을 위한 JSR-330 종속성 주입 또는 Java @PostConstruct 메소드 주석을위한 JSR 250 공통 주석 으로 해결할 수 있습니다 .

@PostConstruct

JSR-250은 Java SE 6에 포함 된 공통 주석 세트를 정의합니다.

PostConstruct 주석은 초기화를 수행하기 위해 종속성 주입이 완료된 후에 실행되어야하는 메소드에서 사용됩니다. 이 메소드는 클래스를 서비스하기 전에 호출해야합니다. 이 주석은 의존성 주입을 지원하는 모든 클래스에서 반드시 지원되어야합니다.

JSR-250 Chap. 2.5 javax.annotation.PostConstruct

@PostConstruct 어노테이션은 인스턴스가 인스턴스화되고 모든 인젝션이 수행 된 후에 실행될 메소드 정의를 허용합니다.

public class Car {
  @Inject
  private Engine engine;  

  @PostConstruct
  public void postConstruct() {
    engine.initialize();  
  }
  ...
} 

생성자에서 초기화를 수행하는 대신 코드는 @PostConstruct로 주석이 달린 메소드로 이동합니다.

post-construct 메소드의 처리는 @PostConstruct로 주석이 달린 모든 메소드를 찾아서 차례로 호출하는 간단한 문제입니다.

private  void processPostConstruct(Class type, T targetInstance) {
  Method[] declaredMethods = type.getDeclaredMethods();

  Arrays.stream(declaredMethods)
      .filter(method -> method.getAnnotation(PostConstruct.class) != null) 
      .forEach(postConstructMethod -> {
         try {
           postConstructMethod.setAccessible(true);
           postConstructMethod.invoke(targetInstance, new Object[]{});
        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {      
          throw new RuntimeException(ex);
        }
      });
}

인스턴스화 및 주입이 완료된 후 사후 생성 방법의 처리를 수행해야합니다.


답변

또한 생성자 기반 초기화는 일종의 프록시 또는 원격 작업이 필요할 때마다 의도 한대로 작동하지 않습니다.

ct는 EJB가 deserialize 될 때마다 그리고 새로운 프록시가 생성 될 때마다 호출됩니다 …


답변