2013-04-23 2 views
2

Весна 3.2. Все работает, когда я делаю:Autowire/впрыскивание фасоли в метод контроллера

@Controller 
public class MyController { 
    @Inject 
    Provider<MyBean> provider; 

    @RequestMapping("/chart") 
    public void getChart(HttpServletResponse resp) { 
     provider.get(); 
    } 
} 

, но она не работает, когда я ставлю MyBean в качестве аргумента getChart:

@Controller 
public class MyController { 

    @RequestMapping("/chart") 
    public void getChart(HttpServletResponse resp, MyBean myBean) { 
     // No such method MyBean.<init>() 
    } 
} 

Так Spring пытается создать новый экземпляр myBean вместо использования уже связанный.

Конфигурация:

@Configuration 
public class Config { 
    @Inject 
    @Bean @Scope("request") 
    public MyBean provideMyBean(MyOtherBean myOtherBean) { 
     return myOtherBean.getMyBean(); 
    } 
} 

Он также не работает, если я делаю мой запрос контроллер с заданной областью, и добавить @ Inject/@ Autowired к getChart(). Затем он не может найти экземпляр HttpServletResponse (NoSuchBeanDefinitionException), хотя, безусловно, он должен быть одним в области запроса.

Возможно, это просто не реализовано весной?

+0

Вы пытаетесь MyBean или привязка просто получить экземпляр из контейнера МОК? –

+0

Где объявляется mybean? – Krishna

+0

@ KevinBowersox просто получите экземпляр. –

ответ

1

Решенный путем создания пользовательского HandlerMethodArgumentResolver:

/** 
* Resolves beans defined in {@link Config}, 
* because Spring doesn't want to do it implicitly. 
* 
* Makes possible to write something like 
* @RequestMapping(value="/chart", method=RequestMethod.GET) 
* getChart(HttpServletRequest req, MyBean myBean) 
* 
* and Spring will inject both arguments. 
*/ 
public class MethodArgumentResolver implements HandlerMethodArgumentResolver, BeanFactoryAware { 
    private final Set<Class> knownTypes = Config.getDeclaredTypes(); 

    private BeanFactory beanFactory; 

    @Override 
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException { 
     this.beanFactory = beanFactory; 
    } 

    @Override 
    public boolean supportsParameter(MethodParameter parameter) { 
     Class<?> type = parameter.getParameterType(); 
     return knownTypes.contains(type); 
    } 

    @Override 
    public Object resolveArgument(
      MethodParameter parameter, 
      ModelAndViewContainer mavContainer, 
      NativeWebRequest webRequest, 
      WebDataBinderFactory binderFactory) throws Exception { 
     Class<?> type = parameter.getParameterType(); 
     return beanFactory.getBean(type); 
    } 
} 

и в Config:

static Set<Class> getDeclaredTypes() { 
    Set<Class> result = Sets.newHashSet(); 
    Method[] methods = Config.class.getDeclaredMethods(); 
    for (Method method : methods) { 
     if (method.getAnnotation(Bean.class) != null) { 
      result.add(method.getReturnType()); 
     } 
    } 
    return result; 
} 
+0

Это довольно javascript-ish способ пойти ... Предпочтительным способом с Spring было бы @Inject ваша зависимость как свойство вашего контроллера. Объем достигается с помощью механизма на основе прокси, поэтому не бойтесь какой-либо проблемы безопасности потоков. – Vincent

+0

Вы правы в отношении свойств контроллера. Фактически, в течение некоторого времени активного использования инъекции зависимостей мы все меньше и меньше нуждаемся в этом методеArgumentResolver, потому что теперь наши методы Controllers требуют гораздо меньших зависимостей, чем раньше, поэтому нет необходимости в настраиваемых компонентах в параметрах. –

+0

Но я не согласен с бобами, основанными на прокси. Я предпочел бы использовать Provider <> для явного описания областей. Области важны. –