Многослойное приложение Dropwizard
У меня было простое приложение службы отдыха Dropwizard, у которого было только два уровня: уровень контроллера (он же ресурс) и уровень персистентности (он же дао). Приложение Dropwizard было небольшим, лаконичным и работало без сбоев.
Но затем, через некоторое время, некоторые требования изменились, и мне нужно добавить некоторую бизнес-логику для обработки входящего объекта json и последующего сохранения его в базе данных. Итак, я ищу лучший подход для добавления этого уровня обслуживания между уровнями контроллера и персистентности.
Подскажите, пожалуйста, лучший способ добавления сервисного слоя в приложение. Благодарю.
Контроллер (он же ресурс):
@Path("/person")
@Consumes({MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_JSON})
public class PersonResource {
private PersonService personService;
public PersonResource(PersonService personService) {
this.personService = personService;
}
@GET
public List<Person> getAll(){
return personService.getAll();
}
@GET
@Path("/{id}")
public Person findById(@PathParam("id") Integer id){
return personService.findPersonById(id);
}
}
Уровень обслуживания:
public class PersonService {
private PersonDAO personDAO;
public PersonService(PersonDAO personDAO) {
this.personDAO = personDAO;
}
@UnitOfWork
public List<Person> getAll(){
return personDAO.getAll();
}
@UnitOfWork
public Person findPersonById(Integer id){
return personDAO.findById(id);
}
}
Класс применения:
public class DemoApplication extends Application<DemoConfiguration> {
public static void main(final String[] args) throws Exception {
new DemoApplication().run(args);
}
private final HibernateBundle<DemoConfiguration> hibernateBundle = new HibernateBundle<DemoConfiguration>(Person.class) {
@Override
public DataSourceFactory getDataSourceFactory(DemoConfiguration configuration) {
return configuration.getDatabaseAppDataSourceFactory();
}
};
@Override
public void initialize(final Bootstrap<DemoConfiguration> bootstrap) {
bootstrap.addBundle(hibernateBundle);
}
@Override
public void run(final DemoConfiguration configuration, final Environment environment) {
final PersonDAO personDAO = new PersonDAO(hibernateBundle.getSessionFactory());
final PersonService personResource = new PersonService(personDAO);
environment.jersey().register(personResource);
}
}
Я могу запустить приложение успешно, но когда дело доходит до обработки запроса, он не может 404 кода ошибки. И в логе вижу это сообщение:
org.glassfish.jersey.internal.inject.Providers: поставщик com.laboratory.dropwizard.service.PersonService, зарегистрированный во время выполнения SERVER, не реализует интерфейсы провайдера, применимые во время выполнения SERVER. Из-за проблем с конфигурацией ограничений поставщик com.laboratory.dropwizard.service.PersonService будет игнорироваться.
Что не так с Dropwizard и как я могу представить рабочий сервисный слой? Благодарю.
2 ответа
Вы получаете сообщение об ошибке (предупреждение), потому что вы пытаетесь register
PersonService
, register
Метод предназначен только для регистрации ресурсов и известных типов провайдеров. То, что вы, вероятно, хотите сделать вместо этого, это использовать внедрение зависимости. Что бы вы сделали, это связали DAO и сервис с инфраструктурой инъекций. Тогда вы могли бы использовать @Inject
вводить их, где это необходимо.
@Override
public void run(DemoConfiguration conf, Environment env) {
env.jersey().register(new AbstractBinder() {
@Override
public void configure() {
bindAsContract(PersonDAO.class).in(Singleton.class);
bindAsContract(PersonService.class).in(Singleton.class);
}
});
}
Теперь вы можете внедрить DAO в сервис и сервис в ресурс
public class PersonService {
private PersonDAO dao;
@Inject
public PersonService(PersonDAO dao){
this.dao = dao;
}
}
@Path("people")
public class PersonResource {
private PersonService service;
@Inject
public PersonResource(PersonService service) {
this.service = service;
}
}
В настоящее время создаются транзакции с
@UnitOfWork
аннотация работает только для ресурсов, управляемых Джерси. Если вы хотите использовать его за пределами ресурсов Джерси, например, в аутентификаторах, вам следует создать экземпляр класса сUnitOfWorkAwareProxyFactory
,
Пример кода, который иллюстрирует это:
SessionDao dao = new SessionDao(hibernateBundle.getSessionFactory());
ExampleAuthenticator exampleAuthenticator = new UnitOfWorkAwareProxyFactory(hibernateBundle)
.create(ExampleAuthenticator.class, SessionDao.class, dao);
Попробуйте что-нибудь в этом направлении.