V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
tomoya92
V2EX  ›  问与答

求问 springboot 项目怎么加载 jar 包中的 bean

  •  
  •   tomoya92 · 2019-06-07 10:04:53 +08:00 · 5246 次点击
    这是一个创建于 1995 天前的主题,其中的信息可能已经有所发展或是发生改变。

    主项目 pybbs,启动类包名 co.yiiu.pybbs 配置了扫描包 @SpringBootApplication(scanBasePackages = "co.yiiu.pybbs")

    另外创建了一个 maven 项目,写了一个 bean,名包是 co.yiiu.pybbs.plugin 类上也加了 @Component 注解


    首先我把新建的 maven 项目通过 mvn install 安装到本地,然后在 pybbs 里通过 pom 引入,启动项目测试没有问题,可以扫描到新建包中的 bean 以及方法的调用


    然后我又通过 mvn assembly:assembly 把 pybbs 打包了,在 assembly 里配置了程序 jar 包和引入信赖 jar 包分享的方式来打包的,生成的目录中会有一个 lib 文件夹,然后我把新建的 maven 项目也打成 jar 包,然后拷贝到 pybbs/lib 目录中,启动项目就有问题了,spring 不会去扫描 jar 包中的 bean,方法也没有生效


    求问:

    spring 怎么加载外部 jar 包中的 bean 呢?

    下面有我两个项目的配置,大佬们帮忙看下是我哪配置错了吗?万分感谢!!!


    pybbs 中的 pom.xml build 配置

    <build>
    
        <finalName>pybbs</finalName>
    
        <resources>
          <resource>
            <directory>src/main/java</directory>
            <includes>
              <include>**/*.xml</include>
            </includes>
            <filtering>true</filtering>
          </resource>
          <resource>
            <directory>src/main/resources</directory>
          </resource>
        </resources>
    
        <plugins>
    
          <!--springboot 插件
          <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
          </plugin>-->
    
          <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>2.6</version>
            <configuration>
              <!-- 如果是 true 在打出来的包 /路径上面会增加这个 Assembly 的 id 显示-->
              <appendAssemblyId>false</appendAssemblyId>
              <descriptors>
                <!-- assembly 描述文件位置 -->
                <descriptor>src/main/resources/assembly.xml</descriptor>
              </descriptors>
              <!-- 打包完成后文件输出位置 这里为 target 目录-->
              <outputDirectory>${project.build.directory}</outputDirectory>
            </configuration>
          </plugin>
          <plugin>
            <!-- 主要用来打包主 jar-->
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>2.6</version>
            <configuration>
              <archive>
                <manifest>
                  <!--启动文件入口类,就是 springboot 启动 main 方法所在类 -->
                  <mainClass>co.yiiu.pybbs.PybbsApplication</mainClass>
                  <!-- 主 jar 依赖的 jar 包路径-->
                  <classpathPrefix>lib/</classpathPrefix>
                  <addClasspath>true</addClasspath>
                </manifest>
                <!--<manifestEntries>
                  &lt;!&ndash; 在 Class-Path 下添加配置文件的路径 &ndash;&gt;
                  <Class-Path>resources</Class-Path>
                </manifestEntries>-->
              </archive>
              <!-- 不把配置文件和 html 文件打进主 jar 内-->
              <excludes>
                <exclude>*.java</exclude>
                <exclude>static/</exclude>
                <exclude>db/</exclude>
                <exclude>templates/</exclude>
                <exclude>*.yml</exclude>
                <exclude>*.txt</exclude>
                <exclude>logback.xml</exclude>
              </excludes>
            </configuration>
          </plugin>
    
          <!-- 打包发布时,跳过单元测试 -->
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <configuration>
              <skipTests>true</skipTests>
            </configuration>
          </plugin>
    
        </plugins>
      </build>
    

    assembly.xml 配置

    <assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
    
      <id>package</id>
      <formats>
        <!-- 打包成目录,这里其实有很多选择,如 dir,jar,war,zip 等,我们这里选择先打成目录,到真正要用的时候可以打包成 zip-->
        <format>tar.gz</format>
        <!--<format>dir</format>-->
      </formats>
    
      <includeBaseDirectory>false</includeBaseDirectory>
    
      <fileSets>
        <!-- 把项目相关的说明文件,打包进 zip 文件的根目录 -->
        <fileSet>
          <directory>${project.basedir}</directory>
          <outputDirectory></outputDirectory>
          <excludes>
            <exclude>logback.xml</exclude>
            <exclude>static/**</exclude>
            <exclude>*.json</exclude>
            <exclude>pom.xml</exclude>
            <exclude>target/**</exclude>
            <exclude>mysql/**</exclude>
            <exclude>docs/**</exclude>
            <exclude>logs/**</exclude>
            <exclude>src/**</exclude>
            <exclude>sql/**</exclude>
            <exclude>.idea/**</exclude>
            <exclude>.gitignore</exclude>
            <exclude>.classpath</exclude>
            <exclude>.factorypath</exclude>
            <exclude>.project</exclude>
            <exclude>application.pid</exclude>
            <exclude>pybbs.iml</exclude>
            <exclude>pybbs.pid</exclude>
            <exclude>.settings/**</exclude>
            <exclude>Dockerfile</exclude>
            <exclude>docker-compose.yml</exclude>
            <exclude>application-docker.yml</exclude>
            <exclude>application-dev.yml</exclude>
          </excludes>
        </fileSet>
        <!-- 把项目的配置文件,打包进 zip 文件的根目录 -->
        <fileSet>
          <directory>${project.basedir}/src/main/resources</directory>
          <outputDirectory></outputDirectory>
          <excludes>
            <exclude>assembly.xml</exclude>
            <exclude>static/upload/**</exclude>
            <exclude>i18n/**</exclude>
          </excludes>
          <!--  <excludes>
               <exclude>**</exclude>
            </excludes>-->
        </fileSet>
        <!-- 把项目的脚本文件,打包进 zip 文件的 bin 目录-->
        <fileSet>
          <directory>${project.basedir}/src/main/bin</directory>
          <outputDirectory>bin</outputDirectory>
          <excludes>
            <exclude>target/**</exclude>
            <exclude>*.json</exclude>
            <exclude>static/**</exclude>
            <exclude>templates/**</exclude>
          </excludes>
        </fileSet>
      </fileSets>
    
      <dependencySets>
        <!-- 打包依赖文件,就是 maven 里面那一堆 jar 包-->
        <dependencySet>
          <outputDirectory>/lib</outputDirectory>
          <scope>runtime</scope>
          <!-- 除了主 jar 文件都打到 lib 目录下-->
          <excludes>
            <exclude>${project.groupId}:${project.artifactId}</exclude>
          </excludes>
        </dependencySet>
        <!-- 主 jar 打到根目录,因为 pom 文件中设置主 jar 的依赖包目录为 lib/-->
        <dependencySet>
          <outputDirectory>/</outputDirectory>
          <outputFileNameMapping>${artifact.artifactId}${dashClassifier?}.${artifact.extension}</outputFileNameMapping>
          <includes>
            <include>${project.groupId}:${project.artifactId}</include>
          </includes>
        </dependencySet>
      </dependencySets>
    </assembly>
    

    新建 maven 项目中 pom.xml build 节点配置

    <build>
        <finalName>pybbs-redis-cache-plugin</finalName>
        <plugins>
          <!-- 编译指定 jdk 版本号 -->
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.1</version>
            <configuration>
              <source>1.8</source>
              <target>1.8</target>
              <encoding>UTF-8</encoding>
              <showWarnings>true</showWarnings>
            </configuration>
          </plugin>
          <!-- 部署带上源文件, 可以在引入依赖时看到源码, 以及源码上的注释信息 -->
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-source-plugin</artifactId>
            <version>3.0.1</version>
            <configuration>
              <includePom>true</includePom>
              <excludeResources>true</excludeResources>
              <attach>true</attach>
            </configuration>
            <executions>
              <execution>
                <id>attach-sources</id>
                <goals>
                  <goal>jar</goal>
                </goals>
              </execution>
            </executions>
          </plugin>
        </plugins>
      </build>
    
    14 条回复    2019-06-08 09:03:17 +08:00
    happypy1
        1
    happypy1  
       2019-06-07 10:59:01 +08:00
    @SpringBootApplication(scanBasePackages = "co.yiiu.pybbs")

    你把你的那个 jar 里的包也加进去试试看?
    visaxin906
        2
    visaxin906  
       2019-06-07 11:01:08 +08:00
    spring context -> read xml -> scan bean
    tomoya92
        3
    tomoya92  
    OP
       2019-06-07 11:04:18 +08:00
    @happypy1 #1 jar 中的包名跟 pybbs 的包名一样,帖子内容中有说明,就是扫不到。。
    tomoya92
        4
    tomoya92  
    OP
       2019-06-07 11:05:43 +08:00
    @visaxin906 #2 你的意思是在 jar 包中写一个 xml 来声明 jar 包中的 bean,然后在 pybbs 里通过
    tomoya92
        5
    tomoya92  
    OP
       2019-06-07 11:06:23 +08:00
    @tomoya92 #4 你的意思是在 jar 包中写一个 xml 来声明 jar 包中的 bean,然后在 pybbs 里通过 applicationContext 来读取 jar 包中的 xml 配置文件从而达到加载 jar 包中的 bean 的目的吗?
    br00k
        6
    br00k  
       2019-06-07 14:07:50 +08:00
    你应该使用 starter 组件开发。在组件 spring.factories 的配置里指定配置文件,在配置文件里注解设置包扫描路径。
    c4f36e5766583218
        7
    c4f36e5766583218  
       2019-06-07 14:18:51 +08:00
    1. 使用包扫描扫到那个 bean (如果这个 bean 有扫描注解)
    2. xml 配置
    3. java 配置
    limuyan44
        8
    limuyan44  
       2019-06-07 16:28:40 +08:00 via Android
    按 spring 方式正常引就好了,不是入门的基础吗。
    MoHen9
        9
    MoHen9  
       2019-06-07 21:50:21 +08:00 via Android
    如果普通方式运行是正常的,那就是打包的原因了,真的将依赖和配置打包进去的话,不应该出现扫描不到的问题,建议用解压软件看看打的 jar 结构,从来没用过 mvn assembly 这种命令打包,一般不是用 mvn build 打包吗?
    Leiothrix
        10
    Leiothrix  
       2019-06-07 22:36:32 +08:00
    老哥,
    Leiothrix
        11
    Leiothrix  
       2019-06-07 22:42:13 +08:00
    老哥,你新建的那个 maven 项目也有 Spring Boot 的依赖吗?如果有依赖且存在启动类的话是不可以直接打成 jar 包作为依赖的哦,这是一个陷阱。可执行 Spring Boot 项目打出来的默认 jar 包不可以作为依赖。你可以去查阅一下相关材料,然后最好建一个普通的 maven 项目去放置通用的 common 类。
    tomoya92
        12
    tomoya92  
    OP
       2019-06-08 08:56:48 +08:00
    @Leiothrix #11 新建的那个项目就是个普通的 maven 项目,没有 springboot 依赖
    tomoya92
        13
    tomoya92  
    OP
       2019-06-08 08:58:39 +08:00
    @br00k #6 一样的吧,starter 不是也要打包后然后配置在 springboot 主项目里吗?

    难道 staretr 开发好之后,放在 lib 目录中就可以默认加载了?
    tomoya92
        14
    tomoya92  
    OP
       2019-06-08 09:03:17 +08:00
    @MoHen9 #9 貌似找到原因了,在主项目里打包后,生成的 jar 包里有个 MANIFEST.MF 文件,里面定义了 Class-Path: xxx.jar 所有依赖的 jar 包都在这定义好了,所以项目在启动的时候才会加载这些 jar 包

    我新建的那个 maven 项目打成的 jar 包没有引入到项目的 pom 文件里,所以在打主项目的 jar 包时,这个 Class-Path 里就没有我开发的那个 jar 包,这也导致了项目启动的时候不加载它

    原因找到了,然后我就在尝试配置 maven-jar-plugin 插件,增加上了 lib/* 打包识别不了,换成 lib/*.jar 也识别不了,这个插件好像不支持通配符

    然后就只能在启动项目之后,手动去使用 spring 的一些工具类将插件里开发的类加载到 ioc 容器里了,现在还没有折腾出来。。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2599 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 15:21 · PVG 23:21 · LAX 07:21 · JFK 10:21
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.