Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Contexts and Dependency Injection Contents 1. Overview of CDI 2. Bean scopes 3. Qualifiers 4. Producers 5. Additional techniques 2 1. Overview of CDI What is CDI? What kinds of object can be injected? Understanding the need for CDI Using CDI to inject dependencies Allowable injection points Bean names 3 What is CDI? CDI= Contexts and Dependency Injection Contexts • Dependency injection • • Enables you to bind the lifecycle and interactions of stateful components to lifecycle contexts Allows you to inject components into an application in a type-safe manner You can choose at deployment time which implementation of a particular interface to inject Note: Interfaces play a vital role in CDI • Allows different implementations to be injected easily 4 What Kinds of Object can be Injected? CDI allows you to inject the following kinds of objects: • • • • • • • Almost any Java class Java EE session beans Java EE resources Persistence contexts Producer fields, and objects returned by producer methods Web service references Remote enterprise bean references 5 Understanding the Need for CDI (1 of 2) Imagine a repository that gets records from a data store Here's an interface • Describes the repository capabilities public interface Repository { String getRecord(int id); } Repository.java Here's a simple implementation • Just returns hard-coded data - that's fine! public class SqlRepository1 implements Repository { @Override public String getRecord(int id) { return "This is record " + id; } } SqlRepository1.java 6 Understanding the Need for CDI (2 of 2) Now imagine a servlet needs a repository object • We can say that the repository is a dependency of the servlet The servlet could instantiate its dependencies itself… public class MyServlet1 extends HttpServlet { private Repository repository; @Override public void init() { repository = new SqlRepository1(); } @Override public void doGet(HttpServletRequest req, HttpServletResponse resp) { String data = repository.getRecord(42); resp.getWriter().write("Record obtained via MyServlet1: " + data); } } MyServlet1.java 7 Using CDI to Inject Dependencies (1 of 2) We can use CDI to inject a repository automatically into the servlet The first step is to annotate the dependency class with a lifecycle annotation, e.g. @RequestScoped • Tells CDI when to create / destroy the dependency object import javax.enterprise.context.RequestScoped; @RequestScoped public class SqlRepository2 implements Repository { @Override public String getRecord(int id) { return "This is record " + id; } } SqlRepository2.java 8 Using CDI to Inject Dependencies (2 of 2) Our servlet can now have its dependencies injected automatically by the CDI runtime • Annotate dependencies with @Inject import javax.inject.Inject; … public class MyServlet2 extends HttpServlet { @Inject private Repository repository; @Override public void doGet(HttpServletRequest req, HttpServletResponse resp) { String data = repository.getRecord(42); resp.getWriter().write("Record obtained via MyServlet2: " + data); } } MyServlet2.java 9 Allowable Injection Points Field @Inject private Repository repository; Constructor private Repository repository; @Inject public MyServlet2(Repository r) { repository = r; } Setter private Repository repository; @Inject public void setRepository(Repository r) { repository = r; } Initialization method private Repository repository; @Inject public void init(Repository r) { repository = r; } 10 Bean Names If you want to make a bean accessible in EL, you must annotate the bean with @Named @Named @RequestScoped public class Timestamp { public String getCurrentDate() { … } public String getCurrentTime() { … } } Timestamp.java You can then use the bean in EL in JSP and Facelets pages <html … > … <f:view> Current date: <h:outputText value="#{timestamp.currentDate}" /> <br/> Current time: <h:outputText value="#{timestamp.currentTime}" /> </f:view> … NamedBeansDemo.xhtml </html> 11 2. Bean Scopes Allowable bean scopes Understanding conversation scope Example of conversation scope 12 Allowable Bean Scopes Scope Annotation Duration Request @RequestScoped User's interaction with a web app in a single request. View @ViewScoped User's interaction with the same page in a web app (JSF 2.2). Session @SessionScoped User's interaction with a web app across multiple requests. Application @ApplicationScoped Shared state across all users' interactions with a web app. Dependent @Dependent The default scope if none is specified. It means an object exists to serve exactly one client bean and has the same lifecycle as that client bean. Conversation @ConversationScoped User's interaction with a servlet, including JSF apps. The conversation scope exists within developer-controlled boundaries that extend it across multiple requests for longrunning conversations. 13 Understanding Conversation Scope To define a CDI bean with conversation scope: • • • To start / stop conversational state: • Annotate the CDI bean class with @ConversationScoped Note, the class must implement Serializable Inject a conversation bean of type @Conversation Call the conversation bean's begin() and end() methods Example: @Named @ConversationScoped public class ConversationManager implements java.io.Serializable { @Inject private Conversation conversation; public void someStartMethod() { conversation.begin(); … } public void someEndMethod() { conversation.end(); … } … } ConversationManager.java 14 Example of Conversation Scope Run the ConversationScopeDemo.xhtml demo file 15 3. Qualifiers Defining a qualifier annotation Applying a qualifier annotation Using a qualifier in an injection 16 Defining a Qualifier Annotation You can define a qualifier annotation as a means of differentiating several bean implementations Example: import javax.inject.Qualifier; import java.lang.annotation.Retention; import java.lang.annotation.Target; import import import import import static static static static static java.lang.annotation.RetentionPolicy.RUNTIME; java.lang.annotation.ElementType.TYPE; java.lang.annotation.ElementType.METHOD; java.lang.annotation.ElementType.FIELD; java.lang.annotation.ElementType.PARAMETER; @Qualifier @Retention(RUNTIME) @Target({TYPE, METHOD, FIELD, PARAMETER}) public @interface Logging {} Logging.java 17 Applying a Qualifier Annotation You can annotate bean implementations with your qualifier annotation Example: @RequestScoped @Logging public class SqlRepository3 implements Repository { @Override public String getRecord(int id) { System.out.printf("[%s] : getRecord(%d) invoked\n", new Date(), id); return "This is record " + id; } } SqlRepository3.java 18 Using a Qualifier in an Injection You can use a qualifier annotation in an injection, to specify you want a particular type of implementation Example: public class MyServlet3 extends HttpServlet { @Inject @Logging private Repository repository; … } MyServlet3.java 19 4. Producers Defining producer fields and methods Using produced values Producing Java EE resources Disposing produced objects 20 Defining Producer Fields and Methods Producers are a way to allow non-beans to be injected • • E.g. primitives, or objects not in a bean archive E.g. objects requiring complex construction Example: @RequestScoped public class Numbers { @Produces @MaxNumber private int maxNumber = 100; private Random random = new Random(System.currentTimeMillis()); @Produces @RandomNumber public int next() { return 1 + random.nextInt(maxNumber); } } Numbers.java 21 Injecting Produced Values To inject a produced value: • If the value varies at runtime: • Use @Inject, plus the appropriate qualifier annotation Wrap produced field in Instance, and call get() to get value Example: public class MyServlet4 extends HttpServlet { @Inject @MaxNumber private int maxNumber; @Inject @RandomNumber private Instance<Integer> randomNumber; public void doGet(HttpServletRequest req, HttpServletResponse resp) resp.getWriter().write("Max: " + max + ", " + "Random number: " + rand.get()); } } { MyServlet4.java 22 Producing Java EE Resources You can use producers to allow Java EE resources to be injected • • • JMS queues, topics, connection factories Persistence contexts Etc. Example: public class SomeBean { @Produces @SomeTopic @Resource(name="topics/SomeTopic") private Topic someTopic; @Produces @SomeDatabase @PersistenceContext private EntityManager entityManager; … } 23 Disposing Produced Objects You can use producers to generate objects that need to be disposed when the context is closed • Define a method with a parameter annotated with @Disposes Example: public class SomeBean { @Produces @SomeDatabase @PersistenceContext private EntityManager entityManager; public void closeEntityManager(@Disposes @SomeDatabase EntityManager em) { em.close(); } } 24 5. Additional Techniques Predefined Java EE bean types Stereotypes Interceptors Decorators Using CDI in JSF 25 Predefined Java EE Bean Types Java EE provides predefined beans that implement the following interfaces Predefined bean Description Injection example UserTransaction Resource @Resource UserTransaction transaction; Principal Resource @Resource Principal principal; Validator Resource @Resource Validator validator; ValidatorFactory Resource @Resource ValidatorFactory factory; HttpServletRequest CDI bean @Inject HttpServletRequest request; HttpSession CDI bean @Inject HttpSession session; ServletContext CDI bean @Inject ServletContext context; 26 Stereotypes Stereotypes are used to reduce the amount of boilerplate code @Stereotype @Named @RequestScoped @Target(TYPE) @Retention(RUNTIME) public @interface RequestScopedSecureBean {} @RequestScopedSecureBean public class SomeBean { … } 27 Interceptors (1 of 4) An interceptor is a special bean that intercepts calls on other methods • • Typically implements cross-cutting code such as security, transactions, logging, etc. Allows you to put all this low-level code in a single place, and have the CDI runtime automatically call it The first step is to define an interceptor binding • A special annotation, annotated with @InterceptorBinding @InterceptorBinding @Inherited @Retention(RUNTIME) @Target({METHOD, TYPE}) public @interface Audited { } Audited.java 28 Interceptors (2 of 4) The next step is to implement the interceptor bean @Dependent @Audited @Interceptor public class AuditedInterceptor { @AroundInvoke public Object logMethodEntry(InvocationContext ic) throws Exception { Method m = ic.getMethod(); Class[] pTypes = m.getParameterTypes(); Object[] pVals = ic.getParameters(); System.out.printf("%s() called on %s\n", m.getName(), m.getDeclaringClass().getName()); for (int i = 0; i < pTypes.length; i++) { System.out.printf("%s = %s\n", pTypes[i], pVals[i]); } Object result = ic.proceed(); System.out.printf("Return value: %s\n", result); return result; } } AuditedInterceptor.java 29 Interceptors (3 of 4) You must register all interceptor beans in beans.xml <?xml version="1.0" encoding="UTF-8"?> <beans bean-discovery-mode="annotated" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"> <interceptors> <class>demos.cdi.beans.AuditedInterceptor</class> </interceptors> </beans> beans.xml 30 Interceptors (4 of 4) The last step is to designate which beans (or individual methods) are to be intercepted @RequestScoped @Audited public class SqlRepository5 implements Repository { @Override public String getRecord(int id) { return "This is record " + id; } } SqlRepository5.java 31 Decorators Decorators decorate all interfaces they implement • • @Delegate is used to inject the original object Decorators must be explicitly listed in beans.xml, in their respective order Example @Decorator public class LogDecorator implements Logger { @Inject @Delegate @Any private Logger logger; @Override public void log(String msg) { logger.log(timestamp() + ":" + msg); } } 32 Using CDI in JSF There are several issues worth exploring when using CDI in conjunction with JSF • • • • View scope Initialization vs. post-construction Accessing query string parameters Pre-destruction See the following example files: • • • demos.cdi.beans.MyViewScopedBean ViewScopeDemoPage1.xhtml ViewScopeDemoPage1.xhtml 33 Any Questions? 34