Reduce to the Max: Lightweight Java EE
-
Upload
open-knowledge-gmbh -
Category
Technology
-
view
284 -
download
7
description
Transcript of Reduce to the Max: Lightweight Java EE
Java
Reduce to the MaxLightway Enterprise Java
Lars Röwekamp | open knowledge GmbH
@mobileLarson@_openknowledge
„Weniger ist mehr!“
„Java EE ermöglicht - dank EE Web
Profile - extrem elegante und
l e i c h t g e w i c h t i g e E n t e r p r i s e
Anwendungen“
Was sie mitnehmen sollten ...JSF & CDI Lightway Java EE
„Weniger ist mehr!“
„Java EE ermöglicht - dank EE Web
Profile - extrem elegante und
l e i c h t g e w i c h t i g e E n t e r p r i s e
Anwendungen“
Was sie mitnehmen sollten ...JSF & CDI Lightway Java EE
Der KlassikerJSF & CDI Lightway Java EE
Der KlassikerJSF & CDI Lightway Java EE
TX
Der KlassikerJSF & CDI Lightway Java EE
Ok, wo liegt das Problem?
Heterogene Lösungen
Der KlassikerJSF & CDI Lightway Java EE
Der KlassikerJSF & CDI Lightway Java EE
eigene DI, Validierung, LifeCycle
eigene DI, Validierung, LifeCycle
eigene DI, Validierung, LifeCycle
Technology drivesBusiness
Der KlassikerJSF & CDI Lightway Java EE
TX
UC: „User“ anzeigen/ändern
Der KlassikerJSF & CDI Lightway Java EE
TX
Einen JSF ManagedBean
Controller, bitte.
Und für mich einen EJB Service.
Entity X mit ID Y,wenn möglich.
UC: „User“ anzeigen/ändern
Der KlassikerJSF & CDI Lightway Java EE
TX
Einen JSF ManagedBean
Controller, bitte.
Und für mich einen EJB Service.
Entity X mit ID Y,wenn möglich.
Hey, ich will doch nur den Current User!
Der KlassikerJSF & CDI Lightway Java EE
@ManagedBean(name=“userController“) @SessionScoped public class UserControllerMB implements Serializable {
private User user; // plus getter and setter
@ManagedProperty(value=“#{authenticationController}“) private authControllerMB AuthenticationController;
@EJB private UserService userService
@EJB private MailService mailService
... // some more services needed public String create() { .. }
public String askForDeleteConfirmation() { ... }
public String deleteAfterConfirmation() { ... }
}
Der KlassikerJSF & CDI Lightway Java EE
@ManagedBean(name=“userController“) @SessionScoped public class UserControllerMB implements Serializable {
private User user; // plus getter and setter
@ManagedProperty(value=“#{authenticationController}“) private authControllerMB AuthenticationController;
@EJB private UserService userService
@EJB private MailService mailService
... // some more services needed public String create() { .. }
public String askForDeleteConfirmation() { ... }
public String deleteAfterConfirmation() { ... }
}
Layer Solution
Der KlassikerJSF & CDI Lightway Java EE
@ManagedBean(name=“userController“) @SessionScoped public class UserControllerMB implements Serializable {
private User user; // plus getter and setter
@ManagedProperty(value=“#{authenticationController}“) private authControllerMB AuthenticationController;
@EJB private UserService userService
@EJB private MailService mailService
... // some more services needed public String create() { .. }
public String askForDeleteConfirmation() { ... }
public String deleteAfterConfirmation() { ... }
}
String basiertes IoC
Layer Solution
Der KlassikerJSF & CDI Lightway Java EE
@ManagedBean(name=“userController“) @SessionScoped public class UserControllerMB implements Serializable {
private User user; // plus getter and setter
@ManagedProperty(value=“#{authenticationController}“) private authControllerMB AuthenticationController;
@EJB private UserService userService
@EJB private MailService mailService
... // some more services needed public String create() { .. }
public String askForDeleteConfirmation() { ... }
public String deleteAfterConfirmation() { ... }
}
String basiertes IoC
Infrastrutur Injection
Layer Solution
Der KlassikerJSF & CDI Lightway Java EE
@ManagedBean(name=“userController“) @SessionScoped public class UserControllerMB implements Serializable {
private User user; // plus getter and setter
@ManagedProperty(value=“#{authenticationController}“) private authControllerMB AuthenticationController;
@EJB private UserService userService
@EJB private MailService mailService
... // some more services needed public String create() { .. }
public String askForDeleteConfirmation() { ... }
public String deleteAfterConfirmation() { ... }
}
String basiertes IoC
Infrastrutur Injection
Technology Injection
Layer Solution
Der KlassikerJSF & CDI Lightway Java EE
@ManagedBean(name=“userController“) @SessionScoped public class UserControllerMB implements Serializable {
private User user; // plus getter and setter
@ManagedProperty(value=“#{authenticationController}“) private authControllerMB AuthenticationController;
@EJB private UserService userService
@EJB private MailService mailService
... // some more services needed public String create() { .. }
public String askForDeleteConfirmation() { ... }
public String deleteAfterConfirmation() { ... }
}
String basiertes IoC
Infrastrutur Injection
String basierte Navi
Technology Injection
Layer Solution
Der KlassikerJSF & CDI Lightway Java EE
@ManagedBean(name=“userController“) @SessionScoped public class UserControllerMB implements Serializable {
...
public String create() { if (user.getUsername() == user.getPassword()) { ... // create faces messages return USERNAME_SHOULD_NOT_EQUAL_PASSSWORD; // createUser.xhtml } else if (userService.checkForFreeUsername(user.getUsername())) { userService.create(user); mailService.sendWelcomeMail(user); SystemUser loggedInUser = authenticationController.getLoggedInUser(); if (Role.ROLE_TRAINEE.equals(loggedInUser.getRole()) { trackingService.trackAction(TrackAction.USER_CREATED, user); } return “USER_CREATED“; // or userOverview.xhtml } else { ... // create faces messages return “DUPLICATE_USERNAME“; // or createUser.xhtml } } }
Der KlassikerJSF & CDI Lightway Java EE
@ManagedBean(name=“userController“) @SessionScoped public class UserControllerMB implements Serializable {
...
public String create() { if (user.getUsername() == user.getPassword()) { ... // create faces messages return USERNAME_SHOULD_NOT_EQUAL_PASSSWORD; // createUser.xhtml } else if (userService.checkForFreeUsername(user.getUsername())) { userService.create(user); mailService.sendWelcomeMail(user); SystemUser loggedInUser = authenticationController.getLoggedInUser(); if (Role.ROLE_TRAINEE.equals(loggedInUser.getRole()) { trackingService.trackAction(TrackAction.USER_CREATED, user); } return “USER_CREATED“; // or userOverview.xhtml } else { ... // create faces messages return “DUPLICATE_USERNAME“; // or createUser.xhtml } } }
Monster UseCase
Der KlassikerJSF & CDI Lightway Java EE
@ManagedBean(name=“userController“) @SessionScoped public class UserControllerMB implements Serializable {
...
public String create() { if (user.getUsername() == user.getPassword()) { ... // create faces messages return USERNAME_SHOULD_NOT_EQUAL_PASSSWORD; // createUser.xhtml } else if (userService.checkForFreeUsername(user.getUsername())) { userService.create(user); mailService.sendWelcomeMail(user); SystemUser loggedInUser = authenticationController.getLoggedInUser(); if (Role.ROLE_TRAINEE.equals(loggedInUser.getRole()) { trackingService.trackAction(TrackAction.USER_CREATED, user); } return “USER_CREATED“; // or userOverview.xhtml } else { ... // create faces messages return “DUPLICATE_USERNAME“; // or createUser.xhtml } } }
Monster UseCase
Cross Validation
Der KlassikerJSF & CDI Lightway Java EE
@ManagedBean(name=“userController“) @SessionScoped public class UserControllerMB implements Serializable{
private User user;
... public String askForDeleteConfirmation(User userToDelete) { user = userToDelete; return “USER_READY_FOR_DELETE“; // userDeleteConfirmation.xhtml }
public String deleteAfterConfirmation() { userService.delete(user); ... // do some more stuff, e.g. sending an email, tracking, ... user = null; return “USER_DELETED“; // userSuccessfulDeleted.xhtml }
}
Der KlassikerJSF & CDI Lightway Java EE
@ManagedBean(name=“userController“) @SessionScoped public class UserControllerMB implements Serializable{
private User user;
... public String askForDeleteConfirmation(User userToDelete) { user = userToDelete; return “USER_READY_FOR_DELETE“; // userDeleteConfirmation.xhtml }
public String deleteAfterConfirmation() { userService.delete(user); ... // do some more stuff, e.g. sending an email, tracking, ... user = null; return “USER_DELETED“; // userSuccessfulDeleted.xhtml }
}
Session statt „Wizard“
Scope Mismatch
Java
Java
U are here!
Java
„We want a typesafe and modern lightway
Enterprise Achritecture.“
Refactoringis needed
Der Klassiker - revistedJSF & CDI Lightway Java EE
Der Klassiker - revistedJSF & CDI Lightway Java EE
Der Klassiker - revistedJSF & CDI Lightway Java EE
Java
„Get ride of all the JSF specific Managed
Beans and Scopes.“
RefactoringStep 1
Refactoring - Step 1 JSF & CDI Lightway Java EE
@javax.faces.bean.ManagedBean(name=“userController“) @javax.faces.bean.SessionScoped public class UserControllerMB implements Serializable {
private User user; // plus getter and setter
@javax.faces.ManagedProperty(value=“#{authenticationController}“) private authControllerMB AuthenticationController;
@EJB private UserService userService
@EJB private MailService mailService
... }
Refactoring - Step 1 JSF & CDI Lightway Java EE
@javax.inject.Named(“userController“) @javax.enterprise.context.SessionScoped public class UserControllerMB implements Serializable {
private User user; // plus getter and setter
@javax.inject.Inject private authControllerMB AuthenticationController;
@EJB private UserService userService
@EJB private MailService mailService
... }
Refactoring - Step 1 JSF & CDI Lightway Java EE
@javax.inject.Named(“userController“) @javax.enterprise.context.SessionScoped public class UserControllerMB implements Serializable {
private User user; // plus getter and setter
@javax.inject.Inject private authControllerMB AuthenticationController;
@javax.inject.Inject private UserService userService
@javax.inject.Inject private MailService mailService
... }
Refactoring - Step 1 JSF & CDI Lightway Java EE
@SessionScopedclass MyBeanA
Proxy forclass MyModel
@Inject
@RequestScopedclass MyModel
Injection Target Contextual Reference Contextual Instance
businessMethod() Lookup or create
return
businessMethod()
returnreturn
Spezialfall
Java
„Use Business Injection instead of
Infrastructure Injection.“
RefactoringStep 2
Refactoring - Step 2 JSF & CDI Lightway Java EE
@Named(“userController“) @SessionScoped public class UserControllerMB implements Serializable {
@Inject private AuthControllerMB authenticationController;
@EJB private UserService userService
@EJB private MailService mailService
... }
Refactoring - Step 2 JSF & CDI Lightway Java EE
@Named(“userController“) @SessionScoped public class UserControllerMB implements Serializable {
@Inject private SystemUser loggedInUser;
@EJB private UserService userService
@EJB private MailService mailService
... }
Refactoring - Step 2 JSF & CDI Lightway Java EE
@Named(“userController“) @SessionScoped public class UserControllerMB implements Serializable {
@Inject private SystemUser loggedInUser;
@EJB private UserService userService
@EJB private MailService mailService
... }
@Current
Refactoring - Step 2 JSF & CDI Lightway Java EE
@SessionScoped public class AuthenticationController
implements Serializable {
private SystemUser authenticatedUser;
public String authenticate() { ... }
public SystemUser getAuthenticatedUser() { return authenticatedUser; }
}
Refactoring - Step 2 JSF & CDI Lightway Java EE
@SessionScoped public class AuthenticationController
implements Serializable {
private SystemUser authenticatedUser;
public String authenticate() { ... }
public SystemUser getAuthenticatedUser() { return authenticatedUser; }
}
@Produces @Current
Refactoring - Step 2 JSF & CDI Lightway Java EE
@SessionScoped public class AuthenticationController
implements Serializable {
private SystemUser authenticatedUser;
public String authenticate() { ... }
public SystemUser getAuthenticatedUser() { return authenticatedUser; }
}
@Produces @Current
@Inject @Current SystemUser
Refactoring - Step 2 JSF & CDI Lightway Java EE
@SessionScoped public class AuthenticationController
implements Serializable {
private SystemUser authenticatedUser;
public String authenticate() { ... }
public SystemUser getAuthenticatedUser() { return authenticatedUser; }
}
@Produces @Current
@Inject @Current SystemUser
@Named(“loggedInUser“)
#{loggedInUser}
Refactoring - Step 2 JSF & CDI Lightway Java EE
@SessionScoped public class AuthenticationController
implements Serializable {
private SystemUser authenticatedUser;
public String authenticate() { ... }
public SystemUser getAuthenticatedUser() { return authenticatedUser; }
}
@Produces @Current
@Inject @Current SystemUser
@Named(“loggedInUser“)
#{loggedInUser}
@RequestScoped
Refactoring - Step 2 JSF & CDI Lightway Java EE
@Qualifier@Target({FIELD, PARAMETER, METHOD, TYPE})@Retention(RUNTIME)public @interface Current { }
Refactoring - Step 2 JSF & CDI Lightway Java EE
@Qualifier@Target({FIELD, PARAMETER, METHOD, TYPE})@Retention(RUNTIME)public @interface Current { }
Self-made Qualifier
Java
„Split Monster Use Case into its
logical & modular Parts.“
RefactoringStep 3
Refactoring - Step 3 JSF & CDI Lightway Java EE
@Named(“userController“) @SessionScoped public class UserControllerMB implements Serializable {
...
public String create() { if (user.getUsername() == user.getPassword()) { ... // create faces messages return USERNAME_SHOULD_NOT_EQUAL_PASSSWORD; // createUser.xhtml } else if (userService.checkForFreeUsername(user.getUsername())) { userService.create(user); mailService.sendWelcomeMail(user); User loggedInUser = authenticationController.getLoggedInUser(); if (Role.ROLE_TRAINEE.equals(loggedInUser.getRole()) { trackingService.trackAction(TrackAction.USER_CREATED, user); } return “USER_CREATED“; // or userOverview.xhtml } else { ... // create faces messages return “DUPLICATE_USERNAME“; // or createUser.xhtml } } }
Refactoring - Step 3 JSF & CDI Lightway Java EE
@Named(“userController“) @SessionScoped public class UserControllerMB implements Serializable {
...
public String create() { if (user.getUsername() == user.getPassword()) { ... // create faces messages return USERNAME_SHOULD_NOT_EQUAL_PASSSWORD; // createUser.xhtml } else if (userService.checkForFreeUsername(user.getUsername())) { userService.create(user); mailService.sendWelcomeMail(user); User loggedInUser = authenticationController.getLoggedInUser(); if (Role.ROLE_TRAINEE.equals(loggedInUser.getRole()) { trackingService.trackAction(TrackAction.USER_CREATED, user); } return “USER_CREATED“; // or userOverview.xhtml } else { ... // create faces messages return “DUPLICATE_USERNAME“; // or createUser.xhtml } } }
JSF & CDI Lightway Java EE
@Named(“userController“) @SessionScoped public class UserController implements Serializable {
...
private User user; ... public String create() { userService.create(user); // main use case ... return “USER_CREATED“; // navigation } }
Refactoring - Step 3
JSF & CDI Lightway Java EE
@Named(“userController“) @SessionScoped public class UserController implements Serializable {
@Inject @Created Event<User> userCreatedEventSource;
private User user; ... public String create() { userService.create(user); // main use case userCreatedEventSource.fire(user); // sub use cases return “USER_CREATED“; // navigation } }
Refactoring - Step 3
JSF & CDI Lightway Java EE
@Named(“userController“) @SessionScoped public class UserController implements Serializable {
@Inject @Created Event<User> userCreatedEventSource;
private User user; ... public String create() { userService.create(user); // main use case userCreatedEventSource.fire(user); // sub use cases return “USER_CREATED“; // navigation } }
Refactoring - Step 3 Loosly coupled
via CDI Event
JSF & CDI Lightway Java EE
@ApplicationScoped public class MailService {
public void sendWelcomeMail(@Observes @Created User createdUser) {
... // do some work with createdUser }
... }
Refactoring - Step 3
Event Consumer I
JSF & CDI Lightway Java EE
@ApplicationScoped public class TrackingService {
@Inject @Current User loggedInUser;
public void trackUserCreated(@Observes @Created User newUser) { if (User.ROLE_TRAINEE.equals(loggedInUser.getRole()) { this.trackAction(TrackAction.USER_CREATED, newUser); } } ... }
Refactoring - Step 3
Event Consumer II
JSF & CDI Lightway Java EE
@ApplicationScoped public class TrackingService {
@Inject @Current User loggedInUser;
public void trackUserCreated(@Observes(during == AFTER_SUCCESS) @Created User newUser) { if (User.ROLE_TRAINEE.equals(loggedInUser.getRole()) { this.trackAction(TrackAction.USER_CREATED, newUser); } } ... }
Refactoring - Step 3
Event Consumer II
JSF & CDI Lightway Java EE
@ApplicationScoped public class GlobalCache {
public void insertIntoCache(@Observes(receice == IF_EXISTS, during == AFTER_SUCCESS) @Created User newUser) { ... // do some work } ... public void deleteFromCache(@Observes(receice == IF_EXISTS, during == AFTER_SUCCESS) @Deleted User deletedUser) { ... // do some other work }
}
Refactoring - Step 3
Event Consumer II
Java
„Validate once and only once -
not once per layer.“
RefactoringStep 4
JSF & CDI Lightway Java EE
Refactoring - Step 4
JSF & CDI Lightway Java EE
Refactoring - Step 4
JSF & CDI Lightway Java EE
Refactoring - Step 4
*many thanks to irian.at
JSF & CDI Lightway Java EE
Refactoring - Step 4
*many thanks to irian.at
JSF & CDI Lightway Java EE
Refactoring - Step 4
<html xmlns=“http://www.w3.org/1999/xhtml” ...
<h:form id=“createUserForm”> <h:outputLabel for=“firstName“ value=“Vorname:“ <h:inputText id=“firstName“ value=“#{userController.user.firstName}“> <f:validateRequired /> <f:validateLenght minimum=“8“ /> </h:inputText> ... </h:form> ...
<h:messages globalOnly=“true” /></html>
JSF & CDI
Und wo ist das Problem?
‣Cross Side Validation‣Cross Layer Validation‣Cross Component Validation
Migration GuideRefactoring - Step 4
JSF & CDI
Cross Side/Layer Validation
‣ Bean Validation 1.0 (JSR 303)‣ @nnotation basiert
‣ Validierung des Domain Models‣ JSF 2 supported‣ eigene Constraints möglich
Migration GuideRefactoring - Step 4
JSF & CDI Migration Guide
Refactoring - Step 4
public class User {
@Birthday private Date dateOfBirth; @Min(value = 0) private Integer children;
@NotNull private String firstName; @NotNull private String lastName;
...}
Validator Interface
JSF & CDI
Cross Component Validation
‣ JSF Events ermöglichen das gezielte Aufrufen einer via <f:event> Tag angegebenen Methode als direkte Reaktion auf ein Component Event
‣ JSF Events sind u.a. ‣ preValidate‣ postValidate
Migration GuideRefactoring - Step 4
JSF & CDI Lightway Java EE
Refactoring - Step 4
<html xmlns=“http://www.w3.org/1999/xhtml” ...
<h:form id=“changePassword”>
<f:event type=“postValidate” listener=“changePasswordBean.validate” /> ... </h:form> ...
<h:messages globalOnly=“true” /></html>
JSF & CDI Lightway Java EE
Refactoring - Step 4
public class ChangePasswordBean { ...
public void validate(ComonentSystemEvent event) { UIForm form = (UIForm)e.getComponent(); UIInput oldPwdInput = (UIInput)form.findComponent(“oldPwd”); String oldPwd = (String)oldPwdInput.value(); ... if (oldPwd.equals(newPwd)) { // 1. set faces error messgage // 2. render response ... } }}
Java
„Make Transactions where you want - not
where Technology.“
RefactoringStep 5
JSF & CDI Lightway Java EE
TX
Refactoring - Step 5
JSF & CDI Lightway Java EE
TX
Refactoring - Step 5
JSF & CDI Lightway Java EE
@Named(“userController“) @SessionScoped public class UserController implements Serializable {
...
public String create() { userService.create(user); // main use case userCreatedEventSource.fire(user); // Created Event return “USER_CREATED“; // Navigation } }
Refactoring - Step 5
JSF & CDI Lightway Java EE
@Named(“userController“) @SessionScoped public class UserController implements Serializable {
...
public String create() { userService.create(user); // main use case userCreatedEventSource.fire(user); // Created Event return “USER_CREATED“; // Navigation } }
Refactoring - Step 5
Transactional Use Case
JSF & CDI Lightway Java EE
@Named(“userController“) @SessionScoped public class UserController implements Serializable {
...
public String create() { userService.create(user); // main use case userCreatedEventSource.fire(user); // Created Event return “USER_CREATED“; // Navigation } }
Refactoring - Step 5
Transactional Use Case
* JTA 1.2 oder DeltaSpike oder Self-Made
@Transactional
JSF & CDI Lightway Java EE
@InterceptorBinding @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) public @interface Transactional { @NonBinding public TransactionalType value() ! default TransactionalType.REQUIRED; }
Refactoring - Step 5
JSF & CDI Lightway Java EE
@InterceptorBinding @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) public @interface Transactional { @NonBinding public TransactionalType value() ! default TransactionalType.REQUIRED; }
Refactoring - Step 5
Transactional Annotation
JSF & CDI Lightway Java EE
@Transactional @Interceptor public class TransactionInterceptor {
@Inject private UserTransaction utx;
@AroundInvoke public Object applyTransaction(InvocationContext ic) throws Throwable {
... // implement utx.begin() ic.proceed(); // call original method ... // implement utx.commit()
} }
Refactoring - Step 5
* XML Konfiguration
JSF & CDI Lightway Java EE
@Transactional @Interceptor public class TransactionInterceptor {
@Inject private UserTransaction utx;
@AroundInvoke public Object applyTransaction(InvocationContext ic) throws Throwable {
... // implement utx.begin() ic.proceed(); // call original method ... // implement utx.commit()
} }
Refactoring - Step 5
* XML Konfiguration
Transactional Interceptor
Java
„Use corresponding Scopes - not too short
and not too long“
RefactoringStep 6
Refactoring - Step 6 JSF & CDI Lightway Java EE
@Named(“userController“) @SessionScoped public class UserControllerMB implements Serializable {
private User user;
... public String askForDeleteConfirmation(User userToDelete) { user = userToDelete; return “USER_READY_FOR_DELETE“; // userDeleteConfirmation.xhtml }
public String deleteAfterConfirmation() { userService.delete(user); ... // do some more stuff, e.g. sending an email, tracking, ... user = null; return “USER_DELETED“; // userSuccessfulDeleted.xhtml }
}
Refactoring - Step 6 JSF & CDI Lightway Java EE
@RequestScopedclass MyBeanA
@ConversationSopedclass MyWizard
@Inject Conversation conv; // inside „start“ Methode conv.begin();
// inside „end“ Methode conv.end();
@RequestScopedclass MyBeanB
@Inject
@Inject
Refactoring - Step 6 JSF & CDI Lightway Java EE
@Named(“userController“) @ConversationScoped public class UserControllerMB implements Serializable {
private User user;
@Inject Conversation conversation; ... public String askForDeleteConfirmation(User userToDelete) { conversation.begin(); user = userToDelete; return “USER_READY_FOR_DELETE“; // userDeleteConfirmation.xhtml }
public String deleteAfterConfirmation() { ... }
}
Refactoring - Step 6 JSF & CDI Lightway Java EE
@Named(“userController“) @ConversationScoped public class UserControllerMB implements Serializable{
private User user;
@Inject Conversation conversation; ... public String askForDeleteConfirmation(User userToDelete) { ... }
public String deleteAfterConfirmation() { conversation.end(); userService.delete(user); ... // do some more stuff, e.g. sending an email, tracking, ... user = null; return “USER_DELETED“; // or userSuccessfulDeleted.xhtml }
}
Java
„The Spec is kind of slow when it
comes to evolution.“
The MissingPieces
EE Web Profile - Missing PiecesJSF & CDI Lightway Java EE
Bessere Conversationen
Built-in Transaktionen
weitere Scopes
typesafe Navigation
und vieles mehr ...
EE Web Profile - Missing PiecesJSF & CDI Lightway Java EE
JSF & CDI
Lightway Enterprise Java
‣mit CDI
‣ typensicher ‣ schichtenneutral‣ fachliche und technologische Injection ‣ eventgetriebene Entwicklung
FazitMigration Guide
Java
Reduce to the MaxLightway Enterprise Java
Lars Röwekamp | open knowledge GmbH
@mobileLarson@_openknowledge