2015-06-11 5 views
4

Предупреждение: я понимаю, что может быть злоупотреблением намерениями за весенними бобами и/или методами интерфейса по умолчанию 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())); 
     } 

} 

Примечание что он правильно решает бобы и, похоже, работает. Прежде чем я начну использовать такой шаблон, я хотел бы знать о рисках.

+0

Это злоупотребление интерфейсом как пространство имен. Поскольку эти методы 'default' ничего не делают, но возвращают статическую информацию, вы должны сделать их' static' и использовать 'import static' вместо реализации псевдо-интерфейса. – Holger

+0

@ Хольгер, я понимаю, что этот пример верен. Но скажите, что я хотел добавить функциональность, которая нуждается в доступе к текущему экземпляру класса? Таким образом, я получаю значительную функциональность, просто добавляя интерфейс и избегая необходимости передавать экземпляр другим методам. – RutledgePaulV

+0

Ну, в этом примере также неясно, почему вы не можете просто использовать абстрактный базовый класс для «Документов». Кроме того, нет ничего плохого в использовании наследования, независимо от того, с помощью 'abstract class' или' interface' с методами 'default'. Или есть конкретная проблема, почему это должно быть иначе в контексте Весны? – Holger

ответ

1

Есть уже рассмотренные предостережения на пребывание away from statics

В вашем случае, вы можете столкнуться с проблемой, если интерфейс получает ссылки до вашего контекста весны инициализируется. Таким образом, статический ClientDetailsService service будет пустым, что приведет к NPE.

Как правило, с ростом кода вы можете потерять контроль над этим интерфейсом во время запуска приложения.

+1

Хорошая точка [вещь с порядком инициализации] (http://stackoverflow.com/q/23096084/2711488).Но также неверно помещать статическую информацию в методы 'interface', что делает ее похожей на информацию о каждом экземпляре ... – Holger

+0

@ Хольгер, когда я думаю о интерфейсах по умолчанию, я все еще придерживаюсь статики, а не экземпляра. Хотя я получаю ваш ponit о том, как вовлеченная семантика может заставить кого-то поверить в его информацию об уровне экземпляра против статического. – 6ton

+2

Пожалуйста, 'default' * методы *. Наличие методов 'default' не изменяет того, что такое' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' ''. Если вы хотите использовать 'static' методы, вы можете добавить' static' методы в 'interface' (который не делает его« статическим интерфейсом »). Но методы 'default' - это просто методы non⁠-⁠'abstract', как и другие методы экземпляра non-' abstract' для конкретных 'class'es. – Holger

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