关于spring 扫描不到jar中class文件的原因分析及解决

目录
  • spring 扫描不到jar中class文件的原因及解决
    • 背景
    • Q: 那么我们怎么解决spring 扫描不到jar中class这个问题呢?
    • Q: 那么我们怎么打包成Runable JAR FILE,并且解决spring 扫描不到jar中class的问题?
    • 大功告成
  • @ComponentScan注解进行扫描的几种方式
    • 方式一:扫描包
    • 方式二:扫描类
    • 方式三:扫描包(通配式:开发常用)

spring 扫描不到jar中class文件的原因及解决

背景

公司一web项目使用的是spring mvc开发的,老员工们写了一个缓存service,即EhcacheService , 该缓存service在web中使用了spring 的@Scheduled 启动加载缓存,代码如下:

applicationContext.xml

<context:component-scan base-package="cn.com.service" />

EhcacheService .java

// 启动加载缓存, 以上一次执行完为准
@Scheduled(fixedDelay = 365 * 24 * 60 * 60 * 1000)
public void initEhcache() {
    logger.debug("++++++++++++++++++++缓存加载开始++++++++++++++++++++");
    long start = System.currentTimeMillis();
    try {
        this.ehcacheService.loadCache();
    } catch (Exception e) {
        logger.error(e.getMessage(), e);
    }
    long end = System.currentTimeMillis();
    logger.debug("++++++++++++++++++++缓存加载结束,耗时:" + (end - start) + "++++++++++++++++++++");
}

然而最近同步数据,需要用到EhcacheService , 本人也懒得重写里面的方法,便想着使用ClassPathXmlApplicationContext 或者FileSystemXmlApplicationContext 或者GenericXmlApplicationContext来加载spring配置,然后打包成jar包,丢到linux上,使用java -jar my.jar。代码如下:

test.java

// 程序入口
public static void main(String[] args) throws Exception {
    // 加载spring配置
    GenericXmlApplicationContext context = new GenericXmlApplicationContext();
    context.setValidating(false);
    context.load("classpath*:spring-*.xml");
    context.refresh();
    // ApplicationContext ctx = new FileSystemXmlApplicationContext("spring-*.xml");
    // ApplicationContext context = new ClassPathXmlApplicationContext("spring-*.xml");
    System.out.println("bean的数据量" + context.getBeanDefinitionNames().length);
    EhcacheService ehcacheService = (EhcacheService) context.getBean("ehcacheService");
}

我们先看一下在Eclipse中运行情况

我们再看看打包成Runable jar File后,使用 java -jar my.jar的运行情况

根据图片中的错误,我们可以看到,spring-*.xml是成功被加载了,然而找不到bean, 很明显,它存在一种可能,那就是bean的class文件没有被spring扫描到。

那么为什么会出现这种情况呢?经过我多方面的查证,spring 扫描bean文件是通过Thread.currentThread().getContextClassLoader().getResource(packageName)加载的。那么我们分析一下ContextClassLoader资源加载机制。

举例说明:我们有这样的一个: cn.com.Test, 类加载器首先会把这个包名转化成文件夹的形式 cn/com, 然后到这个文件夹里去加载Test.class。

然后,当你打包成Runable jar File时,jar的包和文件系统中的包便不是一个概念了,它不能将cn.com转换成cn/com文件夹方式去解读, 类加载转换成cn/com去加载类的时候,便会报出classNotFoundException异常

下面我们使用如下代码验证一下这个过程:

// 项目中jar包所在物理路径
String jarName = "C:\\Users\\Administrator\\Desktop\\my.jar";
// 项目中war包所在物理路径
//String jarName = "C:\\Users\\Administrator\\Desktop\\my.war";
 JarFile jarFile = new JarFile(jarName);
 Enumeration<JarEntry> entrys = jarFile.entries();
 while (entrys.hasMoreElements()) {
     JarEntry jarEntry = entrys.nextElement();
     System.out.println(jarEntry.getName());
 }     

打印结果如下:

META-INF/MANIFEST.MF cn/com/server/action/JobAction.class cn/com/server/annotation/DataDigestAnnotation.class cn/com/server/dao/EhcacheDao.class

然后我们打包成war包再看看他的war包物理路径,我们可以看到打印结果如下:

META-INF/MANIFEST.MF META-INF/ WEB-INF/classes/ WEB-INF/classes/cn/ WEB-INF/classes/cn/com/ WEB-INF/classes/cn/com/ WEB-INF/classes/cn/com/server/ WEB-INF/classes/cn/com/server/action/ WEB-INF/classes/cn/com/server/action/JobAction.class WEB-INF/classes/cn/com/server/addrsrv/ WEB-INF/classes/cn/com/server/addrsrv/GeoAddrSrv.class …..

我们可以看到war类的文件目录和jar的文件目录明显不同,这样就能解释上面我所描述的问题。

Q: 那么我们怎么解决spring 扫描不到jar中class这个问题呢?

A: 有一种做法,就是打jar包的时候,打成JAR file, 然后选择 add directory entries, 如图:

然后这种打包方式,虽然能解决spring 扫描不到jar中class文件问题,但是打并不是我们想要的,我们想要的是一个可以执行jar,也就是Runable JAR FILE。

Q: 那么我们怎么打包成Runable JAR FILE,并且解决spring 扫描不到jar中class的问题?

A:

1、首先使用Eclipse打包,打包成JAR file。

2、上传到Linux, 解压my.jar

unzip my.jar -d myapp

3、进入 myapp文件夹, 使用以下命令:

java -Djava.ext.dirs=WebContent/WEB-INF/lib cn.com.test

大功告成

其他技巧:除了上诉使用代码方式查看jar包物理路径,我们还可以是 jar tr my.jar来查看。如图:

@ComponentScan注解进行扫描的几种方式

方式一:扫描包

返回是String的数组,所以可是多个包路径!也可是一个包路径!完整写法是

  • 单个:@ComponentScan(basePackages = “xxx”)
  • 多个:@ComponentScan(basePackages = {“xxx”,“aaa”,“…”})

注意:可以省略“basePackages =”

方式二:扫描类

同样返回是String的数组,所以可以是有多个类名! 也可是一个类名!

  • 单个:@ComponentScan(basePackageClasses = “”)
  • 多个:@ComponentScan(basePackageClasses = {“xxx”,“aaa”,“…”})

注意:不可以省略“basePackageClasses =”

测试:

方式三:扫描包(通配式:开发常用)

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • spring注解在自定义jar包中无法被扫描的解决方案

    spring注解在自定义jar包中无法被扫描 前两天,一朋友在开发的时候遇到了一个问题向我求助, service服务为第三方提供的服务里面有spring注解并将service 打成jar包中,使用maven引入. 使用new可以创建,但是使用autowire无法注入提示信息如下图 报错信息 这类问题在开发中一直是我们最不愿意看到的,乍一看,感觉挺对,还挺有道理.但是就是更想要的结果对不上. 我当时给出的判断autowire的类重名导致注入失败,建议用配合使用qualifier或者 使用resou

  • 解决Spring Boot 多模块注入访问不到jar包中的Bean问题

    情景描述 一个聚合项目spring-security-tutorial,其中包括4个module,pom如下所示: <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://mav

  • 解决SpringBoot打成jar运行后无法读取resources里的文件问题

    开发一个word替换功能时,因替换其中的内容功能需要 word 模版,就把 word_replace_tpl.docx 模版文件放到 resources 下 在开发环境中通过下面方法能读取word_replace_tpl.docx文件,但是打成jar包在 linux下运行后无法找到文件了 File file = ResourceUtils.getFile(ResourceUtils.CLASSPATH_URL_PREFIX + "static/office_template/xxx.docx&q

  • springboot多模块包扫描问题的解决方法

    问题描述: springboot建立多个模块,当一个模块需要使用另一个模块的服务时,需要注入另一个模块的组件,如下面图中例子: memberservice模块中的MemberServiceApiImpl类需要注入common模块中的RedisService组件,该怎么注入呢? 解决: 在memberservice模块的启动类上加上RedisService类所在包的全路径的组件扫描,就像这样: 注意启动类上方的注解@ComponentScan(basePackages={"com.whu.comm

  • 关于spring 扫描不到jar中class文件的原因分析及解决

    目录 spring 扫描不到jar中class文件的原因及解决 背景 Q: 那么我们怎么解决spring 扫描不到jar中class这个问题呢? Q: 那么我们怎么打包成Runable JAR FILE,并且解决spring 扫描不到jar中class的问题? 大功告成 @ComponentScan注解进行扫描的几种方式 方式一:扫描包 方式二:扫描类 方式三:扫描包(通配式:开发常用) spring 扫描不到jar中class文件的原因及解决 背景 公司一web项目使用的是spring mvc

  • @Transaction,@Async在同一个类中注解失效的原因分析及解决

    目录 @Transaction @Async在同一个类中注解失效 下面用伪代码阐述一下原因 说说解决 @Async的实现类方式 方法1:实现接口AsyncConfigurer 方法2:直接注入bean @Transaction @Async在同一个类中注解失效 在同一个类中,一个方法调用另外一个有注解(比如@Async,@Transational)的方法,注解是不会生效的. 比如,下面代码例子中,有两方法,一个有@Async注解,一个没有.第一次如果调用了有注解的test()方法,会启动@Asy

  • SpringBoot使用Async注解失效原因分析及解决(spring异步回调)

    目录 Async注解失效原因分析及解决(spring异步回调) Spring中@Async 有时候在使用的过程中@Async注解会失效 解决方式一 解决方式二 springboot @Async 失效可能原因 Async注解失效原因分析及解决(spring异步回调) Spring中@Async 在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的:但是在处理与第三方系统交互的时候,容易造成响应迟缓的情况,之前大部分都是使用多线程来完成此类任务,其实,在spring 3.x之后,就已

  • 后端接收不到AngularJs中$http.post发送的数据原因分析及解决办法

    1.问题: 后端接收不到AngularJs中$http.post发送的数据,总是显示为null 示例代码: $http.post(/admin/KeyValue/GetListByPage, { pageindex: 1, pagesize: 8 }) .success(function(){ alert("Mr靖"); }); 代码没有错,但是在后台却接收不到数据,这是为什么呢? 用火狐监控:参数是JSON格式 用谷歌监控:传参方式是request payload 可以发现传参方式是

  • PHP中ID设置自增后不连续的原因分析及解决办法

    PHP中ID设置自增后不连续的原因分析如下所述: alter table tablename drop column id; alter table tablename add id mediumint(8) not null primary key auto_increment first; 每次删除把这两行家伙加上就行了 还有就是这个 使用mysqli对象中的query()方法每次调用只能执行一条SQL命令. 如果需要一次执行多条SQL命令,就必须使用mysqli对象中的 multi_que

  • JavaScript中的ParseInt("08")和“09”返回0的原因分析及解决办法

    今天在程序中出现一个bugger ,调试了好久,最后才发现,原来是这个问题. 做了一个实验: alert(parseInt("01")),当这个里面的值为01====>07时都是正常的,但是在"08","09"就会返回0 (这种现象出现在ie内核的浏览器中,如360浏览器就会出现这种错误)(谷歌,火狐不受影响) . 查阅资料得知着这种现象原因: 大神的解释: 01--07自然没有问题,但是09,08都是不合格的八进制形式,所以被按照0处理了

  • springboot中生成文件路径的问题及解决方法

    目录 springboot生成文件路径 举例 springboot创建错误(路径) 解决 springboot生成文件路径 在进行 springboot 项目开发以及打包为 jar 包发布时, 可能会有两种情况下生成文件路径不一致的问题, 有一种获取路径的方法可以使两种环境下都可以正确获取到项目或jar包的根目录 举例 String root = System.getProperty("user.dir"); String path = root +"\\out.txt&qu

  • spring cloud eureka 服务启动失败的原因分析及解决方法

    目录 环境: 错误log 环境: <spring-boot-version>2.3.5.RELEASE</spring-boot-version> <spring-cloud-version>Hoxton.SR8</spring-cloud-version> 错误log Unable to start web server; nested exception is org.springframework.boot.web.server.WebServerEx

  • Flex读取txt文件中的内容报错原因分析及解决

    Flex读取txt文件中的内容 1.具体错误如下  2.错误原因 读取文件不存在 复制代码 代码如下: var file:File = new File(File.applicationDirectory.nativePath+"/phone.txt"); 3.解决办法 将文件导入进去

  • 不要在cookie中使用特殊字符的原因分析

    Constructs a cookie with a specified name and value. The name must conform to RFC 2109. That means it can contain only ASCII alphanumeric characters and cannot contain commas, semicolons, or white space or begin with a $ character. The cookie's name

随机推荐