Предупреждение: я понимаю, что может быть злоупотреблением намерениями за весенними бобами и/или методами интерфейса по умолчанию Java 8. Я ищу конкретную и аргументированную критику того, почему это может быть небезопасным подходом, который я не признаю.Использование пружинных управляемых компонентов в стандартном методе интерфейса?
Я определил класс, который дает мне статический доступ к бегущему контексту приложения:
@Component
public class BeanAccessor implements ApplicationContextAware {
private static ApplicationContext applicationContext;
public static <T> T getSingleton(Class<T> clazz){
return applicationContext.getBean(clazz);
}
public static <T> T getSingleton(String beanName, Class<T> clazz){
return applicationContext.getBean(beanName, clazz);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
BeanAccessor.applicationContext = applicationContext;
}
}
я тогда может использовать эти методы BeanAccessor внутри методов интерфейса по умолчанию для того, чтобы получить доступ к весне удались бобы изнутри метода.
Я понимаю, что эта функциональность может быть достигнута путем реализации других классов и сервисов, а не для того, чтобы почувствовать необходимость смешать ее с текущей (по крайней мере, для примера ниже, я на самом деле ничего не делаю с этим) , Это отчасти является «художественным» предпочтением, и я уверен, что продолжу поиск других вариантов использования.
Обратите внимание, что я НЕ пытаюсь сохранить состояние в каждом экземпляре, как описано здесь https://kerflyn.wordpress.com/2012/07/09/java-8-now-you-have-mixins/, и я действительно признаю, что есть опасности в этом.
Вот пример использования:
public interface ClientAware {
String TENANT_NAME = "TENANT_NAME";
default ClientDetails clientDetails() {
ClientDetailsService service = BeanAccessor.getSingleton(ClientDetailsService.class);
return service.loadClientByClientId(SecurityUtil.getClientId());
}
default Map<String, Object> clientInfo() {
return clientDetails().getAdditionalInformation();
}
default String tenant() {
return (String) clientInfo().get(TENANT_NAME);
}
}
И тогда мой фактический класс с помощью интерфейса (и другой интерфейс, который делает подобные вещи, чтобы добавить мета-информацию для ответа):
@RestController
@RequestMapping("/documents")
public class Documents implements WrapAware, ClientAware {
@Autowired
private DocumentService docService;
@RequestMapping(method = RequestMethod.GET)
public Object byPathAndTenant(@RequestParam("path") String path) {
return ok(docService.getDocumentsByPathAndTenant(path, tenant()));
}
}
Примечание что он правильно решает бобы и, похоже, работает. Прежде чем я начну использовать такой шаблон, я хотел бы знать о рисках.
Это злоупотребление интерфейсом как пространство имен. Поскольку эти методы 'default' ничего не делают, но возвращают статическую информацию, вы должны сделать их' static' и использовать 'import static' вместо реализации псевдо-интерфейса. – Holger
@ Хольгер, я понимаю, что этот пример верен. Но скажите, что я хотел добавить функциональность, которая нуждается в доступе к текущему экземпляру класса? Таким образом, я получаю значительную функциональность, просто добавляя интерфейс и избегая необходимости передавать экземпляр другим методам. – RutledgePaulV
Ну, в этом примере также неясно, почему вы не можете просто использовать абстрактный базовый класс для «Документов». Кроме того, нет ничего плохого в использовании наследования, независимо от того, с помощью 'abstract class' или' interface' с методами 'default'. Или есть конкретная проблема, почему это должно быть иначе в контексте Весны? – Holger