Tomcat 연구 의 ClassLoader
26065 단어 ClassLoader
1. Tomcat 의 ClassLoader:
TOMCAT 자체 클래스 로 더 (ClassLoader)
+---------------------------+
| Bootstrap |
| | |
| System |
| | |
| Common |
| / / |
| Catalina Shared |
+---------------------------+
그 중:
- Bootstrap - JVM 자체 클래스 와 $JAVA 불 러 오기HOME/jre/lib/ext/*.jar
- System
1. jndi. jar JNDI API 인터페이스, 이 패 키 지 는 자바 1.2 시 에 만 불 러 옵 니 다. 1.3 이후 버 전 JDK 는 자동 으로 불 러 옵 니 다.
2. naming - common. jar JNDI 인터페이스 구현 클래스, Tomcat 은 이러한 클래스 로 메모리 에 Context 를 사용 합 니 다.
3. naming - resources. jar JNDI 구현, Tomcat 는 웹 앱 의 정적 자원 을 찾 습 니 다.
4. servlet.jar Servlet,Jsp API
5. xerces. jar XML 해상도 기, 특정 웹 앱 은 자신의 / WEB - INF / lib 에 덮어 쓸 수 있 습 니 다.
- Catalina Tomcat 를 불 러 와 모든 인 터 페 이 스 를 실현 하 는 클래스 입 니 다. 이러한 클래스 는 웹 앱 에 전혀 보이 지 않 습 니 다. 모든 패키지 되 지 않 은 클래스 는 $CATALINA 에 있 습 니 다.HOME / server / classes 모든 jar 가방 $CATALINAHOME / server / lib 아래 에 있 습 니 다. 일반적인 상황 에서 이 ClassLoader 는 아래 의 몇 개의 가방 을 로드 합 니 다.
1. catalina. jar Servlet 용기 의 Tomcat 구현 패키지
2. jakarta - regexp - X. Y. jar 정규 표현 식, 필터 요청 시 사용
3. servlets - xxxx. jar Servlet 지원 패키지
4. tomcat - coyote. jar Tomcat 의 Coyote 연결 실현 패키지
5. tomcat - jk. jar 웹 서버 바 인 딩 패키지, Tomcat 바 인 딩 아파 치 등 을 웹 서버 로 허용
6. tomcat - jk2. jar 기능 동일
7. tomcat - util. jar Tomcat 도구 류, 일부 커 넥 터 에 사 용 될 수 있 습 니 다.
8. tomcat - warp. jar 는 아파 치 서버 패키지 에 사용
- Shared 모든 WEB APP 에서 볼 수 있 는 클래스 를 불 러 옵 니 다. TOMCAT 에 서 는 볼 수 없습니다.
$CATALINA_HOME / shared / classes 모든 jar 가방 $CATALINAHOME / lib 아래.
기본 상황 은 다음 가방 을 포함 합 니 다:
1. jasper - copiler. jar Jsp 컴 파일 러, Jsp 를 Servlet 로 컴 파일
2. jasper - runtime. jar JSp (Servlet 로 컴 파일 됨) 실행 지원 패키지
3. naming - factory. jar 는 웹 앱 이 JNDI 패 키 지 를 사용 하 는 것 을 지원 합 니 다.
-WebAppX 웹 앱 ClassLoader, 웹 앱 이 배 치 될 때 이 ClassLoader 가 생 성 됩 니 다. 모든 class 가 있 습 니 다.
WEB - INF / classes 에서 모든 jar 는 WEB - INF / lib 아래 에 있 습 니 다.
특히 WEB APP 자체 의 ClassLoader 구현 이 남 다 르 므 로 주의 하 시기 바 랍 니 다.
먼저 WEB APP 자신의 디 렉 터 리 에서 불 러 오 려 고 합 니 다. 실패 하면 부모 ClassLoader 의 프 록 시 를 요청 합 니 다. 그러면 서로 다른 WEB APP 간 의 클래스 를 불 러 오 는 데 방해 가 되 지 않 습 니 다. 또한 Tomcat Server 는 CatalinaClassLoader, 일반적인 웹 앱 에서 사용 하 는 WebApp ClassLoader 를 사용 합 니 다.
2. org. apache. catalina. startup. bootstrap
이 종 류 는 Tomcat 의 집행 입구 점 입 니 다. 우 리 는 다음 과 같은 두 가지 방법 을 중점적으로 분석 합 니 다.
2.1. initClassLoaders, ClassLoader 차원 만 들 기
private void initClassLoaders() {
try {
ClassLoaderFactory.setDebug(debug);
// common ClassLoader, ClassLoader
commonLoader = createClassLoader("common", null);
// catalina ClassLoader, ClassLoader common
catalinaLoader = createClassLoader("server",commonLoader);
// shared ClassLoader, ClassLoader common
sharedLoader = createClassLoader("shared",commonLoader);
} catch (Throwable t) {
log("Class loader creation threw exception", t);
System.exit(1);
}
}
2.2 createClassLoader, 구체 적 인 창설 담당
$CATALINAHOME / conf / catalina. properties 에 서 는 common, server, shared ClassLoader 가 불 러 오 는 경로 와 가방 의 보안 권한 을 정의 합 니 다.
//common
common.loader=${catalina.home}/common/classes,
${catalina.home}/common/endorsed/*.jar,${catalina.home}/common/lib/*.jar
//server
server.loader=${catalina.home}/server/classes,${catalina.home}/server/lib/*.jar
//shared
shared.loader=${catalina.base}/shared/classes,${catalina.base}/shared/lib/*.jar
/**
*param name:Load Name
*param parent: Loader
*classLoader :
*1. classes,
*2. jar
*3. , jar (Applet loader)
*/
private ClassLoader createClassLoader(String name, ClassLoader parent)
throws Exception {
// catalina.properties Loader
String value = CatalinaProperties.getProperty(name + ".loader");
if ((value == null) || (value.equals("")))
return parent;
//classes
ArrayList unpackedList = new ArrayList();
//jar
ArrayList packedList = new ArrayList();
//
ArrayList urlList = new ArrayList();
StringTokenizer tokenizer = new StringTokenizer(value, ",");
// Loader
while (tokenizer.hasMoreElements()) {
String repository = tokenizer.nextToken();
// Check for a JAR URL repository
try {
// url
urlList.add(new URL(repository));
continue;
} catch (MalformedURLException e) {
// Ignore
}
//
boolean packed = false;
//${catalina.home}
if (repository.startsWith(CATALINA_HOME_TOKEN)) {
repository = getCatalinaHome()
+ repository.substring(CATALINA_HOME_TOKEN.length());
//${catalina.base}
} else if (repository.startsWith(CATALINA_BASE_TOKEN)) {
repository = getCatalinaBase()
+ repository.substring(CATALINA_BASE_TOKEN.length());
}
/** , catalina.properties */
// jar
if (repository.endsWith("*.jar")) {
packed = true;
repository = repository.substring
(0, repository.length() - "*.jar".length());
}
if (packed) {
packedList.add(new File(repository));
} else {
unpackedList.add(new File(repository));
}
}
File[] unpacked = (File[]) unpackedList.toArray(new File[0]);
File[] packed = (File[]) packedList.toArray(new File[0]);
URL[] urls = (URL[]) urlList.toArray(new URL[0]);
// Factory ClassLoader
return ClassLoaderFactory.createClassLoader
(unpacked, packed, urls, parent);
}
3. ClassLoaderFactory
ClassLoader Factory 는 ClassLoader 를 만 드 는 공장 류 로 간단 합 니 다.
// ,
public static ClassLoader createClassLoader(File unpacked[],
File packed[],
URL urls[],
ClassLoader parent)
throws Exception {
if (debug >= 1)
log("Creating new class loader");
// Construct the "class path" for this class loader
ArrayList list = new ArrayList();
// class file url, list
if (unpacked != null) {
for (int i = 0; i < unpacked.length; i++) {
File file = unpacked[i];
if (!file.exists() || !file.canRead())
continue;
if (debug >= 1)
log(" Including directory or JAR "
+ file.getAbsolutePath());
URL url = new URL("file", null,
file.getCanonicalPath() + File.separator);
list.add(url.toString());
}
}
// jar jar , url, list
if (packed != null) {
for (int i = 0; i < packed.length; i++) {
File directory = packed[i];
if (!directory.isDirectory() || !directory.exists() ||
!directory.canRead())
continue;
String filenames[] = directory.list();
for (int j = 0; j < filenames.length; j++) {
String filename = filenames[j].toLowerCase();
if (!filename.endsWith(".jar"))
continue;
File file = new File(directory, filenames[j]);
if (debug >= 1)
log(" Including jar file " + file.getAbsolutePath());
URL url = new URL("file", null,
file.getCanonicalPath());
list.add(url.toString());
}
}
}
//
if (urls != null) {
for (int i = 0; i < urls.length; i++) {
list.add(urls[i].toString());
}
}
// StandardClassLoader Loader
String array[] = (String[]) list.toArray(new String[list.size()]);
StandardClassLoader classLoader = null;
if (parent == null)
classLoader = new StandardClassLoader(array);
else
classLoader = new StandardClassLoader(array, parent);
classLoader.setDelegate(true);
return (classLoader);
}
4. 표준 클래스 로 더
Standard ClassLoader 는 URLClassLoader 를 계승 합 니 다. URLClassLoader 류 는 하 드 디스크 디 렉 터 리 에서 클래스 를 불 러 오 거나 로 컬 또는 원 격 으로 jar 파일 을 불 러 오 는 능력 을 가지 고 있 습 니 다. 이 클래스 는 Reloader 인 터 페 이 스 를 실현 하여 자동 으로 클래스 를 다시 불 러 오 는 기능 을 제공 합 니 다. 우 리 는 주로 이 클래스 의 아래 와 방법 을 봅 니 다.
4.1. 구조 함수 표준 ClassLoader
/**
* @param repositories url ,
* @param parent loader
*/
public StandardClassLoader(String repositories[], ClassLoader parent) {
//
// repositories URLClassPath
//ucp ucp= new URLClassPath(urls);
// URLClassPath sun ,
super(convert(repositories), parent);
this.parent = parent;
this.system = getSystemClassLoader();
securityManager = System.getSecurityManager();
if (repositories != null) {
for (int i = 0; i < repositories.length; i++)
// url
addRepositoryInternal(repositories[i]);
}
}
4.2 addRepositoryInternal
/**
* @param repository url
*/
protected void addRepositoryInternal(String repository) {
URLStreamHandler streamHandler = null;
String protocol = parseProtocol(repository);
if (factory != null)
streamHandler = factory.createURLStreamHandler(protocol);
// url jar , jar
// jar , jar .
if (!repository.endsWith(File.separator) && !repository.endsWith("/")) {
JarFile jarFile = null;
try {
Manifest manifest = null;
//jar
if (repository.startsWith("jar:")) {
URL url = new URL(null, repository, streamHandler);
JarURLConnection conn =
(JarURLConnection) url.openConnection();
conn.setAllowUserInteraction(false);
conn.setDoInput(true);
conn.setDoOutput(false);
conn.connect();
jarFile = conn.getJarFile();
//file
} else if (repository.startsWith("file://")) {
jarFile = new JarFile(repository.substring(7));
//file
} else if (repository.startsWith("file:")) {
jarFile = new JarFile(repository.substring(5));
// jar
} else if (repository.endsWith(".jar")) {
URL url = new URL(null, repository, streamHandler);
URLConnection conn = url.openConnection();
JarInputStream jis =
new JarInputStream(conn.getInputStream());
manifest = jis.getManifest();
//
} else {
throw new IllegalArgumentException
("addRepositoryInternal: Invalid URL '" +
repository + "'");
}
} catch (Throwable t) {
t.printStackTrace();
throw new IllegalArgumentException
("addRepositoryInternal: " + t);
} finally {
if (jarFile != null) {
try {
jarFile.close();
} catch (Throwable t) {}
}
}
}
// url url
synchronized (repositories) {
String results[] = new String[repositories.length + 1];
System.arraycopy(repositories, 0, results, 0, repositories.length);
results[repositories.length] = repository;
repositories = results;
}
}
reposcories 는 모든 url 목록 을 저장 하 는 클래스 변수 입 니 다.
이 방법 을 통 해 우 리 는 기본적으로 몇 가 지 를 확정 할 수 있다.
1. ClassLoader 는 '/' 또는 File. separator 로 끝 나 는 경 로 를 불 러 오 는 자원 으로 할 수 있 습 니 다.
2. 로 컬 이나 네트워크 에 있 는 jar 파일 을 class 를 불 러 오 는 자원 으로 할 수도 있 습 니 다. 다른 모든 형식의 자원 (예 를 들 어 zip) 은 합 법 적 이지 않 습 니 다.
3. 네트워크 의 자원 은 jar 패키지 형식 이 어야 합 니 다.
여기까지, ClassLoader 의 구조 가 끝 났 습 니 다.
4.3 loadclass 방법
위 에서 우 리 는 많은 일 을 했 습 니 다. 그 목적 은 classLoader 를 구축 하 는 것 입 니 다. ClassLoader 를 구축 하 는 목적 은 그것 으로 원 하 는 class 를 로드 하 는 것 입 니 다. 따라서 loadClass 방법 이 우리 의 중심 이 고 이 를 통 해 ClassLoader 의 신비 한 베일 을 철저히 풀 수 있 습 니 다.
/**
*param name: load
*param resolve: true resolveClass
*/
public Class loadClass(String name, boolean resolve)
throws ClassNotFoundException {
if (debug >= 2)
log("loadClass(" + name + ", " + resolve + ")");
Class clazz = null;
// , load
clazz = findLoadedClass(name);
if (clazz != null) {
if (debug >= 3)
log(" Returning class from cache");
if (resolve)
resolveClass(clazz);
return (clazz);
}
// java ClassLoader load
if( name.startsWith("java.") ) {
ClassLoader loader = system;
clazz = loader.loadClass(name);
if (clazz != null) {
if (resolve)
resolveClass(clazz);
return (clazz);
}
throw new ClassNotFoundException(name);
}
// load, load catalina.properties
if (securityManager != null) {
int i = name.lastIndexOf('.');
if (i >= 0) {
try {
securityManager.checkPackageAccess(name.substring(0,i));
} catch (SecurityException se) {
String error = "Security Violation, attempt to use " +
"Restricted Class: " + name;
System.out.println(error);
se.printStackTrace();
log(error);
throw new ClassNotFoundException(error);
}
}
}
// ClassLoader
if (delegate) {
if (debug >= 3)
log(" Delegating to parent classloader");
ClassLoader loader = parent;
if (loader == null)
loader = system;
try {
clazz = loader.loadClass(name);
if (clazz != null) {
if (debug >= 3)
log(" Loading class from parent");
if (resolve)
resolveClass(clazz);
return (clazz);
}
} catch (ClassNotFoundException e) {
;
}
}
//
if (debug >= 3)
log(" Searching local repositories");
try {
// Tomcat ClassLoader
clazz = findClass(name);
if (clazz != null) {
if (debug >= 3)
log(" Loading class from local repository");
if (resolve)
resolveClass(clazz);
return (clazz);
}
} catch (ClassNotFoundException e) {
;
}
// , loader
if (debug >= 3)
log(" Delegating to parent classloader");
ClassLoader loader = parent;
if (loader == null)
loader = system;
try {
clazz = loader.loadClass(name);
if (clazz != null) {
if (debug >= 3)
log(" Loading class from parent");
if (resolve)
resolveClass(clazz);
return (clazz);
}
} catch (ClassNotFoundException e) {
;
}
}
// This class was not found
throw new ClassNotFoundException(name);
}
4.4 findClass 방법
public Class findClass(String name) throws ClassNotFoundException {
if (debug >= 3)
log(" findClass(" + name + ")");
// ,
if (securityManager != null) {
int i = name.lastIndexOf('.');
if (i >= 0) {
try {
if (debug >= 4)
log(" securityManager.checkPackageDefinition");
securityManager.checkPackageDefinition(name.substring(0,i));
} catch (Exception se) {
if (debug >= 4)
log(" -->Exception-->ClassNotFoundException", se);
throw new ClassNotFoundException(name);
}
}
}
//
// (throws ClassNotFoundException if it is not found)
Class clazz = null;
try {
if (debug >= 4)
log(" super.findClass(" + name + ")");
try {
synchronized (this) {
clazz = findLoadedClass(name);
if (clazz != null)
return clazz;
//
clazz = super.findClass(name);
}
} catch(AccessControlException ace) {
throw new ClassNotFoundException(name);
} catch (RuntimeException e) {
if (debug >= 4)
log(" -->RuntimeException Rethrown", e);
throw e;
}
if (clazz == null) {
if (debug >= 3)
log(" --> Returning ClassNotFoundException");
throw new ClassNotFoundException(name);
}
} catch (ClassNotFoundException e) {
if (debug >= 3)
log(" --> Passing on ClassNotFoundException", e);
throw e;
}
// Return the class we have located
if (debug >= 4)
log(" Returning class " + clazz);
if ((debug >= 4) && (clazz != null))
log(" Loaded by " + clazz.getClassLoader());
return (clazz);
}
4.5 부모 클래스 (URLClassLoader) 의 findClass 방법
앞에서 말 했 듯 이 URLClassLoader 는 로 컬 에서 class 를 불 러 오고 로 컬 이나 네트워크 에서 jar 를 불 러 오 는 기능 을 가지 고 있 습 니 다.
쉽게 말 하면 findClass 방법 은 Privileged ExceptionAction 의 run 방법 을 간단하게 호출 했 을 뿐 입 니 다. 이런 유형 에 대해 서 는 자세히 알 필요 가 없습니다. 아래 에 파란색 을 치 는 부분 만 보면 됩 니 다.
protected Class findClass(final String name) throws ClassNotFoundException {
try {
return (Class)
AccessController.doPrivileged(new PrivilegedExceptionAction() {
public Object run() throws ClassNotFoundException {
//
String path = name.replace('.', '/').concat(".class");
// ucp
// class Resource( )
Resource res = ucp.getResource(path, false);
if (res != null) {
try {
// Resource Class
return defineClass(name, res);
} catch (IOException e) {
throw new ClassNotFoundException(name, e);
}
} else {
throw new ClassNotFoundException(name);
}
}
}, acc);
} catch (java.security.PrivilegedActionException pae) {
throw (ClassNotFoundException) pae.getException();
}
}
4.6 define Class 방법
이 방법 은 주로 JVM 의 native 방법 으로 class 대상 을 구축 하 는 것 입 니 다. 이러한 세부 사항 에 대해 서 는 제거 할 필요 가 없습니다. JVM 이 Resource 를 이용 하여 Class 대상 을 구 조 했 습 니 다. 아래 파란색 부분 만 주목 하 십시오.
/**
*param name:
*param res: ucp ,ucp url ,url
*ClassLoader Load Class
* StandClassLoader Resource
*Resource JVM Class
*/
private Class defineClass(String name, Resource res) throws IOException {
int i = name.lastIndexOf('.');
URL url = res.getCodeSourceURL();
if (i != -1) {
String pkgname = name.substring(0, i);
// Check if package already loaded.
Package pkg = getPackage(pkgname);
Manifest man = res.getManifest();
if (pkg != null) {
// Package found, so check package sealing.
if (pkg.isSealed()) {
// Verify that code source URL is the same.
if (!pkg.isSealed(url)) {
throw new SecurityException(
"sealing violation: package " + pkgname + " is sealed");
}
} else {
// Make sure we are not attempting to seal the package
// at this code source URL.
if ((man != null) && isSealed(pkgname, man)) {
throw new SecurityException(
"sealing violation: can't seal package " + pkgname +
": already loaded");
}
}
} else {
if (man != null) {
definePackage(pkgname, man, url);
} else {
definePackage(pkgname, null, null, null, null, null, null, null);
}
}
}
// JVM Class
byte[] b = res.getBytes();
java.security.cert.Certificate[] certs = res.getCertificates();
CodeSource cs = new CodeSource(url, certs);
return defineClass(name, b, 0, b.length, cs);
}
이로써 우 리 는 Tomcat 의 ClassLoader 를 철저히 파 역 했 습 니 다. 다음은 ClassLoader 의 구조 와 loadClass 의 과정 을 다시 그 려 보 겠 습 니 다. 여 기 는 sequence 그림 을 그리 지 않 고 각 방법 간 의 호출 관 계 를 간단하게 표시 할 뿐 입 니 다.
사실 위 에서 우리 가 진정 으로 ClassLoader 를 만 드 는 관건 적 인 역할 을 할 수 있 는 것 은 URLClassLoader 와 JVM 의 defineClass 방법 입 니 다. 이런 방법 들 은 이미 봉인 되 었 거나 로 컬 호출 되 었 기 때문에 더 연구 하려 면 더 많은 정력 을 들 여야 합 니 다. 이 절 차 를 읽 은 후에 모든 사람 이 자신 이 필요 로 하 는 ClassLoader, 예 를 들 어 암호 화 ClassLoader 등 을 맞 출 수 있 을 것 이 라 고 믿 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
자바, jar 패키지 에서 자원 파일 읽 기리 소스 Jar. jar 의 리 소스 클래스 를 호출 할 때 JVM 은 리 소스 클래스 에 불 러 오고 리 소스 가 실 행 될 때의 정 보 를 기록 합 니 다 (리 소스 가 있 는 jar 패키지 의 경로 정보 포함)...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.