순서
이 기사는 주로 Java9로 마이그레이션하기위한 몇 가지 예방 조치를 연구합니다.
마이그레이션 유형
1. 코드는 모듈식이 아니며 먼저 JDK9로 마이그레이션하여 JDK9의 API를 사용합니다.
2. 코드도 모듈 식 마이그레이션됩니다
주목할만한 것들
읽을 수없는 클래스
예를 들어, Sun.security.x509는 Java9의 Java.base 모듈로 분류되지만 모듈은 패키지를 내보내지 않습니다.
-add-exports java.base/sun.security.x509 = 실행 중에 all-unname을 추가하여 내보내기 설정을 수정할 수 있습니다.
내부 수업
예를 들어, Sun.misc.unsafe는 원래 Oracle JDK 팀을 사용하고 싶었지만 이러한 클래스는 너무 널리 사용 되었기 때문에 Java9는 뒤로 호환성이되기 위해 타협했지만 이러한 클래스를 JDK.unsupported 모듈로 분류했으며 읽기 성을 제한하지 않았습니다.
➜ ~ ~ java -d jdk.unsupportedjdk.unsupported@9exports com.sun.nio.fileexports sun.miscexports sun.reflectrequires java.base mandateopens sun.miscopens sun.reflect
삭제 된 클래스
java9 삭제 된 sun.misc.base64encoder,이 경우 java.util.base64와 같은 다른 API 만 사용할 수 있습니다.
클래스 경로 대 모듈-경로
Java9는 모듈 시스템을 도입했으며 자체 JDK도 모듈화되었으며 모듈-경로가 클래스 경로에 도입되었습니다. 즉, Module-Path는 Java9에서 선호됩니다. 결국 JDK 자체는 모듈 식입니다. 응용 프로그램 자체가 모듈식이 아닌 경우 Java9는 이름없는 모듈 및 자동 모듈 메커니즘을 통해 암시 적으로 모듈화됩니다. 물론 ClassPath는 Module-Path 사용과 같은 Java9에서 계속 사용할 수 있습니다.
모듈성이없는 항아리는 ClassPath에서 이름없는 모듈로 분류됩니다. Module-Path에서는 자동 모듈로 자동으로 생성됩니다 (자동 모듈은 전이가 명명되지 않은 모든 모듈에 의존하고 자체 패키지를 내보내는 것으로 선언합니다).
여러 모듈 (분할 패키지)에는 패키지 이름이 나타날 수 없습니다.
내보내기는 모듈의 다른 모듈로 지정할 수 있으므로 여러 모듈이 동일한 패키지 이름을 내보내면 혼동이 발생합니다. 특히이 두 모듈이 동시에 필요한 다른 클래스 라이브러리가있는 경우 어떤 모듈을 참조 해야하는지 알 수 없습니다.
전이 의존성
인터페이스 매개 변수 또는 모듈의 반환 유형이 다른 모듈의 클래스를 사용하는 경우, 전이 모듈이 필요합니다.
원형 의존성에주의하십시오
모듈을 설계 할 때는 원형 의존성이 가능한 한 많은지 고려하십시오. 그렇다면 재 설계해야합니다.
서비스를 사용하여 선택적 종속성을 구현하십시오
서비스는 발신자 및 구현 클래스의 종속성을 분리하는 데 특히 적합합니다. 인터페이스에 여러 구현 클래스가있는 경우 발신자는 모든 구현 클래스를 요구할 필요가 없지만 요구 인터페이스 만 필요하며 서비스 유형을 사용하여 구현 클래스의 인스턴스를로드합니다. 디커플링은 모듈-경로에서 구현 모듈을 동적으로 추가하여 달성됩니다.
모듈 버전 관리
Module-Info.java는 버전 번호 선언을 지원하지 않지만 JAR 패키지를 만들 때-모듈 버전을 통해 설정할 수 있습니다. 그러나 모듈 시스템이 모듈을 검색 할 때 모듈 이름을 사용하여 검색 할 수 있습니다 (모듈-경로에 여러 중복 모듈이있는 경우 모듈 시스템은 처음 발견 된 모듈을 사용하여 동일한 이름으로 후속 모듈을 자동으로 무시합니다). 버전 종속성 문제는 모듈 시스템 솔루션의 범위 내에 있지 않으며 Maven과 같은 종속성 관리 도구에 맡겨집니다.
모듈 리소스 액세스
모듈화 후 리소스 파일도 보호되며 모듈은 모듈 자체의 리소스 파일에만 액세스 할 수 있습니다. 교차 모듈 액세스가 필요한 경우 Modulelayer를 사용하여 대상 모듈을 찾은 다음 대상 모듈을 호출하여 모듈의 리소스 파일을로드해야합니다.
반사 사용
여기에는 깊은 반사 문제가 포함됩니다. 소위 깊은 반사는 반사를 통해 클래스의 비공개 요소를 호출하는 것입니다. Module-Info.java의 내보내기는 패키지가 패키지가 직접적으로 속하는 클래스 만 공개 요소에 대한 액세스를 허용하고 비공개 요소에 대한 반사 호출을 허용하지 않는다고 선언합니다.
반사는 모듈 시스템에서 특별한 선언이 허용되어야합니다 (깊은 반사를 허용하기 위해 선언을 사용하여). 이는 Spring과 같은 반사를 사용하는 많은 클래스 라이브러리로 이어집니다. 두 가지 솔루션이 있습니다. 하나는 스프링과 같이 반사가 필요한 모듈에 패키지 이름을 엽니 다. 다른 하나는 전체 모듈을 직접 여는 것입니다.
기본적으로 -ILLEGAL-ACCESS = 허가를 받고이 설정은 JAVA9에서 액세스 할 수없는 JAVA9의 패키지에만 적용되며 JAVA9에서 액세스 할 수없는 새 패키지에는 적용 할 수 없습니다. (모듈 식 시스템으로 마이그레이션 할 때 거부하는 것이 좋습니다)
그러나 모듈 시스템에서는 패키지 이름이 다르며 상속 관계가 없습니다. 예를 들어, com.service.func1 및 com.service.func2는 다른 패키지입니다. Com.Service를 열 수는 없지만 별도로 지정해야하므로 개방이 필요한 더 많은 패키지로 연결됩니다. 따라서 전체 모듈을 여는 것이 사용하기 쉬울 수 있지만 비교적 거친 접근 방식이기도합니다.위의 방법은 원래 모듈 info.java를 변경하는 것입니다. 다른 방법은 Java 또는 Javac을 실행할 때 지정된 명령을 통해 원래 관계를 수정하는 것입니다. 예를 들어
Java ...-ADD-OPENS 소스 모듈/소스 패키지 = 대상 모듈
이름이없는 모듈로 내보내야하는 경우 대상 모듈이 모두 이름 지정됩니다.
물론 새로운 시스템 인 경우 반사를 사용하는 것이 좋습니다. 메소드 핸들 및 바탕 핸들을 사용할 수 있습니다.
FAQ 및 측정
classNotFoundException/noclassDeffoundError
예를 들어, javax.xml.bind.jaxbexception에서 jaxb는 java.xml.bind 모듈로 분류되었으며 Java 이름 지정 후에 추가됩니다.
--add-modules java.xml.bind
문제를 절약하려면 $ java_home 및 모든 타사 라이브러리를 모듈-경로에 추가 한 다음
-add-modules all-module-path
xxx에 의한 불법 반사 액세스 방법 java.lang.classload.defineclass
기존 시스템에는 모듈 인식이 없기 때문에 반사가 발생합니다. Java 이름 지정에 매개 변수를 추가하고 수정하십시오.
--add-opens java.base/java.lang = all-unname
종속성 모듈을 결정하십시오
IDE 또는 JDEP를 통한 분석
jdeps -class -path 'classs/lib/*' -재주문 -summary app.jar
JDEPS는 정적 코드 분석 일뿐입니다. 반사를 사용하는 클래스가 있으면 분석 할 수 없습니다. 수동으로 요구해야합니다. 종속성이 선택 사항 인 경우 정적이 필요할 수 있습니다.
모듈 단위 테스트의 가독성 문제
단위 테스트에 모듈을 사용하는 경우, 단위 테스트 모듈에 runtime시 --add-exports 또는 -add-opens를 통해 대상 모듈의 가독성 및 반사 기능을 부여 할 수 있습니다. 또한 분할 패키지 문제로 인해 단위 테스트 클래스의 패키지 이름을 대상 모듈 패키지 이름으로 복제 할 수 없습니다. Maven 프로젝트의 테스트는
요약
두 단계로 Java9로 이동할 수 있습니다. 먼저, 당신은 먼저 모듈식이 아니며, 먼저 JDK9에서만 실행됩니다. 그런 다음 모듈 식입니다.