最近项目从springboot1.x升级到2.3.x时,发现调用方法时注入的dao类为空。经过长时间排查发现是@Transactional引起。以前一直的思路是只要@Transactional注释的方法为public就可以正常注入,但发现如果是同包下package-private级别的方法调用,也会导致注入为空。
下面代码是UserService中调用了menuService.listMenus()方法
UserService
public List<ProductDto> genProductDtoList(String roleTypeCode) {List<ProductEntity> productList = productService.listAllProducts();List<MenuDto> menuDtoList = menuService.listMenus(productCodeList, roleTypeCode);// 非关键代码省略....return ...
}
MenuService:
List<MenuDto> listMenus(List<String> productCodeList, String roleTypeCode) {List<MenuEntity> leafMenus = menuDao.listMenus(productCodeList, roleTypeCode);if (leafMenus.isEmpty()) {return Lists.newArrayList();}Set<String> parentMenuCodes = leafMenus.stream().map(MenuEntity::getParentCode).collect(Collectors.toSet());List<MenuEntity> parentMenu = menuDao.listMenus(parentMenuCodes);List<MenuEntity> menus = Collections.concat(leafMenus, parentMenu);return menus.stream().map(MenuDto::new).collect(Collectors.toList());}@Transactional(rollbackFor = Exception.class)
public void saveRelationsOfMenuAndRoleType(String typeCode, List<String> menuCodes) {menuDao.deleteRelationsByRoleType(typeCode);List<MenuEntity> menus = menuDao.listLeafMenus(menuCodes);if (menus.isEmpty() && !Objects.equals(typeCode,VISITOR)) {LOGGER.info("至少选择一个菜单!参数:{}", menuCodes);throw new DataException("至少选择一个菜单!");}// 省略代码 --------}
在MenuService中有其他的方法使用了@Transactional进行事务管理,会导致listMenus中的menuDao注入为null.原因就是listMenus方法未定义访问权限,默认是package-private。当把该方法改成public时,则能正常注入:
public List<MenuDto> listMenus(List<String> productCodeList, String roleTypeCode) {List<MenuEntity> leafMenus = menuDao.listMenus(productCodeList, roleTypeCode);if (leafMenus.isEmpty()) {return Lists.newArrayList();}Set<String> parentMenuCodes = leafMenus.stream().map(MenuEntity::getParentCode).collect(Collectors.toSet());List<MenuEntity> parentMenu = menuDao.listMenus(parentMenuCodes);List<MenuEntity> menus = Collections.concat(leafMenus, parentMenu);return menus.stream().map(MenuDto::new).collect(Collectors.toList());}
具体的源码后续分析,先用该方法解决业务报错问题处理。