在Seam Framework中,Interceptor完成简单的AOP功能,本文分析Interceptor的处理流程。
在创建Seam组件的Component类时,有一段初始化Interceptor的代码:
不过可以通过在Seam组件上使用@BypassInterceptors注解以禁止使用Interceptor.
Component.initInterceptors()
这里的Interceptors注解类可以是org.jboss.seam.annotations.intercept.Interceptors
也可以是 javax.interceptor.Interceptors,
要注意的是,Interceptors注解不能直接加到Bean中,而应该通过一个注解间接地加到Bean上,
通过上面的代码可以看出这一点。
Component.initDefaultInterceptors()
BijectionInterceptor即双向注入拦截器,稍后我们来看它是如何工作的。
在Seam Framework中,并不要求Interceptor继承自某个Interface或Class,
只要在Invoke方法上加@AroundInvoke注解即可,这样任何一个Pojo类都可以成为Interceptor,
当然,如果让Interceptor继承自Seam中的AbstractInterceptor,那么能得到一些性能上的优化,
稍后我们会看到这一点。
下面以普通JavaBean为例来说明Interceptor的处理流程
Component.initantiateJavaBean()
在bean创建后,为其创建一个JavaBeanInterceptor,然后创建一个proxy对象返回,
这样对bean的所有调用都将由JavaBeanInterceptor进行处理。
JavaBeanInterceptor.invoke(proxy, method, proceed, params)
JavaBeanInterceptor.interceptInvocation(method, params)
RootInterceptor.invoke(invocation, invocationType)
RootInterceptor.createInvocationContext(invocation, invocationType)
SeamInvocationContext.proceed()
这是一个Interceptor链的处理方法,每进入一个Interceptor,location加一,
直到所有Interceptor都进入才执行实际的业务方法,然后按相反顺序退出Interceptor链,
所以在业务方法中必须调用invocation.proceed()以使Interceptor链进行下去。
Interceptor.aroundInvoke(invocation, userInterceptor)
如果aroundInvokeMethod为null,则继续下一Interceptor,
否则执行userInterceptor的aroundInvokeMethod。
双向注入
双向注入由BijectionInterceptor拦截器完成,双向注入只是IoC的一个扩展,其中
正向注入把Context中的对象到Seam组件中,反向注入把Seam组件的对象注入到Context中,
BijectionInterceptor.aroundInvoke(invocation)
有关双向注入的详细内容请查看后续文章。
在创建Seam组件的Component类时,有一段初始化Interceptor的代码:
if ( interceptionEnabled ) {
initInterceptors();
}
不过可以通过在Seam组件上使用@BypassInterceptors注解以禁止使用Interceptor.
Component.initInterceptors()
initDefaultInterceptors(); // 初始化默认的Interceptor
// 加入用户的Interceptor.
for (Annotation ann : getBeanClass().getAnnotations() ) {
if (annotation.annotationType().isAnnotationPresent(Interceptors.class)) {
Class[] classes = annotation.annotationType().getAnnotation(Interceptors.class).value;
addInterceptor(new Interceptor(classes, annotation, this));
}
}
这里的Interceptors注解类可以是org.jboss.seam.annotations.intercept.Interceptors
也可以是 javax.interceptor.Interceptors,
要注意的是,Interceptors注解不能直接加到Bean中,而应该通过一个注解间接地加到Bean上,
通过上面的代码可以看出这一点。
Component.initDefaultInterceptors()
//根据组件类型初始化Interceptors,这里只给出其中的两个:
if (getType()!=ENTITY_BEAN) {
addInterceptor(new Interceptor(new MethodContextInterceptor(), this));
}
if (needsInjection() || needsOutjection()) { // 需要注入或反向注入
addInterceptor(new Interceptor(new BijectionInterceptor(), this));
}
BijectionInterceptor即双向注入拦截器,稍后我们来看它是如何工作的。
在Seam Framework中,并不要求Interceptor继承自某个Interface或Class,
只要在Invoke方法上加@AroundInvoke注解即可,这样任何一个Pojo类都可以成为Interceptor,
当然,如果让Interceptor继承自Seam中的AbstractInterceptor,那么能得到一些性能上的优化,
稍后我们会看到这一点。
下面以普通JavaBean为例来说明Interceptor的处理流程
Component.initantiateJavaBean()
Object bean = getBeanClass().newInstance();
JavaBeanInterceptor interceptor = new JavaBeanInterceptor(bean, this);
bean = wrap(bean, interceptor);
interceptor.postConstruct();
return bean;
在bean创建后,为其创建一个JavaBeanInterceptor,然后创建一个proxy对象返回,
这样对bean的所有调用都将由JavaBeanInterceptor进行处理。
JavaBeanInterceptor.invoke(proxy, method, proceed, params)
Object result = interceptInvocation(method, params);
return result==bean ? proxy : result;
JavaBeanInterceptor.interceptInvocation(method, params)
return invoke(new RootInvocationContext(bean, method, params), EventType.AROUND_INVOKE);
RootInterceptor.invoke(invocation, invocationType)
if (!isSeamComponent || !Lifecycle.isApplicationInitialized()) {
// 不是一个seam组件,直接调用方法
return invocation.proceed();
}
else {
return createInvocationContext(invocation, invocationType).proceed();
}
RootInterceptor.createInvocationContext(invocation, invocationType)
if (isProcessInterceptors(invocation.getMethod(), invocation.getTarget())) {
// 检查method是否要处理拦截,在Method上也可以加BypassInterceptors注解来忽略拦截器
return createSeamInvocationContext(invocation, invocationType);
}
else {
return invocation;
}
SeamInvocationContext.proceed()
if (location == interceptors.size) {
// 所有Interceptor是否已处理完
return context.proceed();
}
else {
Object userInterceptor = userInterceptors.get(location);
Interceptor interceptor = interceptors.get(location);
location++;
switch (eventType) {
case AROUND_INVOKE:
if (interceptor.isOptimized()) {
// 检查Interceptor是否继承自OptimizedInterceptor
return ((OptimizedInterceptor)userInterceptor).aroundInvoke(this);
}
else {
return interceptor.aroundInvoke(this, userInterceptor);
}
case .....
}
}
这是一个Interceptor链的处理方法,每进入一个Interceptor,location加一,
直到所有Interceptor都进入才执行实际的业务方法,然后按相反顺序退出Interceptor链,
所以在业务方法中必须调用invocation.proceed()以使Interceptor链进行下去。
Interceptor.aroundInvoke(invocation, userInterceptor)
return aroundInvokeMethod==null ?
invocation.proceed() :
Reflections.invoke( aroundInvokeMethod, userInterceptor, invocation );
如果aroundInvokeMethod为null,则继续下一Interceptor,
否则执行userInterceptor的aroundInvokeMethod。
双向注入
双向注入由BijectionInterceptor拦截器完成,双向注入只是IoC的一个扩展,其中
正向注入把Context中的对象到Seam组件中,反向注入把Seam组件的对象注入到Context中,
BijectionInterceptor.aroundInvoke(invocation)
Component component = getComponent();
boolean enforceRequired = !component.isLifecycleMethod(invocation.getMethod());
// 正向注入
component.inject(invocation.getTarget(), enforceRequired);
// 业务方法
Object result = invocation.proceed();
// 反向注入
component.outject(invocation.getTarget(), enforeRequried);
component.disinject(invocation.getTarget());
return result;
有关双向注入的详细内容请查看后续文章。