大多数Java开发人员是因为DI与AOP的需要而使用Spring的.但Spring通常有冗长的XML配置.普通的JDK可以使用动态代理来处理AOP,这篇文章演示了使用JavaScript来处理依赖注入.
从Java 6起,Java应用程序可以在其JVM实例内调用脚本语言,并使用脚本API无缝地与脚本进行通信. Sun公司的JRE附带一个内置的引擎,通过这个API处理Javasript.我们可以利用Javascript的强大表现力在JVM之上执行一些很酷的东西.
我们要创建什么?
1.两个DAO接口和它们的模拟实现.
2.使用这些DAO的一个service示例.
3.JS脚本将它们连接到一起.
4.一个对service方法调用进行记录的简单拦截器.
DAO接口与实现:
package dao; public interface BooksDAO { public int count(); } package dao; public interface MembersDAO { public int count(); } package dao; public class MockBooksDAO implements BooksDAO { @Override public int count() { return 500; } } package dao; public class MockMembersDAO implements MembersDAO { @Override public int count() { return 100; } }
Service接口与实现:
package service; public interface LibraryService { public abstract int countBooks(); public abstract int countMembers(); } package service; import dao.BooksDAO; import dao.MembersDAO; public class MockLibraryService implements LibraryService { private BooksDAO booksDAO; private MembersDAO membersDAO; public MockLibraryService(BooksDAO booksDAO, MembersDAO membersDAO) { this.booksDAO = booksDAO; this.membersDAO = membersDAO; } public int countBooks() { System.out.println("In countBooks()"); return booksDAO.count(); } public int countMembers() { System.out.println("In countMembers()"); return membersDAO.count(); } }
依赖注入脚本:
我们利用JavaScript的Object直接量定义并组织DAOs与services.我们可以从应用程序中查找到这些以获得具体的实现.
src/objects.js
importPackage(Packages.dao) importPackage(Packages.service) importPackage(Packages.interceptor) daos = { booksDAO : new MockBooksDAO(), membersDAO : new MockMembersDAO() } services = { libraryService : LoggingInterceptor.getProxy(new MockLibraryService(daos.booksDAO, daos.membersDAO)) }
应用程序代码:
我们使用ScriptEngineBuilder对Javacript求值,并从中获取service示例.
package app; import javax.script.ScriptEngine; import javax.script.ScriptException; import service.LibraryService; import util.ScriptEngineBuilder; public class Main { public static void main(String[] args) throws ScriptException { ScriptEngine engine = new ScriptEngineBuilder("js").add("/objects.js").build(); LibraryService service = (LibraryService) engine.eval("services.libraryService"); System.out.println("Found " + service.countMembers() + " Members!"); System.out.println("Found " + service.countBooks() + " Members!"); } }
添加AOP到组合中
创建JDK动态代理来记录所有方法调用
package interceptor; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class LoggingInterceptor implements InvocationHandler { private Object target; public static Object getProxy(Object target) { ClassLoader loader = LoggingInterceptor.class.getClassLoader(); Class[] interfaces = target.getClass().getInterfaces(); InvocationHandler handler = new LoggingInterceptor(target); return Proxy.newProxyInstance(loader, interfaces, handler); } private LoggingInterceptor(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { System.out.println("Entered Method: " + method.getName()); Object val = method.invoke(target, args); System.out.println("Completed Method: " + method.getName()); return val; } catch (Exception e) { System.out.println("Exception in Method: " + method.getName()); throw e; } } }
现在,我们可以修改依赖注入脚本,利用代理改变service的创建方式
libraryService : LoggingInterceptor.getProxy(new MockLibraryService(daos.booksDAO, daos.membersDAO))
到此,我们有了一个非常好的干净的包含AOP的依赖注入配置方案,且不需要任何Java SE之外的东西.这里要记住的一个重点是,与使用注解不同,我们仍须在应用程序代码之外维护DI和AOP的配置.Spring会需要一卡车的XML来达到同样的目的.
原文:http://blog.tuxychandru.com/2009/08/using-javascript-as-di-container-in.html