월간 보관물: 2014 3월

Java 에서 public final class 란?

오픈소스 코드를 읽다 보니 다음과 같이 선언된 class 를 종종 보았다.

public final class XXX { }

보통 final 은 변수를 선언할 때 해당 변수의 값이 변경되는것을 방지하기 위해서 사용하는 것인데 class 앞에 사용되는 final 은 어떤 의미인지 의문이 들었다.

답은 간단하다.

final 이 붙은 class 는 더이상 확장할 수 없다. 즉 상속받아서 사용할 수 없다는 것이다.

이것은 원래부터 상속을 위해 디자인된 클래스가 아닌 일반 클래스를 마구잡이로 상속하여 프로그램의 디자인이 깨지고 예상치 못한 일이 발생하는 것을 막아주기 위한 수단이다.

http://stackoverflow.com/questions/218744/good-reasons-to-prohibit-inheritance-in-java

여기서도 볼 수 있듯이 class 는
1. 상속을 위해 디자인되고 그 에 관한 문서를 충분하게 만들거나
2. 상속 자체를 막아버리거나

두가지 경우로 사용하는 것이 안전한 프로그램 방법이라고 설명한다. ( 이펙티브 자바를 보지는 않았지만 그 내용 중 일부에 있다고 함)

maven scope 에서 provided 는 언제 쓸까?

maven 을 쓴지 좀 되었는데 별 생각없이 쓰다가 오늘 이슈를 하나 만났다.
요약하면 같은 라이브러리인데 모듈마다 사용하는 버전이 달라서 하나의 어플리케이션에 버전별로 디펜던시에 추가되는 문제이다.

예를 들면,
mymodule 이라는 모듈이 있고 이것을 Spring application 에서 약간 편리하게 사용하기 위해서 mymodule-spring 이라는 wrapper 같은 것을 만들고 있었는데 스프링 모듈을 가져다 사용해야 했다. 그래서 다음과 같이 pom.xml 에 dependency 를 추가했다.

 <!-- spring -->
 <dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-context</artifactId>
     <version>${spring.version}</version>
 </dependency>

그리고는 pom.xml 에 properties 에 spring.version 값을 정의하였다.
그런데 이 모듈을 가져다 사용하는 어플리케이션의 스프링 버전이 mymodule 과 다른 버전이면? 최종적으로 서로 다른 두 버전의 스프링 라이브러리가 필요하게 된다. 처음에 이 mymodule-spring 을 만들게 된 계기가 mybatis-spring 사용하고 난 후여서 mybatis-spring 의 pom.xml 을 확인해봤다. 링크

여기서 확인할 수 있었던 부분이 mybatis 가 spring 모듈을 사용한 부분에서 scope 를 provided로 지정해 준 것이었다.

<dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>${spring.version}</version>
      <scope>provided</scope>
</dependency>

provided scope 에 대해서 maven 의 문서를 보면 다음과 같다.

This is much like compile, but indicates you expect the JDK or a container to provide the dependency at runtime. For example, when building a web application for the Java Enterprise Edition, you would set the dependency on the Servlet API and related Java EE APIs to scope provided because the web container provides those classes. This scope is only available on the compilation and test classpath, and is not transitive.

위 내용은 번역해 보자면

이 스코프는 compile 과 유사하지만 JDK 나 container 가 의존성을 런타임에 제공한다. 예를 들면 JavaEE 웹 어플리케이션을 만들 때, Servlet API 나 JavaEE API 같은 의존성들은 provided 스코프로 지정하는데 이는 웹 컨테이너가 해당 클래스들을 제공하기 때문이다. (즉, 웹 컨테이너가 달라지면 웹 어플리케이션에 제공되는 부분들이 달라질 수 있다는 말) 이 스코프는 컴파일과 테스트 classpath 에서만 유효하고 transitive 하지 않다.

여기서 transitive 하다는 말은 (단어 번역을 잘 못하겠는데) 일반적으로 a 가 b 와 연관이 있고 b 가 c 와 연관이 있을 때, a 는 c와 연관이 있다고 말할 수 있는 상태이다. 즉 a 모듈이 b 를 의존성으로 가지면 c 역시 의존성으로 가지게 된다는 것이고 이는 maven 2.0 부터 지원되는 transitive dependencies 의 개념이다.

위 설명에서 provided 는 not transitive 하기 때문에 어플리케이션에서 mymodule 을 의존성으로 가져도 mymodule 에서 provided 로 선언된 스프링 라이브러리는 의존성을 가지지 않게 되는 결과를 가져온다.

그럼 고민 끝.