![]() | Resin Documentationapp server |
resin ioc
Resin is designed around an internal inversion-of-control framework used for all configuration and resources including servlets, EJBs, messaging, remoting, and databases. Applications can take advantage of Resin's IoC capabilities using WebBeans-standard annotations and interfaces. Since Resin-IoC is used for servlets, WebBeans and EJBs, any application bean can use EJB annotations like @TransactionAttribute or WebBeans @InterceptionTypes or event @Observes capabilities, in addition to the dependency injection and IoC configuration. The dependency injection framework is type-safe, meaning the registry is organized around Java types, not a flat namespace, which gives more power and flexibility for component assembly. Since injection is annotation-based, most components can avoid XML configuration, while XML is still available for components.
Resin's IoC support is integrated with EJB 3.0
and the core components like Servlets, Filters and remote objects.
This integration means plain Java beans can use EJB annotations
and interception, EJBs can use Resin IoC annotations, and both kinds of
beans can be configured directly from the So it's best to think of Resin-IoC as a set of orthogonal capabilities that are available to any registered bean. The basic capability types are:
Before dependency injection, applications needed to use JNDI to
grab resources managed by Resin: database connections, JMS queues, JCA
With dependency injection, Resin will lookup, verify and inject
the resource when it creates your managed class, for example when creating
a servlet. In the following example, when Resin creates MyServlet, the Example: DataSource and UserTransaction import javax.sql.DataSource; import javax.transaction.UserTransaction; import javax.webbeans.In; public class MyServlet extends GenericServlet { @In private DataSource _ds; @In private UserTransaction _ut; ... } @Named and bindingsSince many applications use multiple resources like named databases,
your injection may need to specify a name or other binding to uniquely
identify the resource you want. In the case of a unique resource like
Example: @Named with DataSource import javax.sql.DataSource; import javax.webbeans.Named; public class MyServlet extends GenericServlet { @Named("foo") private DataSource _ds; ... } Example: resin-web.xml database configuration <web-app xmlns="http://caucho.com/ns/resin"> <database> <name>foo</name> <driver type="org.gjt.mm.mysql.Driver"> <url>jdbc:mysql://localhost:3306/foo</url> </driver> </database> <database> <name>bar</name> <driver type="org.gjt.mm.mysql.Driver"> <url>jdbc:mysql://localhost:3306/bar</url> </driver> </database> </web-app> Injection using a Although many applications will just use field, method, and constructor injectionSince Resin implements all three flavors of dependency injection: field, method and constructor, the choice of style is up to you. You can mark any field with Example: field injection with @Named import javax.webbeans.Named; public class MyBean { @Named DataSource _ds; ... } Method injection can use any binding annotation on any of the parameters.
When Resin introspects the component class and it finds
any Example: method injection with @Named import javax.webbeans.Named; public class MyBean { void foo(@Named("jdbc/foo") DataSource myDataSource) { ... } ... } Construction injection is available for components and singleton beans.
Like method injection, the If the bean has multiple constructors, exactly one must be marked
Example: constructor injection import javax.webbeans.In; public class MyBean { @In public MyBean(DataSource myDataSource) { ... } ... } WebBeans-enabled components (injectable objects)Any Resin-managed object can use the entire WebBeans
dependency-injection system and all of the managed objects, while objects
you create using
Resin global resourcesResin automatically provides several global resources to any
injectable code. Since these resources are unique, your application
will use
Resin configured resourcesAll Resin configured resources are available through WebBeans, since Resin uses WebBeans as its internal registry.
EJB stateless beans are automatically registered the
WebBeans. The default EJB stateful beans are automatically registered with
WebBeans. The default EntityManager and EntityManagerFactory objects
from JPA are automatically registered with WebBeans. The default
<env-entry> tags register their values with
WebBeans. The default <jms-connection-factory> automatically registers the configured
factory with WebBeans.
Connection factories can also be configured with <bean> or <resource>,
depending on the JMS provider. The registered type is the <jms-topic> automatically registers the configured
topic with WebBeans. The default <jms-queue> automatically registers the configured
queue with WebBeans. The default <remote-client> registers remoting clients with WebBeans.
The <remote-client> tag will configure the protocol used and the
expected proxy class. The registered type is the API Example: resin-web.xml for remote-client <web-app xmlns="http://caucho.com/ns/resin"> <remote-client class="example.HelloService"> <url>hessian:http://localhost:8080/hello/</url> </remote-client> </web-app> Example: Injecting for remote-client public class MyServlet extends GenericServlet { @In example.HelloService _hello; ... } The primary value of Resin's dependency injection system is as a type-safe component and service organization registry. Module and component-oriented software has been a goal of software developers for decades, but in practice developing components and services is a difficult task, in large part because the configuration and assembly of the components has been just as complicated as the code itself. There are no silver bullets in software, but the WebBeans registry does significatly reduce the housekeeping code and XML which gets in the way of good design. Annotation-based Component DiscoveryAt startup, Resin will scan jars and class directories for a
Example: META-INF/web-beans.xml <web-beans xmlns="http://caucho.com/ns/resin"> </web-beans> The component itself can be any Java class. Since Resin manages the
component, it can use Example: Movie.java import javax.annotation.PostConstruct; import javax.webbeans.Component; @Component public class Movie { private String _title; private String _director; public String getTitle() { return _title; } public void setTitle(String title) { _title = _title; } public String getDirector() { return _director; } public void setDirector(String director) { _director = director; } @PostConstruct public void init() { ... } } The Any other component or Resin-managed class like servlets can now
use Example: MyServlet.java import javax.webbeans.In; public class MyServlet extends GenericServlet { @In Movie _movie; ... } Most application components will use the Scopes: @Singleton, @Dependent, @RequestScopedThe scope of the component determines when Resin will create a new component and when it will reuse an old one. Singletons will always return the same object, while dependent components will always return a new object instance. Long-lived services will typically be singletons, while scratch-space modules will be dependent components. Components default to You can specify a component's scope with an annotation or in
the
An example scoped resource might be a Example: @RequestScoped Calculator import javax.webbeans.RequestScoped; import javax.webbeans.Component; @RequestScoped @Component public class Calculator { private int _a; private int _b; public void setA(int a) { _a = a; } public void setB(int b) { _b = b; } public int getSum() { return _a + _b; } } You could also register the same calculator using XML: Example: resin-web.xml Calculator <web-app xmlns="http://caucho.com/ns/resin"> <component class="example.Calculator" scope="request"/> </web-app> @New Component DiscoveryThe Example: MyServlet.java import javax.webbeans.New; public class MyServlet extends GenericServlet { @New Movie _movie; ... } The Example: Movie.java public class Movie { private String _title; public String getTitle() { return _title; } public void setTitle(String title) { _title = title; } @PostConstruct public void init() { ... } } Lifecycle: @PostConstruct and @PreDestroyIf your service needs to initialize itself after being configured, it
can annotation an initialization method with At the end of a component's lifetime, you might need to close some
resources, e.g. closing a socket or delisting from a timer service. Resin
will call any component method marked with For example, a Example: Timer Service import javax.annotation.PostConstruct; import javax.webbeans.In; import javax.webbeans.Component; import java.util.concurrent.ScheduledExecutorService; import com.caucho.webbeans.Singleton; @Component @Singleton public class TimerService { @In ScheduledExecutorService _timer; @PostConstruct public void init() { _timerFuture = _timer.scheduleAtFixedRate(this, 0, 2, TimeUnit.SECONDS); } ... @PreDestroy public void close() { _timerFuture.cancel(false); } } You can register your components and services with Resin using the resin.conf or resin-web.xml files. Since the WebBeans registry is integrated with Resin, your services be treated as first-class components along with the Resin resources. Although most components will not need XML, there are a few advantages for the small number of services which do use XML. The XML-configuration lets you customize your application for a
particular environment, e.g. setting configuration parameters. For example,
Resin's In addition, the XML-configuration documents the services you've enabled. For heavyweight services, this documentation is critical, while lightweight components do not need this extra housekeeping overhead. bean and component registrationThe Example: bean and component resin-web.xml <web-app xmlns="http://caucho.com/ns/resin"> <bean class="example.MyService"/> <component class="example.MyService"/> </web-app> The
Bean property configurationResin's XML configuration uses the standard JavaBeans patterns to configure properties. Resin uses the same mechanism for all of its own configuration parsing, including every JavaEE configuration file, the resin-web.xml and the resin.conf itself. So your application will have all the configuration flexibility it needs. Since the component beans can use WebBeans
injections, injected components are typically not configured in
the resin-web.conf, avoiding the need for tags like Example: Hello.java public class Hello { private String _greeting = "default"; public void setGreeting(String greeting) { _greeting = greeting; } public String getGreeting() { return _greeting; } } The basic example sets a Example: resin-web.xml configuring a singleton <web-app xmlns="http://caucho.com/ns/resin"> <bean class="example.Hello"> <init> <greeting>Hello, World</greeting> </init> </bean> </web-app> Resin's configuration uses 5 basic bean patterns, extending the JavaBeans
conventions. It can configure literal values like string and integers as
well as configuring other beans. Any component bean configured by Resin
has full access to (Currently the patterns are name-based like JavaBeans, since Resin was designed before annotations. We may add configuration annotations in the future. Example: Bean configuration patterns public void setFoo(String data); public void setFoo(Movie data); public void addFoo(Movie data); public Movie createFoo(); public void setText(String data);
As mentioned above, Resin uses these 5 patterns to handle all of the
JavaEE configuration files. In particular, the Example: sub-bean configuration example <web-app xmlns="http://caucho.com/ns/resin"> <bean class="example.Theater"> <init> <name>Balboa</name> <movie title="The Princess Bride"/> <movie title="The Maltese Falcon"/> </init> </bean> </web-app> In this example, the Example: Theater.java public class Theater { String _name; ArrayList<Movie> _movies = new ArrayList<Movie>(); public void setName(String name) { _name = name; } public Movie createMovie() { return new Movie(this); } public void addMovie(Movie movie) { _movies.add(movie); } public static class Movie { private Theater _theater; private String _title; Movie(Theater theater) { _theater = theater; } public void setTitle(String title) { _title = title; } } } Base configuration: string conversionsResin-IoC provides a number of built-in string conversion types as well
as supporting JavaBeans
String constructorResin-IoC will automatically convert a string to an object if the object has a single String argument constructor. Example: MyBean with constructor public class MyBean { public MyBean(String value) { ... } } valueOfFor classes which implement a static Example: MyBean with valueOf public class MyBean { ... public static MyBean valueOf(String text) { MyBean bean = new MyBean(); bean.setTextValue(text); bean.init(); return bean; } } Compound typeslistSetters taking a List items are specified directly with <value> elements. There is no extra <list> element required. The <list> element is only used when creating a sub-list or sub-element (see below.) Example: MyBean.setValues(List) <my-bean> <values> <value>a</value> <value>b</value> <value>c</value> </values> </my-bean> Example: MyBean.setValues(String []) <my-bean> <values> <value>a</value> <value>b</value> <value>c</value> </values> </my-bean> In the following example, the argument is an object, so we need
a <list> element to tell Resin to create a list. The object
created will be an Example: MyBean.setValues(Object) <my-bean> <values> <list> <value>a</value> <value>b</value> <value>c</value> </list> </values> </my-bean> Resin-IoC can always use the Example: MyBean.addValue(String) <my-bean> <value>a</value> <value>b</value> <value>c</value> </my-bean> References and EL ExpressionsResin-IoC configuration files can use EL expressions to get references to resources, beans, system properties, and calculate generatal expressions based on those values. Since all Resin's resources are added to the WebBeans registry automatically, application components have access to anything they need. Both the JSP immediate syntax and deferred syntax are supported (${...} vs #{...}). Currently, there is no distinction between the two, but the deferred syntax is preferred, since Resin-IoC initializes beans lazily to handle circular references. Example: circular references in resin-web.xml <web-app xmlns="http://caucho.com/ns/resin"> <bean name="a" class="qa.FooBean"> <init bar="#{b}"/> </bean> <bean name="b" class="qa.BarBean"> <init foo="#{a}"/> </bean> </web-app> Because Resin's EL implementation allows method expressions, you can use beans as factories in the EL expressions. If your application is using a scripting language like PHP for the presentation layer, the WebBeans registry provides a simple interface to use your components and services. Although WebBeans injection is typed, each WebBean is also registered under its name for scripting applications. The name must be globally unique, of course, unlike the typed injection binding. The default scripting name is the name of the component's class, with
the first character lowercased. You can change the name by adding
a Example: Movie.java @Component @RequestScoped public class Movie { ... } Quercus/PHPIn Quercus/PHP, the Example: accessing the movie from PHP <?php $movie = java_bean("movie"); echo "title: " . $movie->title . "\n"; ?> JSP/JSF ELResin automatically provides the WebBeans variables to EL expressions for both JSP and JSF. Example: accessing the movie from JSP <c:out value="${movie.title}"/> The JSF also uses the expression language, but uses the deferred syntax, since JSF needs to build a component tree first. Example: accessing the movie from JSF <f:view> <h:outputText value="#{movie.title}"/> </f:view> Although many applications will just use Example: ReadOnly and XA databases import com.foo.webbeans.ReadOnly; import com.foo.webbeans.XA; public class MyServlet extends GenericServlet { @ReadOnly DataSource _readDatabase; @XA DataSource _xaDatabase; ... } You can create a custom binding annotation using
the The annotation can also have annotation parameters. If they exist, Resin will make sure only matching components will be injected. The custom binding annotation can be used anywhere predefined binding annotations can, including fields, methods, constructor, producers, or event observers. Example: ReadOnly.java package com.foo.webbeans; @BindingType @Target({TYPE, METHOD, FIELD, PARAMETER}) @Retention(RUNTIME) public @interface ReadOnly { } Some components are more easily produced using a factory method rather
than getting instantiated directly. In those cases, your application
can mark a factory component's method with the Example: @Produces import javax.webbeans.Component; import javax.webbeans.Produces; import com.caucho.webbeans.Singleton; @Component @Singleton public class MyFactory { @Produces public List<Movie> currentMovies() { ... } The produces method can be marked with Some functions like security, logging and transaction handing need to be used for each method invidually, but require a common implementation pattern. The WebBeans AOP uses a single method as a interceptor for each method invocation. Your method will use an Example: secure method import com.foo.webbeans.Secure; @Component public class MyBean { @Secure public void doSomethingSafely() { ... } } The implementation class will use the
Example: security implementation import javax.interceptor.*; import javax.webbeans.Interceptor; @Secure @Interceptor public class MySecureInterceptor { @AroundInvoke public Object checkSecurity(InvocationContext inv) throws Exception { if (! myContextIsSecure()) throw new MySecurityException("permissiong denied"); return inv.proceed(); } } The interceptors must be enabled in the
Example: META-INF/web-beans.xml <web-beans xmlns="http://caucho.com/ns/resin"> <interceptors> <interceptor>com.foo.MySecureInterceptor</interceptor> </interceptors> </web-beans> Your components can also handle events thrown through the WebBeans API.
Any method with an Example: event handler import javax.webbeans.Component; import javax.webbeans.Observes; @Component public class MyHandler { public void myHandlerMethod(@Observes Movie movie) { ... } } Your application can throw events through the WebBeans
Example: raising events import javax.webbeans.Container; public void MyServlet extends GenericServlet { @In Container _webbeans; public void service(ServletRequest req, ServletResponse res) { _webbeans.raiseEvent(new Movie("A Bridge Too Far")); } } For the above example, Resin will look for all components which
have an @AroundInvoke
javax.interceptor.AroundInvoke @Target(METHOD) @Retention(RUNTIME) public @interface AroundInvoke { } Example: @AroundInvoke method import javax.interceptor.*; public class MyBean { @AroundInvoke protected Object log(InvocationContext cxt) throws Exception { System.out.println("Before: " + cxt.getMethod()); Object value = cxt.proceed(); System.out.println("After: " + cxt.getMethod()); return value; } public String hello() { return "hello, world"; } } @DenyAll
javax.annotation.security.DenyAll @Target({METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface DenyAll { } @Interceptor
javax.webbeans.Interceptor @Target({TYPE}) @Retention(RUNTIME) public @interface Interceptor { } @InterceptorBindingType
javax.webbeans.InterceptorBindingType @Target({TYPE}) @Retention(RUNTIME) public @interface InterceptorBindingType { } @Interceptors
javax.interceptor.Interceptors @Target({TYPE,METHOD}) @Retention(RUNTIME) public @interface Interceptors { public Class []value(); } Example: @Interceptor method import javax.interceptor.*; public class MyBean { @Interceptors(MyInterceptor.class) public String hello() { return "hello, world"; } } public class MyInterceptor { @AroundInvoke protected Object log(InvocationContext cxt) throws Exception { System.out.println("Before: " + cxt.getMethod()); Object value = cxt.proceed(); System.out.println("After: " + cxt.getMethod()); return value; } } InvocationContextThe
javax.interceptor.InvocationContext public interface InvocationContext { public Object proceed() throws Exception; public Map<String, Object> getContextData(); public Method getMethod(); public Object[] getParameters() throws IllegalStateException; public void setParameters(Object[] parameters) throws IllegalStateException; public Object getTarget(); } @PermitAll
javax.annotation.security.PermitAll @Target({METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface PermitAll { } @RolesAllowed
javax.annotation.security.RolesAllowed @Target({TYPE,METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface RolesAllowed { String []value(); } @RunAs
javax.annotation.security.RunAs @Target({TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface RunAs { String value(); } @TransactionAttributeDefines the transaction boundary for business methods. The default value is REQUIRED. If @TransactionAttribute annotates the class, it defines the default value. All Resin-managed beans can use
javax.ejb.TransactionAttribute @Target({TYPE,METHOD}) @Retention(RUNTIME) public @interface TransactionAttribute { TransactionAttributeType value() default REQUIRED; } @BindingType
javax.webbeans.BindingType @Target({TYPE}) @Retention(RUNTIME) public @interface BindingType { } Example: custom @XA binding type package demo; @BindingType @Target({TYPE, METHOD, FIELD, PARAMETER}) @Retention(RUNTIME) public @interface XA { } Example: using the custom @XA binding type package demo; import javax.sql.*; public class MyBean { @XA DataSource _xa; @NonXA DataSource _nonXa; ... } @EJBConfigures EJB values for a field or method. @EJB is essentially a @Resource where it's known that the result is an EJB interface.
javax.ejb.EJB @Target({TYPE, METHOD, FIELD, PARAMETER}) @Retention(RUNTIME) public @interface EJB { String name() default ""; String businessInterface() default ""; String jndiName() default ""; } In the following exaple, Resin will call Example: @EJB method injection @EJB void setFoo(example.Test test) { _test = test; } @InMarks a field, method, or parameter for injection. When used with a constructor, it marks the given constructor as the constructor to use when creating new instances. javax.webbeans.In @Target({CONSTRUCTOR, METHOD, FIELD, PARAMETER, TYPE}) @Retention(RUNTIME) public @interface In { } @Named
javax.webbeans.Named @BindingType @Target({METHOD, FIELD, PARAMETER, TYPE}) @Retention(RUNTIME) public @interface Named { String value(); } @NewMarks a field, method, or parameter for injection with a new
instance of the object. If the type of the javax.webbeans.New @Target({METHOD, FIELD, PARAMETER, TYPE}) @Retention(RUNTIME) public @interface New { } @NonBinding
javax.webbeans.NonBinding @Target({FIELD, METHOD}) @Retention(RUNTIME) public @interface NonBinding { } Example: @Demo with @NonBinding package demo; @BindingType @Target({TYPE, METHOD, FIELD, PARAMETER}) @Retention(RUNTIME) public @interface Demo { @NonBinding String description() default ""; } @Resource
In general, it's better to use the WebBeans
annotations:
Frameworks like Struts2, Wicket, and Mule can delegate object creation to Resin-IoC. By configuration Resin-IoC to create the framework objects, your application's components can directly inject Resin resources and application components configured with Resin. Integration information for the frameworks is maintained on the Caucho wiki site. Currently supported frameworks include:
Implementing new object factories for other frameworks is straightforward. ObjectFactory patternFrameworks like Struts2 provide an Example: Struts2 integration package com.caucho.xwork2; import com.caucho.webbeans.manager.*; import com.opensymphony.xwork2.ObjectFactory; import java.util.*; import javax.webbeans.*; public class ResinObjectFactory extends ObjectFactory { private final WebBeansContainer _webBeans = WebBeansContainer.create(); @Override public Object buildBean(Class clazz, Map extraContext) throws Exception { return _webBeans.getObject(clazz); } } Injection patternSome frameworks, like Wicket, prefer to instantiate the object, but can call Resin-IoC for a dependency-injection step. With this kind of framework integration, the created object only gets dependency-injection; it does not get any aspects or interception. Example: Wicket injection package com.caucho.wicket; import com.caucho.webbeans.manager.*; import org.apache.wicket.Component; import org.apache.wicket.application.*; public class ResinComponentInjector implements IComponentInstantiationListener { private WebBeansContainer _webBeans = WebBeansContainer.create(); public void onInstantiation(Component component) { _webBeans.injectObject(component); } }
|