2013-12-05 3 views
2

У меня есть веб-приложение, которое имеет UserService, чтобы разрешить операции, связанные с пользователем.SpringMVC, null весна бобы, сервлеты и Apache Thrift

Я могу использовать фасоль UserService внутри любого из моих классов @Controller, и он отлично работает.

Если добавить второй сервлет типа ThriftServlet так:

//register the thrift API servlet 
ServletRegistration.Dynamic thrift = servletContext.addServlet("thriftapi", new ThriftServlet()); 
thrift.setLoadOnStartup(2); 
thrift.addMapping("/api/*"); 

ThriftServlet выглядит следующим образом:

public class ThriftServlet extends TServlet { 

    // constructor 
    public ThriftServlet() { 
     super(new MyService.Processor<ThriftApiHandler>(
      new ThriftApiHandler()), new TBinaryProtocol.Factory()); 
    } 
} 

А потом я украшен мой ThriftApiHandler с @Component, чтобы позволить инъекции фасоли (или поэтому я подумал), чтобы это выглядело так:

@Component 
public class ThriftApiHandler implements MyService.Iface { 

    @Autowired 
    UserService userService; 

    @Override 
    public String myServiceMethod(String someParam) throws SomeException, TException { 
     // userService is null when this is called by a client application 
    } 
} 

я могу увидеть в журналах отладки, что автоматическое связывание действительно Осуществляющий (временные метки и классы пропущено):

<snip> - Creating shared instance of singleton bean 'thriftApiHandler' 
<snip> - Creating instance of bean 'thriftApiHandler' 
<snip> - Registered injected element on class [my.package.api.ThriftApiHandler]: AutowiredFieldElement for my.package.service.UserService my.package.api.ThriftApiHandler.userService 
<snip> - Eagerly caching bean 'thriftApiHandler' to allow for resolving potential circular references 
<snip> - Processing injected method of bean 'thriftApiHandler': AutowiredFieldElement for my.package.service.UserService my.package.api.ThriftApiHandler.userService 

Но userService (и любые другие бобы я стараюсь и инъекционные) всегда пустой внутри любой из бережливости api.

Возможно, это связано с тем, как класс TServlet наследуется от HttpServlet и не знает «о весеннем контексте»?

Я чувствую, что мне не хватает чего-то общего с контекстами сервлетов и общих бобах и т. Д., Но я довольно новичок в SpringMVC. Если опубликовать какой-либо код, этот вопрос будет легче ответить, сообщите мне.

ответ

2

Весна всегда будет терпеть неудачу (исключить исключение), если она не может решить цель @Autowired. Если вы получаете null, то Spring на самом деле не управляет вашим объектом и поэтому не может ничего вводить. Вот здесь.

public ThriftServlet() { 
    super(new MyService.Processor<ThriftApiHandler>(
     new ThriftApiHandler()), new TBinaryProtocol.Factory()); // here 
} 

Вы инстанцировании ваши ThriftApiHandler себя, вместо того, чтобы получить его с весны.

Если вы хотите получить его от Spring, вам необходимо будет получить доступ к ApplicationContext из атрибутов ServlectContext или куда бы вы его не поместили.

+0

Если я добавлю '@ Component' в' ThriftServlet', должен ли я использовать '@ Autowire'' ThriftApiHandler'? Даже тогда я не могу ссылаться на это в конструкторе 'new MyService.Processor (thriftApiHandler), потому что он не является статическим ... –

+0

@wwarren Вам не следует добавлять обработчик в конструктор. Сервлеты должны выполнять свою конфигурацию в методе 'init', где у вас есть доступ к' ServletContext'. 'Создание вашего' ThrifServlet' '@ Component' ничего не изменит, если он не управляется Spring. –

+0

Думаю, я понял это - взгляните на мой ответ ниже и предложите какие-либо улучшения? –

1

Я понял это в конце ...

  1. Добавлено @Component к ThriftServlet класса
  2. создал новый класс под названием ThriftProcessor (смотри ниже), который также является @Component
  3. Измененный ThriftServlet конструктор (см ниже), чтобы быть @Autowired и принимает параметр Processor
  4. Подстроил класс инициализатора приложения, чтобы получить ThriftServlet из весеннего боба вместо его экземпляра (ПРИМЕЧАНИЕ: должен был сообщить ApplicationContext, чтобы обновить себя до того, как это сработает)

ThriftProcessor класс:

@Component 
public class ThriftProcessor extends MyService.Processor<ThriftApiHandler> { 

    @Autowired 
    public ThriftProcessor(ThriftApiHandler iface) { 
     super(iface); 
    } 
} 

ThriftServlet класс:

@Component 
public class ThriftServlet extends TServlet { 

    @Autowired 
    public ThriftServlet(Processor<ThriftApiHandler> p) { 
     super(p, new TBinaryProtocol.Factory()); 
    } 
} 

Новая конфигурация сервлета в intializer:

//register the thrift API servlet using a spring bean 
ServletRegistration.Dynamic thrift = servletContext.addServlet("thriftapi", (ThriftServlet) ctx.getBean("thriftServlet")); // get thriftServlet from springbeans! 
thrift.setLoadOnStartup(2); 
thrift.addMapping("/api/*"); 

Если есть "лучше" способ сделать это, скажите так!

+1

Да, как я уже сказал, вам нужны ваши бобы из контекста Spring, если вы хотите, чтобы Spring справилась с ними. То, что вы сделали, кажется хорошим. Я просто изменил бы конструктор ThriftProcessor, чтобы просто иметь параметр 'ThriftApiHandler', без' ApplicationContext' (если у вас нет нескольких «ThriftApiHandler'). –

+0

О да, спасибо за это - отредактировал его в моем ответе! –

Смежные вопросы