Springboot 패키지 실행 소스 분석

6841 단어
포장
Springboot을 포장할 때 마븐 플러그인을 설정해야 합니다 [spring-boot-maven-plugin]

    
        
            org.springframework.boot
            spring-boot-maven-plugin
        
    


이 플러그인은 다음과 같은 5가지 기능 모듈을 제공합니다.
  • build-info: 프로젝트를 생성하는 구축 정보 파일build-info.properties
  • repackage: 기본 goal.mvn 패키지가 실행된 후에 실행 가능한jar/war를 다시 포장하고 mvn 패키지가 생성한jar/war를 ***로 이름을 바꿉니다.origin
  • run: 이것은 Spring Boot 응용 프로그램을 실행할 수 있습니다
  • start: 이것은 mvn integration-test 단계에서 Spring Boot 응용 생명주기 관리
  • stop: 이것은 mvn integration-test 단계에서 Spring Boot 응용 생명주기 관리
  • mvn 패키지 패키지의 이름이 바뀌지 않으려면classifier를 설정하면 Springboot 패키지에서 실행 가능한jar가 XXX-executable입니다.jar이야.
    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
                    
                        executable
                    
            
        
    
    

    구별
    Springboot이 친 가방과 Maven이 친 가방의 차이는 어디에 있을까요?maven package에 싸인 가방 a.jar.original의 이름을 a-original로 변경합니다.jar;그리고 Springboot에서 싸운 가방 a.jar와 비교해 보니 Springboot에서 싸운 가방의MANIFEST가 발견됐어요.MF 파일의 행은 다음과 같습니다.
    ...
    Main-Class: org.springframework.boot.loader.JarLauncher
    Start-Class: com.xxx.XxxApplication
    ...
    

    이곳의 Start-Class는 바로 우리가 쓴 코드의main 입구류입니다.Main-Class는 Springboot이 우리에게 추가한 시작 클래스입니다.
    3. 원본 디버그
    Springboot 실행 가능jar의 실행 과정을 이해하려면 가장 좋은 방법은 debug입니다.다음은 먼저 배치해 보겠습니다.
  • jar 명령 실행 설정
    일반적으로jar를 실행하는 명령은java-jarxx입니다.jar debug는 디버그 포트를 열어야 합니다. 명령은 java-agentlib: jdwp=transport=dtsocket,server=y,address=5005,suspend=y -jar xxx.jar
  • 아이디어에remote debug를 설정하고 포트 번호를 5005로 설정하며 Host는localhost
  • 로 설정합니다.
  • 프로젝트의pom.xml에서spring-boot-loader의maven 의존
    
        org.springframework.boot
        spring-boot-loader
        1.5.10.RELEASE
    
    
  • 증가
  • 상기 설정을 완성한 후 debug 시작 프로그램을 시작하고 아이디어의 디버깅
  • 을 엽니다.
    4. 원본 코드 해석
  • 앞에서 말한 Main-Class 즉 org를 먼저 보세요.springframework.boot.loader.JarLauncher
    public class JarLauncher extends ExecutableArchiveLauncher {
    
    	static final String BOOT_INF_CLASSES = "BOOT-INF/classes/";
    
    	static final String BOOT_INF_LIB = "BOOT-INF/lib/";
    
    	public JarLauncher() {
    	}
    
    	protected JarLauncher(Archive archive) {
    		super(archive);
    	}
    
    	@Override
    	protected boolean isNestedArchive(Archive.Entry entry) {
    		if (entry.isDirectory()) {
    			return entry.getName().equals(BOOT_INF_CLASSES);
    		}
    		return entry.getName().startsWith(BOOT_INF_LIB);
    	}
    
    	public static void main(String[] args) throws Exception {
    		new JarLauncher().launch(args);
    	}
    
    }
    
  • 부모 추상류인 Launcher에 따라가는 launch 방법은 이 방법에서 getClassPathArchives ()를 통해jar 가방에 있는jar를 Archive 대상 목록으로 추상화한다.Springboot loader에서는 Archive 개념을 추상화합니다.archive는jar(JarFileArchive)일 수도 있고 파일 디렉터리(ExplodedArchive)일 수도 있다.이것들은 모두 Springboot에서 추상적으로 나온 통일된 접근 자원의 층으로 이해할 수 있다.이 List에는 다음이 포함됩니다.
  • \BOOT-INF\classes(프로젝트의 class)
  • \BOOT-INF\lib 디렉토리의 모든jar
  • List를 누비고 각 Archive의 URL을 획득하여 List
  • 를 구성합니다.
  • 사용자 정의 클래스 로더를 만듭니다.이 클래스 마운트는 jdk가 자체로 가지고 있는java를 계승합니다.net.URLClassLoader
  • 불러오기,Main Method Runner를 만들고 Launcher를 보는 방법, 논리가 뚜렷하다
    public abstract class Launcher {
    
        /**
         * 1、  List
         * 2、  LaunchedURLClassLoader
         * 3、  main class
         * 4、  
         */
        protected void launch(String[] args) throws Exception {
            JarFile.registerUrlProtocolHandler();
            ClassLoader classLoader = createClassLoader(getClassPathArchives());
            launch(args, getMainClass(), classLoader);
        }
    
        /**
         *   classloader
         */
        protected ClassLoader createClassLoader(List archives) throws Exception {
            List urls = new ArrayList(archives.size());
            for (Archive archive : archives) {
                urls.add(archive.getUrl());
            }
            return createClassLoader(urls.toArray(new URL[urls.size()]));
        }
    
        /**
         *   LaunchedURLClassLoader
         */
        protected ClassLoader createClassLoader(URL[] urls) throws Exception {
            return new LaunchedURLClassLoader(urls, getClass().getClassLoader());
        }
    
        /**
         *      classloader,  main class
         */
        protected void launch(String[] args, String mainClass, ClassLoader classLoader)
                throws Exception {
            Thread.currentThread().setContextClassLoader(classLoader);
            createMainMethodRunner(mainClass, args, classLoader).run();
        }
    
        /**
         *   MainMethodRunner
         */
        protected MainMethodRunner createMainMethodRunner(String mainClass, String[] args, ClassLoader classLoader) {
            return new MainMethodRunner(mainClass, args);
        }
    
        /**
         *     ,    main class
         */
        protected abstract String getMainClass() throws Exception;
    
        /**
         *     ,    List
         */
        protected abstract List getClassPathArchives() throws Exception;
    
        protected final Archive createArchive() throws Exception {
            ProtectionDomain protectionDomain = getClass().getProtectionDomain();
            CodeSource codeSource = protectionDomain.getCodeSource();
            URI location = (codeSource == null ? null : codeSource.getLocation().toURI());
            String path = (location == null ? null : location.getSchemeSpecificPart());
            if (path == null) {
                throw new IllegalStateException("Unable to determine code source archive");
            }
            File root = new File(path);
            if (!root.exists()) {
                throw new IllegalStateException(
                        "Unable to determine code source archive from " + root);
            }
            return (root.isDirectory() ? new ExplodedArchive(root)
                    : new JarFileArchive(root));
        }
    }
    
  • MainMethodRunner의run 방법을 실행하고 메인 클래스의main
    public class MainMethodRunner {
    
        private final String mainClassName;
    
        private final String[] args;
    
        public MainMethodRunner(String mainClass, String[] args) {
            this.mainClassName = mainClass;
            this.args = (args == null ? null : args.clone());
        }
    
        /**
         *       main  ,  invoke
         */
        public void run() throws Exception {
            Class> mainClass = Thread.currentThread().getContextClassLoader()
                    .loadClass(this.mainClassName);
            Method mainMethod = mainClass.getDeclaredMethod("main", String[].class);
            mainMethod.invoke(null, new Object[] { this.args });
        }
    }
    
    
  • 을 시작합니다.

    좋은 웹페이지 즐겨찾기