英文:
BeanCreationException error when referencing configuration class inside a service class
问题
我正在尝试在@Service
类内部自动装配@Configuration
类。基本上,我的@Configuration
类包含了对自定义.properties
文件的映射。当我尝试在我的@Service
类内部自动装配配置类时,会出现BeanCreationException
异常。我不确定发生了什么。只是按照创建Spring属性类的指南进行操作。肯定有些地方我遗漏了。
另外,当我尝试将@Configuration
类自动装配到另一个@Configuration
类时,一切都运行得很顺利。
目前,我知道prop
始终为null,因为当我移除prop.getUploadFileLocation()
调用时,一切都正常。在自动装配过程中肯定出了些问题。
这是我的Service类
@Service
public class ImageService {
public static Logger logger = Logger.getLogger(ImageService.class.getName());
@Autowired
MyProperties prop;
private final String FILE_UPLOAD_LOCATION = prop.getUploadFileLocation() + "uploads/images/";
public void upload(String base64ImageFIle) throws IOException {
logger.info(FILE_UPLOAD_LOCATION);
}
}
这是我的Configuration类
@Data
@Configuration
@ConfigurationProperties(prefix = "my")
public class MyProperties {
private String resourceLocation;
private String resourceUrl;
public String getUploadFileLocation() {
return getResourceLocation().replace("file:///", "");
}
public String getBaseResourceUrl() {
return getResourceUrl().replace("**", "");
}
}
以下是我可以成功使用MyProperties
的地方
@Configuration
public class StaticResourceConfiguration implements WebMvcConfigurer {
@Autowired
MyProperties prop;
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler(prop.getResourceUrl())
.addResourceLocations(prop.getResourceLocation());
}
}
英文:
I am trying to @Autowire
a @Configuration
class inside a @Service
class. basically my @Configuration
class contains mapping to my custom .properties
file. When i try to autowire my configuration class inside my service class, BeanCreationException
occurs. I am not sure what happen. Just followed the guide on creating Property classes from spring. There must be something i missed out.
Also, when i try to autowire @Configuration
class to another @Configuration
class, it runs smoothly
Currently, i know that, prop
is always null because when i remove prop.getUploadFileLocation()
call, everything will be fine. There must be something wrong during autowiring.
Here is my Service class
@Service
public class ImageService {
public static Logger logger = Logger.getLogger(ImageService.class.getName());
@Autowired
MyProperties prop;
private final String FILE_UPLOAD_LOCATION = prop.getUploadFileLocation() +"uploads/images/";
public void upload(String base64ImageFIle) throws IOException {
logger.info(FILE_UPLOAD_LOCATION);
}
}
Here is my Configuration class
@Data
@Configuration
@ConfigurationProperties (prefix = "my")
public class MyProperties {
private String resourceLocation;
private String resourceUrl;
public String getUploadFileLocation() {
return getResourceLocation().replace("file:///", "");
}
public String getBaseResourceUrl() {
return getResourceUrl().replace("**", "");
}
}
And here is where i can successfully use MyProperties
@Configuration
public class StaticResourceConfiguration implements WebMvcConfigurer {
@Autowired
MyProperties prop;
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler(prop.getResourceUrl())
.addResourceLocations(prop.getResourceLocation());
}
}
答案1
得分: 3
问题在于你正在尝试使用自动注入的字段来在内联字段赋值中设置值。
这意味着
private final String FILE_UPLOAD_LOCATION = prop.getUploadFileLocation() + "uploads/images/";
在prop
被自动注入之前就被执行了,这意味着它将始终为null。
缓解这个问题的方法是改用构造函数注入。
@Service
public class ImageService {
//由于使用静态方法,这是可以的
public static Logger logger = Logger.getLogger(ImageService.class.getName());
//如果只用于设置FILE_UPLOAD_LOCATION,则不需要
//允许字段为final
private final MyProperties prop;
//仍然是final
private final String FILE_UPLOAD_LOCATION;
//在组件构造函数上隐式,不需要@Autowired
ImageService(MyProperties prop){
//如果在类中不会在其他地方使用,同样也不需要
this.prop = prop;
FILE_UPLOAD_LOCATION = prop.getUploadFileLocation() + "uploads/images/";
}
public void upload(String base64ImageFIle) throws IOException {
logger.info(FILE_UPLOAD_LOCATION);
}
}
有关为什么一般情况下构造函数优于@Autowired的更多信息,请参见此问题。
英文:
The issue is that you are trying to use an autowired field to set the value in an inline field assignment.
That means
private final String FILE_UPLOAD_LOCATION = prop.getUploadFileLocation() +"uploads/images/";
is executed before the prop
is autowired, meaning it will always be null
The way to mitigate this would be to use constructor injection instead.
@Service
public class ImageService {
//Fine since you are using static method
public static Logger logger = Logger.getLogger(ImageService.class.getName());
//Not needed if you are only using it to set FILE_UPLOAD_LOCATION
//Allows field to be final
private final MyProperties prop;
//Still final
private final String FILE_UPLOAD_LOCATION;
//No need for @Autowired since implicit on component constructors
ImageService(MyProperties prop){
//Again not needed if you aren't going to use anywhere else in the class
this.prop = prop;
FILE_UPLOAD_LOCATION = prop.getUploadFileLocation() +"uploads/images/";
}
public void upload(String base64ImageFIle) throws IOException {
logger.info(FILE_UPLOAD_LOCATION);
}
}
See this question for why constructor is preferred over @autowired in general
答案2
得分: 0
如果您需要在创建StaticResourceConfiguration
bean之前先创建MyProperties
bean,您可以按照以下方式使用@ConditionalOnBean(MyProperties.class)
。Spring将确保在处理StaticResourceConfiguration
之前存在MyProperties
。
@Configuration
@ConditionalOnBean(MyProperties.class)
public class StaticResourceConfiguration implements WebMvcConfigurer {
英文:
If you need MyProperties
bean to be created before StaticResourceConfiguration
bean, you can put @ConditionalOnBean(MyProperties.class)
as following. Spring will make sure MyProperties
is there before processing StaticResourceConfiguration
.
@Configuration
@ConditionalOnBean(MyProperties.class)
public class StaticResourceConfiguration implements WebMvcConfigurer {
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论