Techlunch - Dependency Injection with Vaadin

Post on 22-Jan-2018

549 views 4 download

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!