業務背景: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