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

2019-06-07 10:04:53 +08:00
 tomoya92

主项目 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>
5246 次点击
所在节点    问与答
14 条回复
happypy1
2019-06-07 10:59:01 +08:00
@SpringBootApplication(scanBasePackages = "co.yiiu.pybbs")

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

难道 staretr 开发好之后,放在 lib 目录中就可以默认加载了?
tomoya92
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 容器里了,现在还没有折腾出来。。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/571729

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX