자바 에서 Package Sealing 의 비밀 탐색 여행
JAR (자바 아 카 이브) 의 존재 가 없 었 다 면 자바 가 오늘 처럼 세상 을 크게 만 들 지 는 않 았 을 것 이다.JAR 은 다른 파일 이나 JAR 을 묶 고. jar 를 확장자 로 하 는 파일 이다.Zip 과 같은 형식 으로 압축 하기 때문에 Zip 압축 을 지원 하 는 모든 시스템 환경 에 적 용 됩 니 다.압축 형식 이기 때문에 네트워크 에서 의 전송 이 매우 빠르다.JAR 의 manifest 파일 은 JAR 패키지 에 대해 디지털 서명, 버 전 관리, 패키지 밀봉 (Seal), 프로그램의 실행 입구 설정 등 을 할 수 있 습 니 다. 또한 자바 5 부터 META - INFF 폴 더 에서 색인 파일 인 INDEX. LIST 를 생 성하 여 JAR 파일 의 클래스 로 딩 시간 을 크게 단축 시 킬 수 있 습 니 다.
이 글 은 주로 JAR 의 Package Sealing 기능 을 살 펴 본다.이 기능 은 자바 1.2 에 도입 되 었 다.Jar 파일 을 만 들 때 전체 Jar 나 그 중 몇 개의 Package 를 밀봉 할 지 여 부 를 지정 할 수 있 습 니 다. Jar 파일 전 체 를 밀봉 하 는 것 이 라면 그 안의 모든 Package 가 밀봉 되 었 음 을 의미 합 니 다.패키지 가 밀봉 되면 자바 가상 머 신 은 밀봉 패키지 의 한 종 류 를 성공 적 으로 불 러 온 후 같은 패키지 이름 을 가 진 모든 종 류 는 같은 Jar 파일 에서 나 와 야 합 니 다. 그렇지 않 으 면 Sealing Violation 안전 이상 을 촉발 합 니 다.긴 말 없 이 다음 과 같은 몇 가지 측면 에서 Package Sealing 의 비밀 여행 을 시작 합 시다.
Manifest 의 Package Sealing 설정
JAR 파일 이 어떻게 manifest 파일 을 통 해 Jar 파일 의 Package 를 밀봉 하 는 지 먼저 봅 시다.주로 두 가지 밀봉 방식 이 있다.
Manifest-Version: 1.0
Name: com/tr/algorithm/test/box/
Sealed: true
Name: com/tr/algorithm/search/
Sealed: true
Name: com/tr/multiThreads/
Sealed: true
Name: com/tr/algorithm/BinaryTree/
Sealed: true
위의 manifest 파일 중
몇몇 패키지 에 대해 밀봉 작업 을 했 지만 아래 의 manifest 파일 내용 은 Jar 파일 에 있 습 니 다.
모든 패 키 지 를 밀봉 합 니 다.
Manifest-Version: 1.0
Sealed: true
Java 소스 코드 분석 Sealing Violation
패키지 에 대해 어떻게 밀봉 하 는 지 알 게 된 후 자바 소스 코드 에서 어떻게 Sealing Violation 을 촉발 하 는 지 살 펴 보 자.제 가 사용 하 는 JDK 버 전 은 1.6 입 니 다.
java version "1.6.0_24"
Java(TM) SE Runtime Environment (build 1.6.0_24-b50)
Java HotSpot(TM) Client VM (build 19.1-b02, mixed mode)
다음은 URLClassLoader 에서 Package Sealing 을 안전하게 검사 하 는 코드 입 니 다. 설명 을 추가 하여 이해 하기 쉽 습 니 다.
String pkgname = name.substring(0, i);
Package pkg = getPackage(pkgname);
Manifest man = res.getManifest();
if (pkg != null) {
/*
* , com.seal.util.DateUtil.java, Package
* com.seal.util, ClassLoader 。
*/
if (pkg.isSealed()) {
/*
* , com.seal.util.DateUtil.java, Package com.seal.util ,
* URI Package , Jar
* 。
*/
if (!pkg.isSealed(url)) {
throw new SecurityException(
"sealing violation: package " + pkgname + " is sealed");
}
} else { // Package , 。
/*
* , com.seal.util.DateUtil.java , Package com.seal.util 。
* , 。 ,JVM Package 。
*/
if ((man != null) && isSealed(pkgname, man)) {
throw new SecurityException(
"sealing violation: can't seal package " + pkgname +
": already loaded");
}
}
} else {
/*
* Package ClassLoader , Package。
* Manifest , Manifest Package, , Package 。
*/
if (man != null) {
definePackage(pkgname, man, url);
} else {
definePackage(pkgname, null, null, null, null, null, null, null);
}
}
전체적으로 말 하면 Sealing 에 대한 안전 이상 을 촉발 하 는 두 가지 상황 이 있다.
Package Sealing 의 이점
Package Sealing 이 가 져 올 수 있 는 장점 은 주로 버 전의 일치 성 입 니 다. 자바 가 실 행 될 때 classpath 에서 정 의 된 순서에 따라 불 러 오고 검사 하 는 것 을 알 고 있 습 니 다. 특히 현재 자바 오픈 소스 패키지 가 가득 합 니 다. 자바 응용 프로그램 이나 미들웨어 의 classpath 에 같은 패키지 의 다른 버 전이 포 함 될 가능성 이 높 습 니 다.이것 은 프로그램 운행 에 일치 하지 않 는 결 과 를 만들어 발견 하기 어렵다.
Sealing Violation 실례
다음 두 가지 Sealing Violation 에 대한 예 를 살 펴 보면 쉽게 알 수 있 습 니 다.
버 전 업그레이드 예
첫 번 째 사례 의 큰 배경 은 발 표 된 Jar 가방 을 버 전 업그레이드 하여 사용자 에 게 사용 하 는 것 이다.버 전 1 에는 Dateutil 과 StringUtil 두 가지 가 있 습 니 다.
package com.seal.util;
public class DateUtil {
public void DoDateStuff(){
System.out.println("doing date stuffs in version 1.0");
}
}
package com.seal.util;
public class StringUtil {
public void DoStringStuff(){
System.out.println("doing string stuffs in version 1.0");
}
}
이 두 가지 종 류 는 우리 가 sealed 로 발표 합 니 다.v1.jar。 이 Jar 파일 은 이미 밀봉 되 었 으 며, Manifest 파일 의 내용 은 다음 과 같다.
Manifest-Version: 1.0
Sealed: true
버 전 2 에 서 는 NumberUtil 과 Dateutil 의 논 리 를 바 꾸 었 습 니 다.버 전 2 에서 발표 한 Jar 파일 은 sealedv2.jar。Manifest 파일 의 내용 은 버 전과 같 습 니 다.자바 클래스 코드 는 다음 과 같 습 니 다.
package com.seal.util;
public class DateUtil {
public void DoDateStuff(){
System.out.println("doing date stuffs in version 2.0");
}
}
package com.seal.util;
public class StringUtil {
public void DoStringStuff(){
System.out.println("doing string stuffs in version 2.0");
}
}
package com.seal.util;
public class NumberUtil {
public void DoNumberStuff(){
System.out.println("doing number stuffs in version 2.0");
}
}
이때 고객 에 게 사용 가능 한 Jar 버 전 은 sealed 버 전이 있 습 니 다.v1. jar 와 버 전 2 sealedv2.jar。사용자 에 게 다음 과 같은 테스트 클래스 가 있 습 니 다.
import com.seal.util.DateUtil;
import com.seal.util.NumberUtil;
import com.seal.util.StringUtil;
public class SealTestCase1 {
public static void main(String[] args){
DateUtil du = new DateUtil();
du.DoDateStuff();
StringUtil su = new StringUtil();
su.DoStringStuff();
NumberUtil nu = new NumberUtil();
nu.DoNumberStuff();
}
}
우 리 는 자바 명령 을 실행 하여 위의 테스트 클래스 를 컴 파일 하고 실행 합 니 다. 상기 두 Jar 파일 sealed 를 가정 합 니 다.v1. jar 와 sealedv2. jar, 그리고 SealTestCase 1 종 류 는 디 렉 터 리 D: \ sealing Test \ \ case 에 저 장 됩 니 다.1 중.
다음 명령 을 실행 하여 SealTestCase 1 종 류 를 컴 파일 합 니 다.
javac -classpath .;D:\sealingTest\case_1\sealed_v1.jar;D:\sealingTest\case_1\sealed_v2.jar SealTestCase1.java
다음 명령 을 실행 하여 SealTestCase 1 종 류 를 실행 합 니 다.
java -classpath .;D:\sealingTest\case_1\sealed_v1.jar;D:\sealingTest\case_1\sealed_v2.jar SealTestCase1
doing date stuffs in version 1.0
doing string stuffs in version 1.0
Exception in thread "main" java.lang.SecurityException: sealing violation: package com.seal.util is sealed
at java.net.URLClassLoader.defineClass(URLClassLoader.java:234)
at java.net.URLClassLoader.access$000(URLClassLoader.java:58)
at java.net.URLClassLoader$1.run(URLClassLoader.java:197)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:305)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:246)
at SealTestCase1.main(SealTestCase1.java:14)
이 Sealing Violation 은 바로 JDK 에서 정의 한 첫 번 째 상황 이다.이 Sealing Violation 이 발생 하 는 근본 적 인 원인 을 이해 하려 면 다음 코드 설명 을 보십시오.
public class SealTestCase1 {
public static void main(String[] args){
/*
* JVM com.seal.util.DateUtil , Classpath sealed_v1.jar ,
* ,com.seal.util.DateUtil sealed_v1.jar。 sealed_v1.jar 。
* JVM Package com.seal.util 。
*/
DateUtil du = new DateUtil();
du.DoDateStuff();
/*
* ,sealed_v1.jar classpath sealed_v2.jar ,
* com.seal.util.StringUtil sealed_v1.jar 。
* Package com.seal.util , com.seal.util.StringUtil
* com.seal.util.DateUtil Jar 。 , 。 。
*/
StringUtil su = new StringUtil();
su.DoStringStuff();
/*
* JVM com.seal.util.NumberUtil , sealed_v1.jar
* , sealed_v2.jar, 。
* JVM Package com.seal.util , sealed_v1.jar,
* sealed_v2.jar。 JVM 。
*/
NumberUtil nu = new NumberUtil();
nu.DoNumberStuff();
}
}
위의 원인 을 알 게 되면 우 리 는 할 수 있다.
장 sealedv1. jar 와 sealedv2. jar 가 classpath 에서 위 치 를 바 꾼 다음 다시 실행 합 니 다.
java -classpath .;D:\sealingTest\case_1\sealed_v2.jar;D:\sealingTest\case_1\sealed_v1.jar SealTestCase1
doing date stuffs in version 2.0
doing string stuffs in version 2.0
doing number stuffs in version 2.0
우 리 는 결과 가 정상적으로 나타 나 는 것 을 보 았 다.우 리 는 Package Sealing 이 버 전의 일치 성 을 보증 하 는 것 을 볼 수 있다.
제3자 발표 vs 공식 발표
두 번 째 예 는 어떤 공식 적 으로 밀 폐 된 Jar 파일 을 발 표 했 습 니 다. sealed_official_release.jar。그 종 류 는 아래 와 같다.
package com.seal.util;
public class DateUtil {
public void DoDateStuff(){
System.out.println("doing date stuffs officially");
}
}
package com.seal.util;
public class NumberUtil {
public void DoNumberStuff(){
System.out.println("doing number stuffs officially");
}
}
package com.seal.util;
public class StringUtil {
public void DoStringStuff(){
System.out.println("doing string stuffs officially");
}
}
그리고 이 공식 적 으로 발 표 된 Jar 파일 은 한 제3자 조직 에 의 해 변경 되 고 발표 되 었 다.Jar 파일 이름 unsealed_3rdparty_release.jar。원래 공식 적 으로 발 표 된 Jar 와 는 또 다른 점 이 있 습 니 다.
이 Jar 파일 은 밀봉 되 지 않 은 Jar 파일 입 니 다.내용 은 다음 과 같다.
package com.seal.util;
public class DateUtil {
public void DoDateStuff(){
System.out.println("doing modified date stuffs by third party");
}
}
package com.seal.util;
public class StringUtil {
public void DoStringStuff(){
System.out.println("doing modified string stuffs by third party");
}
}
이 때 사용자 의 손 에는 두 개의 다른 Jar 파일 이 있 을 수 있 으 며, 다음 프로그램 을 실행 해 야 합 니 다.
import com.seal.util.DateUtil;
import com.seal.util.NumberUtil;
import com.seal.util.StringUtil;
public class SealTestCase2 {
public static void main(String[] args){
DateUtil du = new DateUtil();
du.DoDateStuff();
StringUtil su = new StringUtil();
su.DoStringStuff();
NumberUtil nu = new NumberUtil();
nu.DoNumberStuff();
}
}
우 리 는 상술 한 두 개의 Jar 파일 sealed 를 가정 합 니 다.official_release.jar, unsealed_3rdparty_release. jar 와 클래스 SealTestCase 2. java 는 모두 디 렉 터 리 D: \ sealing Test \ \ case 에 있 습 니 다.2 중
다음 명령 을 실행 합 니 다. 컴 파일 류 SealTestCase 2. java.
javac -classpath .;D:\sealingTest\case_2\unsealed_3rdparty_release.jar;D:\sealingTest\case_2\sealed_official_release. jar SealTestCase 2. java 는 다음 명령 을 실행 하여 SealTestCase 2. java 를 실행 합 니 다.
java -classpath .;D:\sealingTest\case_2\unsealed_3rdparty_release.jar;D:\sealingTest\case_2\sealed_official_release.jar SealTestCase2
doing modified date stuffs by third party
doing modified string stuffs by third party
Exception in thread "main" java.lang.SecurityException: sealing violation: can't
seal package com.seal.util: already loaded
at java.net.URLClassLoader.defineClass(URLClassLoader.java:242)
at java.net.URLClassLoader.access$000(URLClassLoader.java:58)
at java.net.URLClassLoader$1.run(URLClassLoader.java:197)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:305)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:246)
at SealTestCase2.main(SealTestCase2.java:15)
이 Sealing Violation 은 바로 JDK 에서 정의 한 두 번 째 상황 이다.이 Sealing Violation 이 발생 하 는 근본 적 인 원인 을 이해 하려 면 다음 코드 설명 을 보십시오.
public class SealTestCase2 {
public static void main(String[] args){
/*
* JVM com.seal.util.DateUtil , Classpath unsealed_3rdparty_release.jar ,
* ,com.seal.util.DateUtil unsealed_3rdparty_release.jar。
* unsealed_3rdparty_release.jar 。
* JVM Package com.seal.util 。
*/
DateUtil du = new DateUtil();
du.DoDateStuff();
/*
* ,unsealed_3rdparty_release.jar classpath sealed_official_release.jar ,
* com.seal.util.StringUtil unsealed_3rdparty_release.jar 。
* Package com.seal.util ,
* , 。 。
*/
StringUtil su = new StringUtil();
su.DoStringStuff();
/*
* JVM com.seal.util.NumberUtil , unsealed_3rdparty_release.jar
* , sealed_official_release.jar, 。 sealed_official_release.jar
* 。 ,JVM Package com.seal.util 。
* JVM Package com.seal.util 。
* ,JVM 。
*/
NumberUtil nu = new NumberUtil();
nu.DoNumberStuff();
}
}
Jar 파일 sealedofficial_release.jar, unsealed_3rdparty_release. jar 의 순 서 는 classpath 에서 위 치 를 바 꾸 고 다음 명령 을 실행 합 니 다.
java -classpath .;D:\sealingTest\case_2\sealed_official_release.jar;D:\sealingTest\case_2\unsealed_3rdparty_release.jar SealTestCase2
doing date stuffs officially
doing string stuffs officially
doing number stuffs officially
우 리 는 고객 류 인 SealTestCase 2 가 실행 하 는 모든 종 류 는 공식 적 으로 발 표 된 Jar 파일 에서 나 온 것 을 보 았 다.그래서 버 전의 일치 성 을 확보 했다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
JPA + QueryDSL 계층형 댓글, 대댓글 구현(2)이번엔 전편에 이어서 계층형 댓글, 대댓글을 다시 리팩토링해볼 예정이다. 이전 게시글에서는 계층형 댓글, 대댓글을 구현은 되었지만 N+1 문제가 있었다. 이번에는 그 N+1 문제를 해결해 볼 것이다. 위의 로직은 이...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.