上面的我们看到
stripes
通过配置文件把框架的大部分功能组件组合在一起,组合在一起,那么怎么有序运行呢?同时不能失去框架的扩展性,不能就顺序执行组件吧,现在的流行的框架都是采用
IOC
容器来组合这些组件,像
structs2
采用
xwork IOC
容器,
tapestry5
现在采用
spring IOC
容器。
IOC
(控制反转)实际上就是拦截器。在
servlet Filter
中,我们应该知道什么是拦截器吧。
Stripes
是框架,不能没有扩展性,但
stripes
又不想弄得太复杂。没有像别的框架借助于别的
IOC
容器。
Stripes
实现了一个小的拦截器子系统,
6
个
LifecycleStage
在
拦截器子系统中执行,同时,
stripes
又给用户实现拦截器的接口,通过配置,可以在自己的系统中实现功能强大的拦截功能。
Interceptor.java
public interface Interceptor {
Resolution intercept(ExecutionContext context) throws Exception;}
上面的 Interceptor 接口的代码,我们可以看出它使用了 ExecutionContext ,什么是 ExecutionContext 就是整个 stripes 执行时上下文,也就是说在 stripes 框架在执行时,只要调用这个上下文,就可以得整个生命周斯所需要的东西。
ExecutionContext.java
public class ExecutionContext {
private static final Log log = Log.getInstance(ExecutionContext.class);
private Collection<Interceptor> interceptors;
private Iterator<Interceptor> iterator;
private Interceptor target;
private ActionBeanContext actionBeanContext;
private ActionBean actionBean;
private Method handler;
private Resolution resolution;
private LifecycleStage lifecycleStage;
。。。。。
public Resolution wrap(Interceptor target) throws Exception {
this.target = target;
this.iterator = null;
return proceed();
}
public Resolution proceed() throws Exception {
if (this.iterator == null) {
log.debug("Transitioning to lifecycle stage ", lifecycleStage);
this.iterator = this.interceptors.iterator();
}
if (this.iterator.hasNext()) {
return this.iterator.next().intercept(this);
}
else {
return this.target.intercept(this);
}
}
}
省去了 set,get 方法, ExecutionContext 就只有两个功能方法。 proceed() 方法就像 servlet filter 中 proceed()filterChain.doFilter(request, response); 运行接下来的过滤器一样,运行下一个拦截器。, ExecutionContext 有 8 个属性。 Interceptors 是指本生命周期阶段的所有要执行的 Interceptor , iterator 是指 Interceptors 集合中某一个,因为采用 iterator ,所以 Interceptor 集合中的 Interceptor 执行是不保证顺序的。也就是说同一个阶段的拦截器不能形成依赖关系。 Target 是目标 Interceptor ,每一个阶段都一定执行的 Interceptor 。 Resolution 是解析器,就像 structs 中 ActionForward 一样。 lifecycleStage 就是前面讲的 6 个生命阶段。 我们可以找一个例子:
DispatcherHelper.java
public static Resolution resolveHandler (final ExecutionContext ctx) throws Exception {
final Configuration config = StripesFilter.getConfiguration();
ctx.setLifecycleStage(LifecycleStage.HandlerResolution);
ctx.setInterceptors(config.getInterceptors(LifecycleStage.HandlerResolution));
return ctx.wrap( new Interceptor() {
public Resolution intercept(ExecutionContext ctx) throws Exception {
ActionBean bean = ctx.getActionBean();
ActionBeanContext context = ctx.getActionBeanContext();
ActionResolver resolver = config.getActionResolver();
// Then lookup the event name and handler method etc.
String eventName = resolver.getEventName(bean.getClass(), context);
context.setEventName(eventName);
final Method handler;
if (eventName != null) {
handler = resolver.getHandler(bean.getClass(), eventName);
}
else {
handler = resolver.getDefaultHandler(bean.getClass());
if (handler != null) {
context.setEventName(resolver.getHandledEvent(handler));
}
}
// Insist that we have a handler
if (handler == null) {
throw new StripesServletException(
"No handler method found for request with ActionBean [" +
bean.getClass().getName() + "] and eventName [ " + eventName + "]");
}
log.debug("Resolved event: ", context.getEventName(), "; will invoke: ",
bean.getClass().getSimpleName(), ".", handler.getName(), "()");
ctx.setHandler(handler);
return null;
}
});
}
这个方面是在生命周期的第二个阶段执行。首先给ExecutionContext设定了所处的阶段,接着去找这个阶段的Interceptors.怎么找呢?它调用了DefaultConfiguration.java中
public Collection<Interceptor> getInterceptors(LifecycleStage stage) {
Collection<Interceptor> interceptors = this.interceptors.get(stage);
if (interceptors == null) {
interceptors = Collections.emptyList();
}
return interceptors;
}
方法。在这个方法从本实现的所有 interceptors 取到属性本阶段的。 Interceptors 是在 DefaultConfiguration 的 init() 方法中:
this.interceptors = initInterceptors();
if (this.interceptors == null) {
this.interceptors = new HashMap<LifecycleStage, Collection<Interceptor>>();
Class<? extends Interceptor> bam = BeforeAfterMethodInterceptor.class;
BeforeAfterMethodInterceptor interceptor = new BeforeAfterMethodInterceptor();
for (LifecycleStage stage : bam.getAnnotation(Intercepts.class).value()) {
Collection<Interceptor> instances = new ArrayList<Interceptor>();
instances.add(interceptor);
this.interceptors.put(stage, instances);
}
还记得前面讲过 DefaultConfiguration 是模版类吗? initInterceptors() 在本类是默认的 return null 实现,推迟到子类实现。 看看 RuntimeConfiguration .java 中 @Override
protected Map<LifecycleStage, Collection<Interceptor>> initInterceptors() {
String classList = getBootstrapPropertyResolver().getProperty(INTERCEPTOR_LIST);
if (classList == null) {
return null;
}
else {
String[] classNames = StringUtil.standardSplit(classList);
Map<LifecycleStage, Collection<Interceptor>> map =
new HashMap<LifecycleStage, Collection<Interceptor>>();
for (String className : classNames) {
try {
Class<? extends Interceptor> type = ReflectUtil.findClass(className.trim());
Intercepts intercepts = type.getAnnotation(Intercepts.class);
if (intercepts == null) {
log.error("An interceptor of type ", type.getName(), " was configured ",
"but was not marked with an @Intercepts annotation. As a ",
"result it is not possible to determine at which ",
"lifecycle stages the interceprot should be applied. This ",
"interceptor will be ignored.");
}
else {
log.debug("Configuring interceptor '", type.getSimpleName(),
"', for lifecycle stages: ", intercepts.value());
}
// Instantiate it and optionally call init() if the interceptor
// implements ConfigurableComponent
Interceptor interceptor = type.newInstance();
if (interceptor instanceof ConfigurableComponent) {
((ConfigurableComponent) interceptor).init(this);
}
for (LifecycleStage stage : intercepts.value()) {
Collection<Interceptor> stack = map.get(stage);
if (stack == null) {
stack = new LinkedList<Interceptor>();
map.put(stage, stack);
}
stack.add(interceptor);
}
}
catch (Exception e) {
throw new StripesRuntimeException(
"Could not instantiate one or more configured Interceptors. The " +
"property '" + INTERCEPTOR_LIST + "' contained [" + classList +
"]. This value must contain fully qualified class names separated " +
"by commas.", e);
}
}
return map;
}
}
这个方法取到配置中的拦截器s,并实例化它们,之后按生命周期分成6类放在renturn中的Map<LifecycleStage, Collection<Interceptor>>中。现在回到resolveHandler方法,这个方法接下来就是return ctx.wrap( new Interceptor() {..});这个实现了一个匿名的Interceptor,之后执行ExcuteContext.wrap(Interceptor)方法。还记得wrap(interceptor),它是一个包扎方法,把这个匿名Interceptor保存ExcuteContext 的target对象。this.target = target;接下的这句 this.iterator = null;仅仅是代码的实现技巧,这个是要在下面的 return proceed();做判断处理。
public Resolution proceed() throws Exception {
if (this.iterator == null) {
log.debug("Transitioning to lifecycle stage ", lifecycleStage);
this.iterator = this.interceptors.iterator(); }
if (this.iterator.hasNext()) {
return this.iterator.next().intercept(this); }
else { return this.target.intercept(this); } }
this . iterator = null 的作用仅仅是为了找到这一阶段的 interceptors 。如果找到了就是执行这一阶段的 interceptors 中的 iterator 。在这里看到,每一个阶段只能执行一个 interceptors 的第一个。那剩下的呢怎么办?剩下就是用户实现的拦截器的传递了。如果用户的实现的拦截器没用传递。那之后就不执行,连本阶段的 匿名 Interceptor 都不会执行就直接返回。返回的是 Resolution 不为 null, 那个整个流程就结束,剩下的执行 Resolution 的跳起页面功能(像 structs 的 ActionForward, 比它的功能强)。用户实现的拦截如下:
@Intercepts({LifecycleStage.ActionBeanResolution})
public class HibernateInterceptor implements Interceptor
{ private static Log log = Log.getInstance(HibernateInterceptor.class);private boolean initializedHibernateProvider = false;
public Resolution intercept(ExecutionContext context) throws Exception
{log.debug("HibernateInterceptor called");
if (!initializedHibernateProvider && (HibernateProvider.getInstance() == null) && (HibernateFilter.getCurrentInstance() != null))
{log.info("Initializing HibernateProvider");
HibernateProvider.setInstance(HibernateFilter.getCurrentInstance());
initializedHibernateProvider = true; }
return context.proceed(); }
看到最后一句的:return context.proceed();从现在开始iterator都不为空。那么就找下一个Interceptor,没有的话,就执行本阶段的目标this.target.intercept(this);这个是在本阶段最后执行的。
如果用户采用如下的话:
@Intercepts({LifecycleStage.HandlerResolution})
public class NoisyInterceptor implements Interceptor {
public Resolution intercept(ExecutionContext ctx) throws Exception {
System.out.println("Before " + ctx.getLifecycleStage());
Resolution resolution = ctx.proceed();
System.out.println("After " + ctx.getLifecycleStage());
return resolution}}
那就是一个嵌套的执行,最后还会返回来执行 Resolution resolution = ctx.proceed(); 下面的语句。 ctx.proceed() 上面的语句是在目标 Interceptor 之前执行。下面的语句是在 目标 Interceptor 之后执行。 Stripes 有一个默认的 @before 和 @after 就是一个在前面一个后面的实现。 分析完了,是不是自己也想写一个 interceptor 。写 interceptor 很简单,只要实现 implements Interceptor ,也就是实现了 public Resolution intercept(ExecutionContext ctx) throws Exception 就可以。还有一点不能忘记,这个 interceptor 是在那个阶段执行的, 如@Intercepts({LifecycleStage.HandlerResolution}) 就是在 HandlerResolution 执行。