业务背景:html
添加商品以及价格,一个商品会有多个价格(针对不一样用户等级).java
代码:spring
先在controller中使用dozer将goodsForm-->Goods,而后保存商品, 以后遍历商品价格列表,注入商品ID,接着保存商品价格.app
GoodsForm: List<GoodsPriceForm> priceList; Goods: List<GoodsPrice> priceList; Controller: Goods goods = BeanMapper.map(goodsForm, Goods.class); save(goods); goods.getPriceList().forEach(p->p.setGoodsId(goods.getId())); save(goods.getPriceList());
在遍历商品价格列表时报错, 错误信息:spring-boot
java.lang.ClassCastException: com.foo.goods.model.GoodsPrice cannot be cast to com.foo.goods.model.GoodsPrice at com.foo.goods.service.GoodsService$$Lambda$11/310447431.accept(Unknown Source) ~[na:na] at java.util.ArrayList.forEach(ArrayList.java:1249) ~[na:1.8.0_51] at com.foo.goods.service.GoodsService.saveGoods(GoodsService.java:34) ~[classes/:na]
对这一异常描述有些摸不着头脑, 经提醒有多是不一样的类加载器加载致使, 在Eclipse debug模式中Expression视图下,输出了goods和goodsPrice的类加载器名this
Goods: org.springframework.boot.devtools.restart.classloader.RestartClassLoader@41aa15ea GoodsPrice: sun.misc.Launcher$AppClassLoader@58644d46
果真涉及到不一样的类加载器. spa
尝试了在pom.xml中注释掉spring-boot-devtools, 再启动后没有上述异常. 但如何在保留devtools的状况下解决该问题呢? 查询官方文档:debug
By default, any open project in your IDE will be loaded using the “restart” classloader, and any regular
.jar
file will be loaded using the “base” classloader. If you work on a multi-module project, and not each module is imported into your IDE, you may need to customize things. To do this you can create aMETA-INF/spring-devtools.properties
file.restThe
spring-devtools.properties
file can containrestart.exclude.
andrestart.include.
prefixed properties. Theinclude
elements are items that should be pulled-up into the “restart” classloader, and theexclude
elements are items that should be pushed down into the “base” classloader. The value of the property is a regex pattern that will be applied to the classpath.code
因而在工程的resources目录下添加了META-INF/spring-devtools.properties,内容为
restart.include.dozer=/dozer-5.5.1.jar
即dozer代码也使用RestartClassLoader,能够解决上述问题.
补充:
在该工程中的Application类中有以下一段代码
@Bean public Mapper fooDozerBeanMapper() { DozerBeanMapper mapper = BeanMapper.getDozerBeanMapper(); List<String> mappingFiles = Lists.newArrayList(mapper.getMappingFiles()); mappingFiles.add("foo-dozer-custom-convert.xml"); mapper.setMappingFiles(mappingFiles); return mapper; }
其中BeanMapper是依赖另外一个工程(bar), 当在Eclipse中关闭该依赖工程(bar)后, 会报错
Caused by: java.lang.LinkageError: loader constraint violation: loader (instance of org/springframework/boot/devtools/restart/classloader/RestartClassLoader) previously initiated loading for a different type with name "org/dozer/DozerBeanMapper" at java.lang.ClassLoader.defineClass1(Native Method) ~[na:1.8.0_05] at java.lang.ClassLoader.defineClass(ClassLoader.java:760) ~[na:1.8.0_05] at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) ~[na:1.8.0_05]
解决方法
修改spring-devtools.properties,再增长一个配置
restart.include.bar=/bar.jar restart.include.dozer=/dozer-5.5.1.jar