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


294

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

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


4
나는 의존성이 될 수 있도록 생성자 주입이 일반적으로 선호된다는 인상을 받았다 final. 이러한 패턴을 감안할 때 @PostConstructJ2EE에 추가되는 이유는 분명히 다른 사용 사례를 보았어야합니까?
mjaggard

답변:


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

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


17
생성자 자체가 모든 종속성을 자동으로 연결하는 경우-모든 자동 연결 필드를 수동으로 설정 한 후 생성자에서 Bean을 완전히 초기화 할 수도 있습니다.
yair

7
빈의 생성자가 두 번 이상 호출 될 수있는 경우는 무엇입니까?
yair

1
아마도 "패시베이션"과 같은 것입니다. 컨테이너가 Bean을 디스크 저장소에 저장하기로 결정한 후 거기서 저장하십시오.
Bozho

13
생성자가 여러 번 호출되는 것을 볼 수는 없습니다. 컨테이너가 프록시를 인스턴스화하면 생성자가 프록시에 대해 한 번 이상 실제 Bean에 대해 한 번 호출되는 것을 볼 수 있습니다.
marcus

서버가 다시 시작된 직후에 페이지가로드 될 때 @PostConstruct 메소드가 호출 되지 않습니다 . (이것은 JBoss의 버그 일 수 있습니다.)
데이브 자비스

96

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

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

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


실제 예 :

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'

19
in a constructor, the injection of the dependencies has not yet occurred. setter 또는 field injection에서는 true이지만 생성자 injection에서는 true가 아닙니다.
Adam Siemion

Java 11에서 @PostConstruct가 제거되면 Java 11 로이 실제 예제를 어떻게 처리 할 수 ​​있습니까?
tet

@tet 답변에서 언급했듯이 javax.annotation-api 라이브러리를 사용해야합니다. 이 주석은 Java 11에서 제거되었지만 Java 9 이후로 더 이상 사용되지 않습니다.
narendra-choudhary

63

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

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


@ 스태프 만 : 내 편에서 하나 더하기. 데이터베이스에서 가져온 값으로 입력 텍스트 필드를 초기화하려는 경우 PostConstruct를 사용하여 입력 텍스트 필드를 초기화 할 수 있지만 생성자 내에서 동일한 작업을 수행하려고하면 실패합니다. PostContruct를 사용하지 않고 초기화 해야하는이 요구 사항이 있습니다. 당신은 시간이 있다면, 당신은이 일에 답하십시오 수 있습니다 stackoverflow.com/questions/27540573/...
Shirgill 인 Farhan

10

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

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);
        }
      });
}

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


1

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

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.