Post on 22-Jan-2018
transcript
Dependency Injection with Programmatic Configuration
Peter Lehto Senior Vaadin Expert
@peter_lehto
Dependency Injection (DI) is a runtime mechanism
Dependency Injection (DI) is a runtime mechanism
Dependency Injection (DI) is a runtime mechanism where dependency between the client object and the dependent object does not occur directly.
Dependency Injection (DI) is a runtime mechanism where dependency between the client object and the dependent object does not occur directly.
Dependency Injection (DI) is a runtime mechanism where dependency between the client object and the dependent object does not occur directly.
With DI the client object does not necessarily manage the lifecycle of the dependent object.
Dependency Injection (DI) is a runtime mechanism where dependency between the client object and the dependent object does not occur directly.
With DI the client object does not necessarily manage the lifecycle of the dependent object.
Dependency Injection (DI) is a runtime mechanism where dependency between the client object and the dependent object does not occur directly.
With DI the client object does not necessarily manage the lifecycle of the dependent object.
Instead with DI a special DI container takes care of the object lifecycle management
Dependency Injection (DI) is a runtime mechanism where dependency between the client object and the dependent object does not occur directly.
With DI the client object does not necessarily manage the lifecycle of the dependent object.
Instead with DI a special DI container takes care of the object lifecycle management
Dependency Injection (DI) is a runtime mechanism where dependency between the client object and the dependent object does not occur directly.
With DI the client object does not necessarily manage the lifecycle of the dependent object.
Instead with DI a special DI container takes care of the object lifecycle management where clients reference managed and possibly shared objects.
Dependency Injection (DI) is a runtime mechanism where dependency between the client object and the dependent object does not occur directly.
With DI the client object does not necessarily manage the lifecycle of the dependent object.
Instead with DI a special DI container takes care of the object lifecycle management where clients reference managed and possibly shared objects.
Why…?
• Loose coupling
• Loose coupling• Dependency inversion
• Loose coupling• Dependency inversion• High Abstraction
• Loose coupling• Dependency inversion• High Abstraction • Highly cohesive modules
• Loose coupling• Dependency inversion• High Abstraction • Highly cohesive modules• Deployment time config
How…?
CDI Context and Dependency Injection
JSR-299 JavaEE specification
Spring Framework
SpringBeans
• @Inject
• @Inject• @Autowired
• @Inject• @Autowired• @Qualifier
• @Inject• @Autowired• @Qualifier• @Produces
• @Inject• @Autowired• @Qualifier• @Produces• @Bean
• @Inject• @Autowired• @Qualifier• @Produces• @Bean• @Component
Example?
public interface VehicleService {
void performService(Vehicle vehicle);
}
@Named("Audi")public class AudiService implements VehicleService {
@Overridepublic void performService(Vehicle vehicle) {System.out.println("Performing Audi service");
}}
@Named("BMW")public class BMWService implements VehicleService {
@Overridepublic void performService(Vehicle vehicle) {System.out.println("Performing BMW service");
}}
@Named("VW")public class VWService implements VehicleService {
@Overridepublic void performService(Vehicle vehicle) {System.out.println("Performing VW service");
}}
public class VehicleOperator {
@Inject@Named("Audi")private VehicleService audiService;
}
public class VehicleOperator {
@Inject@Named("Audi")private VehicleService audiService;
@Inject@Named("BMW")private VehicleService bmwService;
}
public class VehicleOperator {
@Inject@Named("Audi")private VehicleService audiService;
@Inject@Named("BMW")private VehicleService bmwService;
@Inject@Named("VW")private VehicleService vwService;
}
public class VehicleOperator {
@Inject@Named("Audi")private VehicleService audiService;
@Inject@Named("BMW")private VehicleService bmwService;
@Inject@Named("VW")private VehicleService vwService;
public void operate(Vehicle vehicle) {audiService.performService(vehicle);
}}
Setter Injection
For interfering purposes
public class VehicleOperator {
private VehicleService audiService;private VehicleService bmwService;private VehicleService vwService;
public class VehicleOperator {
private VehicleService audiService;private VehicleService bmwService;private VehicleService vwService;
@Injectpublic void setAudiService(@Named("Audi") VehicleService audiService) {
this.audiService = audiService;}
public class VehicleOperator {
private VehicleService audiService;private VehicleService bmwService;private VehicleService vwService;
@Injectpublic void setAudiService(@Named("Audi") VehicleService audiService) {
this.audiService = audiService;}
@Injectpublic void setBMWService(@Named("BMW") VehicleService bmwService) {
this.bmwService = bmwService;}
public class VehicleOperator {
private VehicleService audiService;private VehicleService bmwService;private VehicleService vwService;
@Injectpublic void setAudiService(@Named("Audi") VehicleService audiService) {
this.audiService = audiService;}
@Injectpublic void setBMWService(@Named("BMW") VehicleService bmwService) {
this.bmwService = bmwService;}
@Injectpublic void setVWService(@Named("VW") VehicleService vwService) {
this.vwService = vwService;}
Constructor Injection
For injecting at initialisation time
public class VehicleOperator {
private VehicleService audiService;private VehicleService bmwService;private VehicleService vwService;
public class VehicleOperator {
private VehicleService audiService;private VehicleService bmwService;private VehicleService vwService;
@Injectpublic VehicleOperator(@Named("Audi") VehicleService audiService,
@Named("BMW") VehicleService bmwService, @Named("VW") VehicleService vwService) {
this.audiService = audiService;…
}
Producer method
For programmatic bean manipulation
public class VehicleServiceFactory {
}
public class VehicleServiceFactory {
@Produces@Named("VW")protected VehicleService produceVWService() {
}
}
public class VehicleServiceFactory {
@Produces@Named("VW")protected VehicleService produceVWService() {
VehicleService vwService = ServiceProvider.provideVWService();vwService.enableEmissionManipulation(true);return vwService;
}
}
Avoid ambiguity
with @Vetoed, @Alternative or @Primary
Programmatic Injection
With Instance<T>
public class VehicleOperator {
}
public class VehicleOperator {
@Inject@Named("BMW")private Instance<VehicleService> serviceInstantiator;
}
public class VehicleOperator {
@Inject@Named("BMW")private Instance<VehicleService> serviceInstantiator;
public void operate(Vehicle vehicle) {VehicleService service = serviceInstantiator.get();
}}
public class VehicleOperator {
@Inject@Named("BMW")private Instance<VehicleService> serviceInstantiator;
public void operate(Vehicle vehicle) {VehicleService service = serviceInstantiator.get();service.performService(vehicle);
}}
Programmatic Configuration!
As promised :)
public class Vehicle {
public String getMake() {return "BMW";
}
}
public class NamedLiteral extends AnnotationLiteral<Named> implements Named
public class VehicleOperater {
public class VehicleOperater {
@Inject@Anyprivate Instance<VehicleService> serviceInstantiator;
}
public class VehicleOperater {
@Inject@Anyprivate Instance<VehicleService> serviceInstantiator;
public void operate(Vehicle vehicle) {NamedLiteral named = new NamedLiteral(vehicle.getMake());
}}
public class VehicleOperater {
@Inject@Anyprivate Instance<VehicleService> serviceInstantiator;
public void operate(Vehicle vehicle) {NamedLiteral named = new NamedLiteral(vehicle.getMake());VehicleService service = serviceInstantiator.select(named).get();
}}
public interface TaskProcessor {
void processTask(Task task);
}
@AsynchronousProcessingpublic class ReportingTask implements Task {
}
@AsynchronousProcessingpublic class ReportingTask implements Task {
}
@SynchronousProcessingpublic class SaveDataTask implements Task {
}
@AsynchronousProcessingpublic class AsynchronousTaskProcessor implements TaskProcessor {
@Overridepublic void processTask(Task task) {
}}
@AsynchronousProcessingpublic class AsynchronousTaskProcessor implements TaskProcessor {
@Overridepublic void processTask(Task task) {
}}
@SynchronousProcessingpublic class SynchronousTaskProcessor implements TaskProcessor {
@Overridepublic void processTask(Task task) {
}}
public class TaskHandler {
@Inject@Anyprivate Instance<TaskProcessor> processorInstantiator;
}
public class TaskHandler {
@Inject@Anyprivate Instance<TaskProcessor> processorInstantiator;
public void handleTasks(List<Task> tasks) {tasks.forEach(task -> {
processorInstantiator.select(task.getClass().getAnnotations()).get(). processTask(task);
});}
}
Vaadin with CDI
public class MyVaadinUI extends UI {
}
@CDIUI("")public class MyVaadinUI extends UI {
}
@CDIUI("")public class MyVaadinUI extends UI {
@Injectprivate MainMenu mainMenu;
@Injectprivate ViewArea viewArea;
}
@CDIUI("")public class MyVaadinUI extends UI {
@Injectprivate MainMenu mainMenu;
@Injectprivate ViewArea viewArea;
@Overrideprotected void init(VaadinRequest request) {
HorizontalLayout hl = new HorizontalLayout(mainMenu, viewArea);
…setContent(hl);
}}
UI as managed bean
Entry point
UI as managed bean
Entry point
Context aware
UI as managed bean
Entry point
Context aware
Accesible through URI
UI as managed bean
@CDIUI("")public class MyVaadinUI extends UI {
@Injectprivate MainMenu mainMenu;
@Injectprivate ViewArea viewArea;
@Overrideprotected void init(VaadinRequest request) {
HorizontalLayout hl = new HorizontalLayout(mainMenu, viewArea);
…setContent(hl);
}}
@CDIUI("anotherUI")public class MyVaadinUI extends UI {
@Injectprivate MainMenu mainMenu;
@Injectprivate ViewArea viewArea;
@Overrideprotected void init(VaadinRequest request) {
HorizontalLayout hl = new HorizontalLayout(mainMenu, viewArea);
…setContent(hl);
}}
http://localhost:8080/app/
http://localhost:8080/app/anotherUI
app: contextanotherUI : UI name
Scope UI specific beans with
@UIScoped
@UIScopedpublic class MainMenuBean extends CssLayout implements MainMenu
@UIScoped
Bean associated with UI instance
@UIScoped
Bean associated with UI instance
Bean associated with Web browser tab
@UIScoped
Bean associated with UI instance
Bean associated with Web browser tab
@CDIUI is by default @UIScoped
@UIScoped
@CDIUI MyVaadinUI
_____________________________
@Injectprivate MainMenu menu;
@Injectprivate User currentUser;
@UIScoped
MyVaadinUIMainMenu
@SessionScoped
User
@CDIUI MyVaadinUI
_____________________________
@Injectprivate MainMenu menu;
@Injectprivate User currentUser;
@UIScoped
MyVaadinUIMainMenu
@SessionScoped
User
@CDIUI MyVaadinUI
_____________________________
@Injectprivate MainMenu menu;
@Injectprivate User currentUser;
@CDIUI MyVaadinUI
_____________________________
@Injectprivate MainMenu menu;
@Injectprivate User currentUser;
@UIScoped
MyVaadinUIMainMenu
@UIScoped
MyVaadinUIMainMenu
What about Views?
View
Component composition
View
Component composition
Active view switched by Navigator
View
Component composition
Active view switched by Navigator
Positioned inside ViewDisplay
View
HorizontalLayoutContentAreaMenu
View1
View2
View3
HorizontalLayoutView1Menu
View1
View2
View3
HorizontalLayoutView2Menu
View1
View2
View3
HorizontalLayoutView3Menu
View1
View2
View3
View as managed bean with
@CDIView
public class CustomerViewBean
public class CustomerViewBean extends VerticalLayout
@CDIView("customers")public class CustomerViewBean extends VerticalLayout implements View
http://localhost:8080/app/#!customers
#! : Navigator identifiercustomers : View name
Scope View specific beans with
@ViewScoped
@ViewScoped
Beans associated with View
@ViewScoped
Beans associated with View
@CDIView by default @ViewScoped
@ViewScoped
@ApplicationScoped
@ApplicationScoped@ApplicationScoped
@SessionScoped @SessionScoped @SessionScoped
@ApplicationScoped
@SessionScoped @SessionScoped @SessionScoped
@UI Scoped
@UI Scoped
@UI Scoped
@UI Scoped
@UI Scoped
@UI Scoped
@ApplicationScoped
@ View
@ View
@ View
@ View
@ View
@ View
@ View
@ View
@ View
@ View
@ View
@ View
@SessionScoped @SessionScoped @SessionScoped
@UI Scoped
@UI Scoped
@UI Scoped
@UI Scoped
@UI Scoped
@UI Scoped
Lessons learned
Lessons learned
1. Depend on abstractions through Dependency Inversion
Lessons learned
1. Depend on abstractions through Dependency Inversion
2. Beans need to be managed by (CDI) container
Lessons learned
1. Depend on abstractions through Dependency Inversion
2. Beans need to be managed by (CDI) container
3. Inject to Fields, Methods and Constructor
Lessons learned
1. Depend on abstractions through Dependency Inversion
2. Beans need to be managed by (CDI) container
3. Inject to Fields, Methods and Constructor
4. Producer method allows programmatic bean creation and non-default constructor
Lessons learned
1. Depend on abstractions through Dependency Inversion
2. Beans need to be managed by (CDI) container
3. Inject to Fields, Methods and Constructor
4. Producer method allows programmatic bean creation and non-default constructor
5. Instance<T> provides on-demand instantiation with candidate selection
Lessons learned
1. Depend on abstractions through Dependency Inversion
2. Beans need to be managed by (CDI) container
3. Inject to Fields, Methods and Constructor
4. Producer method allows programmatic bean creation and non-default constructor
5. Instance<T> provides on-demand instantiation with candidate selection
6. Use CDIUI and CDIView for making core Vaadin concepts managed beans
I would NOT start a single new Vaadin project without
Dependency Injection!
Thank you!