ServletModule 现在支持编程式的配置 servlets 和 filters 。这些 servlets 可以直接被注入。
GuiceServletContextListener 类可以用来帮助 Guice 在一个 servlet 容器中来初始化 Guice 应用程序。同样,我也举个例子:
public class InjectedHttpServletTest extends TestCase { private static class MyDependency {} // 假设我的MyServlet依赖于MyDependency private static class MyServlet extends InjectedHttpServlet { @Inject MyDependency myDependency; } // 创建我的MyListener static class MyListener extends GuiceServletContextListener { protected Injector getInjector() { return Guice.createInjector(); } } public void test() throws ServletException { ServletContext context = createFakeServletContext(attributes); ServletConfig config = createMock(ServletConfig.class); expect(config.getServletContext()).andReturn(context).atLeastOnce(); replay(config); GuiceServletContextListener listener = new MyListener(); listener.contextInitialized(new ServletContextEvent(context)); assertEquals(1, attributes.size()); MyServlet servlet = new MyServlet(); servlet.init(config); verify(config); assertNotNull(servlet.myDependency); listener.contextDestroyed(new ServletContextEvent(context)); assertTrue(attributes.isEmpty()); } ... }
Injector.createChildInjector 允许你创建的子 injectors 继承父类的 bindings , scopes , interceptors 和 converters 。该 API 的主要是为了扩展而准备的。看例子吧:
public void test() { Injector parent = Guice.createInjector(); //创建父Injector Injector child = parent.createChildInjector();//创建子Injector //判断是否真的继承了父Injector assertSame(child.getInstance(A.class), parent.getInstance(A.class)); Injector anotherChild = parent.createChildInjector();//创建另一个子Injector //判断是否继承的子Injector一致 assertSame(anotherChild.getInstance(A.class), parent.getInstance(A.class)); Injector grandchild = child.createChildInjector();//创建一个孙子Injector //判断是否孙子继承的Injector也一致 assertSame(grandchild.getInstance(A.class), parent.getInstance(A.class)); } ...
Even Better Error Reporting
在 Guice1.0 的时候,趋向于使用“又臭又长”的“ caused by ”来显示异常。现在我们已经好好的整理了这块。现在一个简单的异常就可以看出当错误发生时, Guice 的不俗表现了。
很像 java.lang.reflect , 该 API 允许你通过编程的方式重写一个 module ,将原来的绑定同新的绑定结合在一起。当然它还允许你查检一个已创建好的 injector ,看看里面绑定的是什么。这将会是你使用 Guice 的又一简单而又强大的扩展工具。看到这里,我马上想到了 Python 。不过,初步来看, API Doc 中貌似没有哪个类含有 Introspedtion 字眼。
Pluggable Type Converters
字符串常量绑定可以使用方便的类型转换,使之转换成任意类型(比如说转换成 dates , URLs 或者 Colours )
public void testOneConstantInjection() throws CreationException { Injector injector = Guice.createInjector(new AbstractModule() { protected void configure() { //将字符串常量“5”绑定到标注“@NumericValue”上 bindConstant().annotatedWith(NumericValue.class).to("5"); bind(Simple.class); } }); Simple simple = injector.getInstance(Simple.class); assertEquals(5, simple.i); } static class Simple { // 属性“i”使用了@NumericValue @Inject @NumericValue int i; }
OSGi-friendly AOP
Guice 是通过内部生成字节码的方式来实现 AOP 。在 Guice2.0 中,生成的 classes 通过一个桥接的 classloader 来装载,而这个 classloader 可以在一个类似于 OSGi 的托管环境。
参数化的注入点( Parameterized injection points )允许你注入像 Reducer<T> 或 Converter<A, B> 这样的类型。 Guice 会计算出 T 的实际类型,并且自动绑定上。 TypeLiteral injection 意味着你可以将一个 TypeLiteral<T> 注入到你的类中。不过要使用这个特性,还得依赖于 Java5 的泛型擦除技术。现在 TypeLiteral 类中的方法就提供了手动类型解决方案。说实话,看完下面的泛型使用,我有点头皮发麻的感觉。
public void testWildcards() throws NoSuchFieldException { TypeLiteral<Parameterized<String>> ofString = new TypeLiteral<Parameterized<String>>() {}; assertEquals(new TypeLiteral<List<String>>() {}.getType(), ofString.getFieldType(Parameterized.class.getField("t")).getType()); assertEquals(new TypeLiteral<List<? extends String>>() {}.getType(), ofString.getFieldType(Parameterized.class.getField("extendsT")).getType()); assertEquals(new TypeLiteral<List<? super String>>() {}.getType(), ofString.getFieldType(Parameterized.class.getField("superT")).getType()); } static class Parameterized<T> { public List<T> t; public List<? extends T> extendsT; public List<? super T> superT; } ...
第一部分结束..........