BeanCreationException错误在服务类内部引用配置类时出现

huangapple go评论76阅读模式
英文:

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 {

huangapple
  • 本文由 发表于 2020年4月10日 12:27:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/61134060.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定