这篇是承接《轻量级 Java 开发框架 设计》系列Blog文的后续文章,本文将介绍 Hasor 内部主要插件并附带插件的功能描述和简单使用 Demo。
Hasor 使用的是“微内核 + 插件扩展”这种设计思想。截止到目前为止 Hasor-Core、Hasor-Web、Hasor-JDBC 中一同提供了 14 个功能插件。本文收集并整理了 Hasor-Core、Hasor-Web 两个部分中 11个插件的功能说明以及基本 Demo。
这 14 个功能模块分别在开发的各个方面给予开发人员各种便捷。假如你不想要其中的某个模块可以将其禁用掉。这比起 Spring 而言不管有用没用都引一大堆功能而言要更加贴切,如果你不喜欢这些功能模块大可以放弃它们仅仅启动 Hasor 的内核。这样你会得到更轻量的框架,因为 Hasor 的核心实现仅有不到 50 个类文件。
这里是一个基于 Hasor 的 WebDemo 工程,工程中还实现了一个 Hessian 插件。地址:http://git.oschina.net/zycgit/hasor/tree/master/examples/SimpleWeb
@Before(AopInterceptor_2.class)//类级别拦截器 public class TestBean { @Before(AopInterceptor_1.class)//方法级别拦截器 public String println(String msg) { //受到方法级、类级拦截器影响的方法 return "println->" + msg; } public String foo(String msg) { //只受到类级拦截影响的方法 return "foo->" + msg; } }
该插件会将所有标记了 @Bean 的类通过“ApiBinder.defineBean(...)”
代码将其注册到 Hasor 容器中。注册之后可以通过“AppContext.getBean”
获取Bean对象。用过 Spring 的话一定不会陌生。例子:
@Bean(value = { "name1", "name2" }) public class NamesBean { public void foo() { System.out.println("this bean is name1 or name2 type:" + this); } }
该插件本身并不提供缓存功能,但是为使用缓存提供了统一的接口。缓存功能
的提供需要实现 CacheCreator 接口并通过标记 @Creator 注解以生效。
使用缓存可以通过在需要缓存的方法上通过标记 @NeedCache 注解以启用结果缓存。例子:
@NeedCache public MenuBean findMenuByCode(String code) { return ...; }
@Creator public class MapCacheCreator implements CacheCreator { private Map<String, Cache> cacheMap = new HashMap<String, Cache>(); public Cache getCacheByName(AppContext appContext, String groupName) { Cache cache = cacheMap.get(groupName); if (cache != null) return cache; cache = new MapCache(); cacheMap.put(groupName, cache); return cache; } } public class MapCache extends HashMap<Serializable, Object> implements Cache { public boolean toCache(Serializable key, Object value) { this.put(key, value); return true; } public Object fromCache(Serializable key) { return this.get(key); } public boolean hasCache(Serializable key) { return this.containsKey(key); } public boolean remove(Serializable key) { super.remove(key); return true; } public boolean clearCache() { super.clear(); return true; } public int size() { return super.size(); } public Set<Serializable> keys() { return super.keySet(); } public void close() { super.clear(); } }
AppContext appContext = ...; /*发送异步事件*/ appContext.getEventManager().doAsyn("EventName", ...);
AppContext appContext = ...; /*发送同步事件*/ appContext.getEventManager().doSync("EventName", ...);
@Listener("EventName") public class Type_B_EventListener implements EventListener { public void onEvent(String event, Object[] params) { System.out.println("Type_B onEvent :" + event + " \t" + Hasor.logString(params)); Thread.sleep(1000); } };
通过 @GuiceModule 注解可以将任意一个基于 Guice 开发的“com.google.inject.Module”
模块加入到 Hasor 中作为 Hasor 的一个模块。例子:
@GuiceModule public class GuiceMod implements Module { public void configure(Binder binder) { System.out.println("Hello guice"); } }
(未整理...)
通过 @Controller 注解提供了 WebMVC 开发所需的支持。该插件还提供了请求响应拦截器功能。
所有控制器都必须要求继承自 AbstractController 抽象类,如果某个方法不像被发布成 action,
可以通过@ControllerIgnore 注解或者配置“hasor-web.controller.globalIgnore”隐藏它们。例子:
@Controller("/mgr/user") public class UserAction extends AbstractController { @Inject private UserService userService; /*获取用户列表,转发到‘/mgr/user/userList.jsp’*/ @Forword public String userList() { List<UserBean> userList = userService.getUserList(); this.setAttr("userList", userList); return "/mgr/user/userList_mvc1.jsp"; } }
请求地址为:http://127.0.0.1:8080/mgr/user/userList.do
通过 @RestfulService 注解发布 Restful 服务的支持,Hasor 的 restful 参考了 JSR-311。
@Any、@AttributeParam、@CookieParam、@Get、@Head、@HeaderParam、@HttpMethod、@Options、@Path、@PathParam、@Post、@Produces、@Put、@QueryParam 这些注解是由这个插件提供的。例子:
@RestfulService public class MenusRestFul { @Inject private MenuServices menuServices; /*使用重定向转发*/ @Redirect /*映射 restful 服务地址,并定义一个参数*/ @Path("/mgr/menus/nav/{menuCode}") /*取得并参数,并跳转到对应的页面*/ public String menuList(@PathParam("menuCode") String menuCode) { MenuBean menuBean = menuServices.findMenuByCode(menuCode); return (menuBean == null) ? "/mgr" : menuBean.getUrl(); } }
请求地址为:http://127.0.0.1:8080/mgr/menus/nav/<code>
该插件是 Controller、Result两个插件的扩展插件,它为上述两个插件提供了返回值集处理机制。
@Forword、@Include、@Json、@Redirect 就是它提供的,开发者还可以自己另外自定义扩展。例子:
@Controller("/action") public class SimpleAction extends AbstractController { @Json public Map<String, Object> json() { HashMap<String, Object> returnData = new HashMap<String, Object>(); returnData.put("data1", true); returnData.put("data2", 123); return returnData; } // @Forword public String forwordTo() { return "/index.htm"; } @Redirect public String redirectTo() { return "http://www.baidu.com"; } }
该插件是用来支持Servlet3.0 规范的软件包,当 Servlet 容器不支持 Servlet3.0 规范时可以
通过该插件提供的 @WebFilter、@WebServlet、@WebInitParam 来实现 Servlet3.0。例子:
@WebFilter("/*") public class TestFilter implements Filter { public void init(FilterConfig filterConfig) throws ServletException {} public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("before Servlet. from " + request.getRequestURI()); chain.doFilter(request, response); System.out.println("after Servlet. from " + request.getRequestURI()); } public void destroy() {} }
@WebServlet("showname.c") public class HelloWordServlet extends HttpServlet { @Inject private AppContext appContext = null; protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { CustomerBean infoBean = this.appContext.getInstance(CustomerBean.class); infoBean.foo(); // resp.getWriter().write("Call Servlet showname.c"); super.service(req, resp); } }
通过这个插件可以将位于ClassPath、Zip等位置中的资源用作 Web 请求响应。插件是以
Servlet 方式提供,开发者需要自己注册它。例子:
@Plugin public class CustomResources extends AbstractWebHasorPlugin { public void loadPlugin(WebApiBinder apiBinder) { // //js,css,gif,ico,jpg,jpeg,png,swf,swc,flv,mp3,wav,avi apiBinder.serve("*.js").with(ResourceHttpServlet.class); apiBinder.serve("*.css").with(ResourceHttpServlet.class); apiBinder.serve("*.wav").with(ResourceHttpServlet.class); apiBinder.serve("*.avi").with(ResourceHttpServlet.class); // apiBinder.getGuiceBinder().bind(ResourceLoaderFactory.class).toInstance(new ResourceLoaderFactory() { public ResourceLoader[] loaderArray(AppContext appContext) { ResourceLoader classLoader = new ClassPathResourceLoader("/META-INF/webapp"); return new ResourceLoader[] { classLoader }; } }); } }
JDBC 的使用参考:http://my.oschina.net/u/1166271/blog/186940