Я кратко расскажу о своих целях ниже, если есть какие-то лучшие альтернативные способы достижения того, что я хочу. This question очень похож на то, что мне нужно, но не совсем точно, что мне нужно. Мой вопрос ...Возможно ли создать один динамический прокси-сервер, который может добавить функциональность в любой конкретный класс?
У меня есть интерфейс:
public interface Command<T> extends Serializable {}
..plus реализация:
public class EchoCommand implements Command<String> {
private final String stringToEcho;
public EchoCommand(String stringToEcho) {
this.stringToEcho = stringToEcho;
}
public String getStringToEcho() {
return stringToEcho;
}
}
Если я создаю еще один интерфейс:
public interface AuthorizedCommand {
String getAuthorizedUser();
}
..is есть способ, которым я могу реализовать интерфейс AuthorizedCommand на EchoCommand во время выполнения, не зная тип подкласса?
public <C extends Command<T>,T> C authorize(C command) {
// can this be done so the returned Command is also an
// instance of AuthorizedCommand?
return (C) theDecoratedCommand;
}
почему ... Я использовал Нетти, чтобы построить себе очень простую структуру клиент/сервер, проверка концепции, основанной на командах. Между командой, распределенной между клиентом и сервером, и обработчиком команд существует взаимно однозначное отношение. Обработчик работает только на сервере, и их очень просто реализовать. Вот интерфейс.
public interface CommandHandler<C extends Command<T>,T> {
public T execute(C command);
}
На стороне клиента все очень просто. Сохранение простых вещей в клиенте является основной причиной, по которой я решил попробовать командный API. Клиент отправляет команду и возвращает будущее. Понятно, что вызов асинхронный, плюс клиент не имеет дело с такими вещами, как упаковка звонка в SwingWorker
. Зачем создавать синхронный API для асинхронных вызовов (что-либо по сети), чтобы обернуть синхронные вызовы в асинхронных вспомогательных методах? Я использую Guava для этого.
public <T> ListenableFuture<T> dispatch(Command<T> command)
Теперь я хочу добавить аутентификацию и авторизацию. Я не хочу, чтобы мои обработчики команд знали о авторизации, но в некоторых случаях я хочу, чтобы они могли запросить что-то относительно того, к какому пользователю выполняется эта команда. В основном я хочу иметь атрибут lastModifiedBy
для некоторых данных.
Я смотрю с помощью Apache Shiro, так очевидный ответ, кажется, чтобы использовать их SubjectAwareExecutor
, чтобы получить информацию об авторизации в ThreadLocal
, но тогда мои обработчики должны быть осведомлены о Shiro, или мне нужно абстрагировать прочь найти некоторый способ сопоставления команд с информацией об аутентификации/авторизации в Сиро.
Поскольку каждая команда уже имеет состояние и проходит через весь мой конвейер, все гораздо проще, если я могу просто украсить команды, которые были авторизованы, чтобы они реализовали интерфейс AuthorizedCommand. Затем мои обработчики команд могут использовать информацию, которая была украшена, но она полностью необязательна.
if(command instanceof AuthorizedCommand) {
// We can interrogate the command for the extra meta data
// we're interested in.
}
Таким образом, я могу также развивать все, что связано с аутентификации/авторизации независимо от основной бизнес-логики моего приложения. Это также (я думаю) позвольте мне связать информацию сессии с Netty Channel
или ChannelGroup
, что, я думаю, имеет больше смысла для инфраструктуры NIO, так? Я думаю, что Netty 4 может даже разрешить набор типизированных атрибутов на Channel
, который хорошо подходит для отслеживания таких вещей, как информация о сеансе (я еще не изучал его).
Главное, что я хочу сделать, - это очень быстро создать прототип приложения. Я хотел бы начать с диспетчера клиентской стороны, который представляет собой простую карту типов команд для управления обработчиками и полностью игнорировать сетевые и защитные стороны вещей. Как только я доволен своим прототипом, я поменю в своем диспетчере на основе Netty (используя Guice), а затем, очень поздно в цикле разработки, я добавлю Сиро.
Я бы очень признателен за любые комментарии или конструктивную критику. Если то, что я объяснил, имеет смысл делать и невозможно в простой старой Java, я бы подумал о создании этой конкретной функции на другом языке JVM. Может, Скала?
Вы пробовали это? У вас будет гораздо больше шансов получить какую-то помощь, если вы действительно попробуете его, а затем опубликуйте свои результаты. –