Многослойное приложение 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);

Попробуйте что-нибудь в этом направлении.

Другие вопросы по тегам