candi (java injection) pattern tutorial
Four of the primary Java Injection patterns. The four main CanDI patterns share a common goal: improve code with a declarative injection style. When Java classes cleanly describe their dependencies, their lifecycles, and their exports, they are self-documenting. You can read the classes and understand how they will behave, i.e. you don't need to read the code side-by-side with XML configuration to understand the system's behavior. The custom, typesafe binding annotations are key to CanDI's self-documentation, because injection points clearly describe the resources or services they expect with adjective-oriented annotations. Because the annotations are true Java classes, they are documented in JavaDoc and verified by the compiler. The small number of meaningful adjectives means they don't impose a significant coding burden, and are well worth the small extra development time.
This tutorial describes four main CanDI design patterns: services, resources, startup and extensions. Services center an application's design by encapsulating management and data. Resources are the configurable interface between the user and the application. Startup initializes the application. And extensions allow sophisticated applications to tailor their behavior to the user's needs. Tutorial ArchitectureSince the purpose of the service pattern is encapsulating state and
managment for multiple clients, the tutorial shows a single service
used by multiple servlets and by PHP and JSP scripts. Services are
typically singletons in the application and use The resource pattern configures a driver class and properties in
XML for an application resource.
The resource tutorial uses Startup initialization is needed by most applications, and can use
the CanDI startup pattern to document the startup classes and avoid
unnecessary XML. Because CanDI discovers
beans through classpath scanning, you can create startup beans with
just a A plugin or extension capability can improve the flexibility of
many applications, even if designed for internal use. The plugin pattern
uses CanDI's discovery process for the plugin capability without
requiring a new infrastructure.
The tutorial reuses the Java Injection APIThe most important CanDI classes are just three annotations:
Applications which provide scripting access to services or
resources will use the
The startup pattern uses two additional annotations,
A plugin or extension architecture uses two
additional CanDI classes to easily find plugins discovered during
CanDI's classpath scanning.
Because services are often unique in an application, the service
interface is generally enough to uniquely identify
the service. In CanDI, the package example; import javax.inject.Inject; ... public class GetServlet extends HttpServlet { private @Inject MyService _service; ... } Users of the service will access it through an interface
like package example; public interface MyService { public void setMessage(String message); public String getMessage(); } All the information relevant to the class deployment is
on the class itself, because the service implementation is discovered
through CanDI's classpath scanning. In other words, The service's
deployment is self-documenting. Since services are generally
singletons, they will typically have the
Scripting beans use the package example; import javax.inject.Singleton; import javax.inject.Named; import javax.enterprise.inject.Default; @Singleton @Named("myService") @Default public class MyServiceBean implements MyService { private String _message = "default"; public void setMessage(String message) { _message = message; } public String getMessage() { return _message; } } Using Services from PHP and JSPCanDI is designed to integrate closely with scripting languages
like PHP and JSP. The scripting languages locate a CanDI service or
resource using a string, because scripting lacks the strong typing
needed for full dependency injection. As mentioned above, the name of
a CanDI service is declared by the <?php $myService = java_bean("myService"); echo $myService->getMessage(); ?> While PHP has a function access to the CanDI service or resource,
JSP and JSF grab the CanDI bean with using the JSP expression
language. Any CanDI bean with a message: ${myService.message} Resources like databases, and queues fit multiple roles in an
application and need configuration and description
beyond their generic CanDI encourages a small number of binding
annotations used as adjectives to describe resources. A typical
medium application like a mail list manager might use half a dozen
custom binding adjectives, and may need fewer or more depending on
the number of unique resources. Each database, queue,
mail, and JPA EntityManager will generally have a unique name. If
users need customization and configuration of internal resources, you
may need additional binding types. If the application has a
single database, it might only have one binding annotation, or might even
use The purpose of the binding annotation is to self-document the
resource in the client code. If the application uses
The tutorial has public class SetServlet extends HttpServlet { private @Red MyResource _red; private @Blue MyResource _blue; ... } The XML is short and meaningful, because it's only required for
customization, not for wiring and binding. Databases and JMS queues will
need to configure the database driver and add the binding
adjective. Applications resources can also be configured in XML if
exposing the configuration is useful to your users, but unique
internal classes like most services will stay out of the XML.
In our example, we let the users configure the The XML configuration for a bean needs three pieces of data: the
driver class, the descriptive binding annotation, and any customization data.
Because the driver is the most important, CanDI uses the class as the
XML tag and uses the package as the XML namespace.
While scanning the XML, the driver class is top and prominent,
reflecting its importance. In the
example, <example:BlueResourceBean xmlns:example="urn:java:example"> ... </example:BlueResourceBean> In CanDI, the binding annotation is also an XML tag, represented by its classname and package. In CanDI, classes and annotations get XML tags with camel-case names matching the classname, and XML for properties are lower case. The case distinguishes annotations from properties in the XML, improving XML readability. <example:Blue xmlns:example="urn:java:example"/> Properties of a resource use the standard beans-style names, so
<web-app xmlns="http://caucho.com/ns/resin" xmlns:example="urn:java:example"> <example:BlueResourceBean> <example:Blue/> <example:data>blue resource</example:data> </example:BlueResourceBean> <example:RedResourceBean> <example:Red/> <example:data>red resource</example:data> </example:RedResourceBean> </web-app> Binding types should generally be descriptive adjectives, so it can
describe the injection clearly. Anyone reading code should
understand immediately which resource it's using. The tutorial's
package example; import static java.lang.annotation.ElementType.*; import static java.lang.annotation.RetentionPolicy.*; import java.lang.annotation.*; import javax.inject.Qualifier; @Qualifier @Documented @Target({TYPE, METHOD, FIELD, PARAMETER}) @Retention(RUNTIME) public @interface Blue { } The resource implementation itself is straightforward. When the
resource is a singleton, it will need a
package example; public class BlueResourceBean { private String _data; public void setData(String data) { _data = data; } } The package example; import javax.annotation.PostConstruct; import javax.ejb.Startup; import javax.inject.Inject; @Startup public class MyStartupBean { private @Inject MyService _service; @PostConstruct public void init() { _service.setMessage(this + ": initial value"); } } A plugin or extension architecture can make an application more
flexible and configurable. For example, a filtering system, or
blueprints or custom actions can add significant power to an
application. The plugin pattern uses CanDI's discovery system
to find all implementations of the plugin interface. The The CanDI The package example; import javax.inject.Inject; import javax.enterprise.inject.Any; import javax.enterprise.inject.Instance; ... public class GetServlet extends HttpServlet { @Inject @Any Instance<MyResource> _resources; public void service(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { PrintWriter out = response.getWriter(); for (MyResource resource : _resources) { out.println("resource: " + resource); } } }
|