Java 在非组件对象上使用Spring@Value
我遇到了一个我不知道如何解决的问题。我使用SpringBoot创建了RESTfulAPI,并且我正在实现DTO域实体模式,所以在这个特殊情况下,我有这个控制器的方法Java 在非组件对象上使用Spring@Value,java,spring,spring-mvc,Java,Spring,Spring Mvc,我遇到了一个我不知道如何解决的问题。我使用SpringBoot创建了RESTfulAPI,并且我正在实现DTO域实体模式,所以在这个特殊情况下,我有这个控制器的方法 @RequestMapping(method = RequestMethod.POST) @ResponseBody public ResponseEntity<UserResponseDTO> createUser(@RequestBody UserRequestDTO data) { UserDomain u
@RequestMapping(method = RequestMethod.POST)
@ResponseBody
public ResponseEntity<UserResponseDTO> createUser(@RequestBody UserRequestDTO data) {
UserDomain user = this.mapper.map(data, UserDomain.class);
UserDomain createdUser = this.service.createUser(user);
UserResponseDTO createdUserDTO = this.mapper.map(createdUser, UserResponseDTO.class);
return new ResponseEntity<UserResponseDTO>(createdUserDTO, HttpStatus.CREATED);
}
public class UserDomain {
private Long id;
private Date createdDate;
private Date updatedDate;
private String username;
private String password;
@Value("${default.user.enabled:true}") // I have default-values.properties being loaded in another configuration file
private Boolean enabled;
}
如果您的映射程序有一个方法,该方法采用已准备好的实例而不是
类,那么您可以添加原型作用域用户域bean,并从控制器方法调用上下文.getBean()
控制器
否则,您可以使用和AspectJ编译时编织。但是您必须决定是否值得在项目中引入编织,因为您有其他方法来处理这种情况
pom.xml
弹簧配置
与
相同
请参阅Spring文档以了解有关的更多信息
编辑
关于你的编辑
请注意,您在那里使用。这意味着UserDomain
实例必须由Spring容器管理。容器不知道在其外部创建的实例,因此不会为此类实例解析(完全相同),例如UserDomain UserDomain=new UserDomain()
或UserDomain.class.newInstance()
。因此,您仍然需要向上下文添加一个原型范围的UserDomain
bean。实际上,这意味着所提出的方法与关联的方法类似,只是它将您的UserDomain
与Spring绑定在一起。因此,这是不好的
使用或不将您的域对象绑定到Spring,仍然可以设计出更好的解决方案
ApplicationContextProvider.java
弹簧配置
然而,我不喜欢这种方法的额外复杂性和草率性。我认为这一点都不合理。你没有服务层吗?首选项、参数、默认值等应该注入到服务类中,这些服务类是集中业务逻辑的,应该由Spring管理
如果没有用户服务
,则将默认值加载到控制器中
我只是注意到从DTO到domain类的转换正在控制器中进行
定义
@Value("${default.user.enabled:true}")
private Boolean defaultUserEnabled;
在控制器内部,然后
if (user.isEnabled() == null)
user.setEnabled(defaultUserEnabled);
但是,正如我已经说过的,默认值的声明和设置都属于Spring托管服务类。可能的重复项实际上不是我想要的。我知道我可以连接环境并获取属性,但我想在这里通过@Value annotations.Fine来实现。请看我的答案。非常好的答案!还有一件事。您认为使用环境在UserDomain构造函数中获取属性(例如)更好吗?或者你更愿意像你在这个答案中解释的那样去做?谢谢我认为解决这种情况的最佳方法是使用prototype作用域UserDomain
bean。这样,您的域代码就不会绑定到Spring,也不会有与编织相关的额外开销(甚至编译时)?这将提高性能,因为我不必将所有对象层实例(dto域实体)都创建为Spring Bean,这几乎是我一直在寻找的。谢谢我不认为这是一个优雅的解决方案。无论如何谢谢你!从概念上讲,从架构的角度来看,这是一个不错的解决方案。但是,UserService
不在UserRequestDto
上运行,并且不应该进行转换defaultUserEnabled
在逻辑上也不属于控制器。因此,在我个人看来,在这种情况下,出于转换目的,可能需要在控制器和服务之间引入一个附加层。
@Configuration
public class Config {
@Bean
public static PropertySourcesPlaceholderConfigurer properties() {
PropertySourcesPlaceholderConfigurer propConfigurer = new PropertySourcesPlaceholderConfigurer();
propConfigurer.setLocation(new ClassPathResource("application.properties"));
return propConfigurer;
}
@Bean
@Scope("prototype")
public UserDomain userDomain() {
return new UserDomain();
}
...
}
...
<!-- additional dependencies -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.6</version>
</dependency>
...
<!-- enable compile-time weaving with aspectj-maven-plugin -->
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.7</version>
<configuration>
<complianceLevel>1.8</complianceLevel>
<encoding>UTF-8</encoding>
<aspectLibraries>
<aspectLibrary>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</aspectLibrary>
</aspectLibraries>
<Xlint>warning</Xlint>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
...
@Configurable
public class UserDomain {
private Long id;
private Date createdDate;
private Date updatedDate;
private String username;
private String password;
@Value("${default.user.enabled:true}")
private Boolean enabled;
...
}
@Configuration
@EnableSpringConfigured
public class Config {
@Bean
public static PropertySourcesPlaceholderConfigurer properties() {
PropertySourcesPlaceholderConfigurer propConfigurer = new PropertySourcesPlaceholderConfigurer();
propConfigurer.setLocation(new ClassPathResource("application.properties"));
return propConfigurer;
}
...
}
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext applicationContext;
public static <T> T getEnvironmentProperty(String key, Class<T> targetClass, T defaultValue) {
if (key == null || targetClass == null) {
throw new NullPointerException();
}
T value = null;
if (applicationContext != null) {
System.out.println(applicationContext.getEnvironment().getProperty(key));
value = applicationContext.getEnvironment().getProperty(key, targetClass, defaultValue);
}
return value;
}
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
}
public class UserDomain {
private Boolean enabled;
public UserDomain() {
this.enabled = ApplicationContextProvider.getEnvironmentProperty("default.user.enabled", Boolean.class, false);
}
...
}
@Configuration
@PropertySource("classpath:application.properties")
public class Config {
@Bean
public ApplicationContextProvider applicationContextProvider() {
return new ApplicationContextProvider();
}
...
}
@Value("${default.user.enabled:true}")
private Boolean defaultUserEnabled;
if (user.isEnabled() == null)
user.setEnabled(defaultUserEnabled);