@Autowired当没有定义应该自动装配的 bean 时,默认的Spring 实现会抛出错误。是否可以配置 Spring,将 null 分配给对象而不是抛出异常?
编辑:
我已经添加required=false,Autowired但它仍然无法正常工作。那是我的代码:
@Autowired
private ApplicationContext applicationContext;
@Autowired(required = false)
private HelloService helloService;
public HelloController() {
message = "Hello World";
System.out.println("Controller constructor");
}
@RequestMapping(method = RequestMethod.GET)
public ModelAndView helloWorld() {
ModelAndView modelAndView = new ModelAndView("hello");
if (helloService == null) {
System.out.println(message);
} else {
helloService.hello();
BeanDefinitionRegistry factory = (BeanDefinitionRegistry) applicationContext.getAutowireCapableBeanFactory();
factory.removeBeanDefinition("helloService");
}
return modelAndView;
}
Run Code Online (Sandbox Code Playgroud)
在第一个请求中它是自动装配的,但是在删除 bean 后的下一个请求中factory.removeBeanDefinition("helloService"),再次构造控制器 bean,我得到NoSuchBeanDefinitionException
编辑2:
我创建了另一个具有以下主体的控制器:
@Autowired(required = false)
private TestService testService;
@RequestMapping(method = RequestMethod.GET)
public ModelAndView hello() {
ModelAndView modelAndView = new ModelAndView("hello");
return modelAndView;
}
Run Code Online (Sandbox Code Playgroud)
并且它工作正常 - 对象为空并且不会出错。也许我应该使用不同的方法从 Spring 上下文中删除 bean?
堆栈跟踪:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'helloService' is defined
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:698) ~[spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1175) ~[spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:284) ~[spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) ~[spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.resolvedCachedArgument(AutowiredAnnotationBeanPostProcessor.java:508) ~[spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.access$200(AutowiredAnnotationBeanPostProcessor.java:115) ~[spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:538) ~[spring-beans-4.2.7.RELEASE.jar:4.2.7.RELEASE]
...
Run Code Online (Sandbox Code Playgroud)
重现步骤:
您可以通过将required属性设置为 false来禁用此功能。
@Autowired(required=false)
如果 Spring 找不到 bean,它将使字段未设置为 null。
小智 4
问题是 AutowiredAnnotationBeanPostProcessor 缓存注入结果。因此,当您从上下文中删除bean时,此类认为该对象实际上存在(请参阅AutowiredAnnotationBeanPostProcessor.class中的私有类AutowiredFieldElement扩展InjectionMetadata.InjectedElement和方法inject)。因此,您应该清除该缓存。
我发现的最愚蠢的方法是,但看起来你想做
@Controller
@RequestMapping("/hello")
public class HelloController {
@Autowired(required = false)
private HelloService helloService;
@Autowired
private ApplicationContext applicationContext;
@RequestMapping(method = RequestMethod.GET)
public ModelAndView modelAndView() {
ModelAndView modelAndView = new ModelAndView("hello");
if (helloService != null) {
helloService.hello();
removeBean("helloService");
}
return modelAndView;
}
private void removeBean(String beanName) {
BeanDefinitionRegistry factory = (BeanDefinitionRegistry) applicationContext
.getAutowireCapableBeanFactory();
factory.removeBeanDefinition(beanName);
clearCache(factory);
}
private void clearCache(BeanDefinitionRegistry beanFactory){
AutowiredAnnotationBeanPostProcessor processor = null;
for (BeanPostProcessor beanPostProcessor : ((DefaultListableBeanFactory) beanFactory).getBeanPostProcessors()){
if (beanPostProcessor.getClass().equals(AutowiredAnnotationBeanPostProcessor.class)){
processor = (AutowiredAnnotationBeanPostProcessor) beanPostProcessor;
}
}
try {
Field injectionMetadataCache = processor.getClass().getDeclaredField("injectionMetadataCache");
injectionMetadataCache.setAccessible(true);
Method clear = Map.class.getMethod("clear");
clear.invoke( injectionMetadataCache.get(processor));
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2879 次 |
| 最近记录: |