Post on 09-Jun-2015
INJECT
INJECTION
Юра Литвиненко
• Джавист• http://linkd.in/lytvynenko
• @surg
speechat.co
План
План
•Проблема
План
•Проблема• Внедрение DI
План
•Проблема• Внедрение DI
• Трудности
План
•Проблема• Внедрение DI
• Трудности •Польза
План
•Проблема• Внедрение DI
• Трудности •Польза• ??????????
План
•Проблема• Внедрение DI
• Трудности •Польза• ??????????
• PROFIT!
Проблема
Проблема: Проект
Проблема: Проект
• С 2005 года
Проблема: Проект
• С 2005 года
• До черта кода
Проблема: Проект
• С 2005 года
• До черта кода• Много технического долга
Проблема: Проект
• С 2005 года
• До черта кода• Много технического долга•Монолитный
Проблема: Монолит
Проблема: Монолит
Проблема: Монолит
Проблема: Монолит
Проблема: Монолит
Проблема: Монолит
Проблема: Монолит
Проблема: Монолит
Проблема: Монолит
Проблема: Монолит
А душа просит...
Модульность!
Модульность
Модульность
Модульность
Модульность
Модульность
А еще...
Работа с базой
Проблема: БД
void updateSmth() {
}
Проблема: БД
void updateSmth() {
IDbConnection con = getConnection();
}
Проблема: БД
void updateSmth() {
IDbConnection con = getConnection();
try {
}
}
Проблема: БД
void updateSmth() {
IDbConnection con = getConnection();
try {
// do stuff with con
}
}
Проблема: БД
void updateSmth() {
IDbConnection con = getConnection();
try {
// do stuff with con
} finally {
con.close();
}}
Проблема: БД
void updateSmth() {
// do stuff with con
}
Проблема: БД@Transactionalvoid updateSmth() {
// do stuff with con
}
План
•Проблема•Внедрение DI
• Трудности • Польза• ??????????
• PROFIT!
Что надеть?
Что надеть?выбрать
Внедрение: Выбор
• Spring
• Guice
• Pico-, nano- container
• Apache Avalon
• Apache HiveMind
Внедрение: Выбор
•Spring
•Guice
• Pico-, nano- container
• Apache Avalon
• Apache HiveMind
Внедрение: Выбор
vs
Внедрение: Выбор
vs
Внедрение: Guice
• Легковесность
Внедрение: Guice
• Легковесность• Конфигурация в коде
Внедрение: Guice
• Легковесность• Конфигурация в коде• Мультибиндинг
Внедрение: Guice
• Легковесность• Конфигурация в коде• Мультибиндинг• Упрощенное AOP
Внедрение: Guice
• Легковесность• Конфигурация в коде• Мультибиндинг• Упрощенное AOP
• RI JSR-330
Guice
Guice: Знакомство
Guice: Знакомство
Guice: Знакомство
Guice: Знакомство
•Биндинг
Guice: Знакомство
•Биндинг (binding)
Guice: Знакомство
• Биндинг (binding) – привязка интерфейса к реализации. Конфигурация зависимостей
Guice: Знакомство
• Биндинг (binding) – привязка интерфейса к реализации. Конфигурация зависимостей
•Модуль
Guice: Знакомство
• Биндинг (binding) – привязка интерфейса к реализации. Конфигурация зависимостей
• Модуль – класс, в котором происходит биндинг. Строительный элемент Guice
Guice: Биндинг в коде
Guice: Биндинг в коде
• Вовлечен компилятор
Guice: Биндинг в коде
• Вовлечен компилятор• Java
Guice: Биндинг в коде
• Вовлечен компилятор• Java
• Выразительный DSL
Guice: Биндинг в коде
• Вовлечен компилятор• Java
• Выразительный DSL
• Появился в Spring 3.1
Guice: Биндинг в коде
Guice: Биндинг в кодеbind(FlightFactory.class)
Guice: Биндинг в кодеbind(FlightFactory.class) .to(StubFlightFactory.class)
Guice: Биндинг в кодеbind(FlightFactory.class) .to(StubFlightFactory.class)
...
bind(FlightFactory.class)
Guice: Биндинг в кодеbind(FlightFactory.class) .to(StubFlightFactory.class)
...
bind(FlightFactory.class) .toInstance( )
Guice: Биндинг в кодеbind(FlightFactory.class) .to(StubFlightFactory.class)
...
bind(FlightFactory.class) .toInstance(flightFactoryMock)
Guice: Биндинг в кодеclass Foo {
...
}
Guice: Биндинг в кодеclass Foo {
@Inject FlightFactory flightFactory;
...
}
Guice: Multibinding
Guice: Multibinding
• Коллекция в качестве зависимости
Guice: Multibinding
• Коллекция в качестве зависимости• Определяется в разных модулях
Guice: Multibinding
• Коллекция в качестве зависимости• Определяется в разных модулях• По сути - поддержка плагинов
Guice: Multibinding
Guice: MultibindingMultibinder<Service> binder =
Guice: MultibindingMultibinder<Service> binder = Multibinder.newSetBinder( binder(), Service.class);
Guice: MultibindingMultibinder<Service> binder = Multibinder.newSetBinder( binder(), Service.class);
binder.addBinding()
Guice: MultibindingMultibinder<Service> binder = Multibinder.newSetBinder( binder(), Service.class);
binder.addBinding() .to(DocumentService.class);
Guice: MultibindingMultibinder<Service> binder = Multibinder.newSetBinder( binder(), Service.class);
binder.addBinding() .to(DocumentService.class);...
Guice: MultibindingMultibinder<Service> binder = Multibinder.newSetBinder( binder(), Service.class);
binder.addBinding() .to(DocumentService.class);...binder.addBinding()
Guice: MultibindingMultibinder<Service> binder = Multibinder.newSetBinder( binder(), Service.class);
binder.addBinding() .to(DocumentService.class);...binder.addBinding() .toInstance(userService);
Guice: Multibindingpublic class ServiceRegistry {
...
}
Guice: Multibindingpublic class ServiceRegistry {
@Inject private Set<Service> services;
...
}
Guice: Ошибки
Guice: Ошибки
• Ошибки сложно отследить
Guice: Ошибки
• Ошибки сложно отследить• Guice подробно разъясняет
Guice: Ошибки
• Ошибки сложно отследить• Guice подробно разъясняет
• ...в чем ошибка
Guice: Ошибки
• Ошибки сложно отследить• Guice подробно разъясняет
• ...в чем ошибка
• ...и главное - где
Например
НапримерЗабыли забиндить интерфейс UserService
Guice: Ошибкиpublic class UserManager {
}
Guice: Ошибкиpublic class UserManager {
@Inject private UserService service;
...
}
Guice: Ошибкиpublic class UserManager {
@Inject private UserService service;
...
}
inj.getInstance(UserManager.class);
Guice: ОшибкиGuice configuration errors:
Guice: ОшибкиGuice configuration errors:
1) No implementation for com.UserService was bound.
Guice: ОшибкиGuice configuration errors:
1) No implementation for com.UserService was bound. while locating com.UserService
Guice: ОшибкиGuice configuration errors:
1) No implementation for com.UserService was bound. while locating com.UserService for field at com.UserManager.service(UserManager.java:17)
Guice: ОшибкиGuice configuration errors:
1) No implementation for com.UserService was bound. while locating com.UserService for field at com.UserManager.service(UserManager.java:17) while locating com.UserManager
Guice: ОшибкиGuice configuration errors:
1) No implementation for com.UserService was bound. while locating com.UserService for field at com.UserManager.service(UserManager.java:17) while locating com.UserManager
1 error at ...
Guice: ОшибкиGuice configuration errors:
1) No implementation for com.UserService was bound. while locating com.UserService for field at com.UserManager.service(UserManager.java:17) while locating com.UserManager
1 error at ...
Guice: Ошибки...
com.google.inject.internal.InjectorImpl.getProvider(InjectorImpl.java:1004)
Guice: Ошибки...
com.google.inject.internal.InjectorImpl.getProvider(InjectorImpl.java:1004)
at com.google.inject.internal.InjectorImpl.getProvider(InjectorImpl.java:961)
Guice: Ошибки...
com.google.inject.internal.InjectorImpl.getProvider(InjectorImpl.java:1004)
at com.google.inject.internal.InjectorImpl.getProvider(InjectorImpl.java:961)
at com.google.inject.internal.InjectorImpl.getInstance(InjectorImpl.java:1013)
Guice: Ошибки...
com.google.inject.internal.InjectorImpl.getProvider(InjectorImpl.java:1004)
at com.google.inject.internal.InjectorImpl.getProvider(InjectorImpl.java:961)
at com.google.inject.internal.InjectorImpl.getInstance(InjectorImpl.java:1013)
at com.jeeconf.Main.main(Main.java:21)
Guice: И еще...
Guice: А также
• Поддержка GWT (GIN)
Guice: А также
• Поддержка GWT (GIN)
• Assisted Inject
Guice: А также
• Поддержка GWT (GIN)
• Assisted Inject
• Поддержка TestNG
Guice: А также
• Поддержка GWT (GIN)
• Assisted Inject
• Поддержка TestNG
• etc...
С чего начать?
ВнедрениеServlet
ВнедрениеServlet
Struts Remoting
ВнедрениеServlet
Struts Remoting
Managers (BO)
План
• Проблема• Внедрение DI
•Трудности
•Польза• ??????????
• PROFIT!
Трудности: Struts
Трудности: Struts
• Action’ы и Controller’ы - синглтоны
Трудности: Struts
• Action’ы и Controller’ы - синглтоны
• Hardcoded
Решение: Struts
Решение: Struts
• Один базовый класс
Решение: Struts
• Один базовый класс• Явная инъекция в конструкторе
Решение: Struts
• Один базовый класс• Явная инъекция в конструкторе• Field injection
Решение: Struts
• Один базовый класс• Явная инъекция в конструкторе• Field injection
• Провайдеры
Решение: Strutsinterface Provider {
}
Решение: Strutsinterface Provider<T> {
}
Решение: Strutsinterface Provider<T> {
T get();
}
Решение: Strutsclass BaseAction extends Action {
}
Решение: Strutsclass BaseAction extends Action {
public BaseAction() {
}
}
Решение: Strutsclass BaseAction extends Action {
public BaseAction() {
Injector injector = ...;
}
}
Решение: Strutsclass BaseAction extends Action {
public BaseAction() {
Injector injector = ...;
injector.injectMembers(this);
}
}
Решение: Strutsclass MyAction extends BaseAction {
}
Решение: Strutsclass MyAction extends BaseAction {
Provider<MyManager> myManager;
}
Решение: Strutsclass MyAction extends BaseAction {
@Inject Provider<MyManager> myManager;
}
Решение: Strutsclass MyAction extends BaseAction {
@Inject Provider<MyManager> myManager;
... execute(Context context) {
}
}
Решение: Strutsclass MyAction extends BaseAction {
@Inject Provider<MyManager> myManager;
... execute(Context context) {
myManager.get().doSmth();
}
}
Трудности: Сервлет
Трудности: Сервлет
• Сервлеты 2.0 - только в web.xml
• Хак: Guice servlet
Трудности: Сервлет
• Сервлеты 2.0 - только в web.xml
• Хак: Guice servlet
• Stack overflow в некоторых случаях
Решение: Сервлет
Решение: Сервлет
• Servlet 3.0
Решение: Сервлет
• Servlet 3.0
• Программная регистрация фильтров и сервлетов
Решение: Сервлет
• Servlet 3.0
• Программная регистрация фильтров и сервлетов
• Свой API (близкий к Guice-Servlet)
Трудности: Статика
Трудности: Статика
• Большинство методов в менеджерах - статические
Трудности: Статика
• Большинство методов в менеджерах - статические
• Очень плохо тестируется
Трудности: Статика
• Большинство методов в менеджерах - статические
• Очень плохо тестируется• Некоторые лучше не трогать
Трудности: Статика
• Большинство методов в менеджерах - статические
• Очень плохо тестируется• Некоторые лучше не трогать• Вирусность
Решение: Статика
Решение: Статика
• Фасады
Решение: Статика
• Фасады (Да, кэп!)
Решение: Статика
• Фасады• Расширение - по необходимости
(Да, кэп!)
Решение: Статика
• Фасады• Расширение - по необходимости
• Более удобный API
(Да, кэп!)
Решение: Статика
• Фасады• Расширение - по необходимости
• Более удобный API
• Спрятать “checked” исключения
(Да, кэп!)
Решение: Статикаclass UserManager {
}
Решение: Статикаclass UserManager {
static User getUser(String login)
}
Решение: Статикаclass UserManager {
static User getUser(String login) throws SQLException, RetrieveFailedException { ... }}
Решение: Статикаclass UserManager {
static User getUser(String login) throws SQLException, RetrieveFailedException { ... }}
interface UserManagerFacade {
}
Решение: Статикаclass UserManager {
static User getUser(String login) throws SQLException, RetrieveFailedException { ... }}
interface UserManagerFacade {
User getUser(String userLogin);
}
Решение: Статикаclass UserManagerFacadeImpl
}
Решение: Статикаclass UserManagerFacadeImpl implements UserManagerFacade {
}
Решение: Статикаclass UserManagerFacadeImpl implements UserManagerFacade {
User getUser(String login) {
}}
Решение: Статикаclass UserManagerFacadeImpl implements UserManagerFacade {
User getUser(String login) { try {
}
}}
Решение: Статикаclass UserManagerFacadeImpl implements UserManagerFacade {
User getUser(String login) { try { return UserManager.getUser(login) }
}}
Решение: Статикаclass UserManagerFacadeImpl implements UserManagerFacade {
User getUser(String login) { try { return UserManager.getUser(login) } catch(Exception e) { }
}}
Решение: Статикаclass UserManagerFacadeImpl implements UserManagerFacade {
User getUser(String login) { try { return UserManager.getUser(login) } catch(Exception e) { // rethrow unchecked exception }
}}
не все так плохо
План• Проблема
• Внедрение DI
• Трудности •Польза
• ??????????
• PROFIT!
Польза
Польза
•Первый шаг к модульности
Польза
•Первый шаг к модульности
•Работа с БД
Польза
•Первый шаг к модульности
•Работа с БД
• Код компактнее
Польза
•Первый шаг к модульности
•Работа с БД
• Код компактнее• Юнит тесты
Польза
•Первый шаг к модульности
•Работа с БД
• Код компактнее• Юнит тесты• Виднее избыток зависимостей
?
Спасибо!