还是在项目中遇到的场景,本来是个excel工具类,但是需要校验表中的数据,还有必要的全局变量,就必须把这个工具类弄成一个多例bean了。
但是我们知道,在日常使用spring时,将bean注入ioc容器时,默认都是以单例注入,除非注明为多例。一个接口用
@Controller注解时往往都是单例。那么如果在这种情况下使用多例bean呢?
1.在单例bean(spring中单例注入),不能使用@Resource,@Autowired直接获取多例bean
(以下是错误代码!)
Api(tags = "组织管理相关")
@RestController
@RequestMapping("/user/sys-user")
public class SysUserController {
@Autowired
SysUserExcelImport SysUserExcelImport;
@Resource
SysUserExcelImport SysUserExcelImport;
@PostMapping("/saveExcel")
@ApiOperation(value = "1.基础用户管理_excel导入基础用户信息", notes = "")
public ResponseBean saveExcel(@RequestParam(value = "files") MultipartFile[] files,@RequestParam(value = "roleIds",required = false)List<String> roleIds) {
try {
for (MultipartFile multipartFile : files) {
File file = MultipartFileToFileUtil.multipartFileToFileLocal(multipartFile);
try {
//如果直接通过注解获取,再打印SysUserExcelImport的hashcode值会发现都会一样
SysUserExcelImport.postConstruct(file);
sysUserExcelImport.close();
file.delete();
if(sysUserExcelImport.getError()){
return new ResponseBean(false,sysUserExcelImport.getErrorExcelPath(),OrganizationEnums.ORGANIZATION_SAVE_USER_EXCEL_FAIL);
}else{
sysUserService.saveUsers(sysUserExcelImport.getSaveSysUserBeans(),roleIds);
return new ResponseBean(true, OrganizationEnums.ORGANIZATION_SAVE_USER_EXCEL_SUCCESS);
}
}catch (Exception e){
file.delete();
throw e;
}
}
return null;
} catch (Exception e) {
e.printStackTrace();
return new ResponseBean(false, e.getMessage(), OrganizationEnums.ORGANIZATION_SAVE_USER_EXCEL_FAIL);
}
}
}
spring容器中在加载controller时同时也会初始化@Resource和@Autowired注解的全局变量,并且只会初始化一次。初始化一次的结果就是这个工具类不会再次出现一个实例对象,并且不能实现多例。(讲的太笼统,可以去看看看看spring在启动时ioc加载bean的过程就清楚了)。
如果不能作为全局变量,那么唯一的解决办法只能通过spring的bean工厂获取了
2.spring提供了 ApplicationContextAware接口以获取上下文环境,再通过上下文环境获取bean
public class ApplicationContextUtils implements ApplicationContextAware {
private static ApplicationContext applicationContext = null;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if(SpringUtils.applicationContext == null){
SpringUtils.applicationContext = applicationContext;
}
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
public static String[] controllersBeanNames(Class<? extends Annotation> clazz){
return getApplicationContext().getBeanNamesForAnnotation(clazz);
}
public static Map<String, Object> controllersBeans(Class<? extends Annotation> clazz){
return getApplicationContext().getBeansWithAnnotation(clazz);
}
public static Object getBean(String name) {
return applicationContext.getBean(name);
}
public static <T> T getBean(Class<T> requiredType) {
return applicationContext.getBean(requiredType);
}
public static <T> T getBean(String name, Class<T> requiredType) {
return applicationContext.getBean(name, requiredType);
}
public static boolean containsBean(String name) {
return applicationContext.containsBean(name);
}
public static boolean isSingleton(String name) {
return applicationContext.isSingleton(name);
}
public static Class<? extends Object> getType(String name) {
return applicationContext.getType(name);
}
}
这个地方是我写错了。原谅我,,,,,,
@PostMapping("/saveExcel")
@ApiOperation(value = "1.基础用户管理_excel导入基础用户信息", notes = "")
public ResponseBean saveExcel(@RequestParam(value = "files") MultipartFile[] files,@RequestParam(value = "roleIds",required = false)List<String> roleIds) {
//获取bean
SysUserExcelImport sysUserExcelImport=SpringUtils.getBean(SysUserExcelImport.class);
try {
for (MultipartFile multipartFile : files) {
File file = MultipartFileToFileUtil.multipartFileToFileLocal(multipartFile);
try {
sysUserExcelImport.postConstruct(file);
sysUserExcelImport.close();
file.delete();
if(sysUserExcelImport.getError()){
return new ResponseBean(false,sysUserExcelImport.getErrorExcelPath(),OrganizationEnums.ORGANIZATION_SAVE_USER_EXCEL_FAIL);
}else{
sysUserService.saveUsers(sysUserExcelImport.getSaveSysUserBeans(),roleIds);
return new ResponseBean(true, OrganizationEnums.ORGANIZATION_SAVE_USER_EXCEL_SUCCESS);
}
}catch (Exception e){
file.delete();
throw e;
}
}
return null;
} catch (Exception e) {
e.printStackTrace();
return new ResponseBean(false, e.getMessage(), OrganizationEnums.ORGANIZATION_SAVE_USER_EXCEL_FAIL);
}
}
这里需要注意的是如果通过bean名称来获取,但是没有获取到。我一直以为是在多例的情况下不会主动加载,,但是发现我错了。。其实是name不对。推荐下这篇文章https://blog.csdn.net/qq_22651103/article/details/88727712。通过注解name默认的是啥,,其实通过name获取也是可以的,但是要写对