接上个贴。继续谈谈自己的annotation是如何处理的。
主要目的,加入一个RPC层,RPC层主要是提供透明的rpc调用的服务层和协议解析层。
对于service层来说,关心的是业务逻辑,用spring的aop的原理,service层提供
服务。不负责具体的rpc的协议的处理和转换,这个转换通过专门的协议的拦截器注入
从而提供各样的rpc调用,比如json-rpc,xml-rpc,edi-rpc,webservice-rpc等
在提供服务的service里,通过自己定义的annotation来published可以提供的rpc的
服务。
先定义了一个Enum来作为Annotation里的可选值,Required,作为Annontation的
一个属性,表明,这个service和method是否要作为rpc的service
public enum Required
{
YES(true),NO(false);
private final boolean value;
Required(boolean value) { this.value = value; }
public boolean value() { return value; }
}
定义两个值,YES,NO,yes表明需要。No表明不需要
接着定义自己的annotation
@Target({ElementType.METHOD, ElementType.TYPE, ElementType.FIELD ,ElementType.PARAMETER
})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface RPC
{
Required required() default Required.NO;
String name() default "";
}
这里定义的比较简单,提供了name属性和required属性,上面的ElementType.FIELD ,ElementType.PARAMETER可以去掉,annotation类似于在class上做的一个记号,标志在class上,这里有关annontation的开发将在其他的文章里单独描述
下面我们来写这个annontation的处理类,这里我使用的是spring的beanProcesser来进行annontation的解析。在spring的
runtime的时候,通过对所有的class的扫描,来归纳做了RPC的annotation的类。
这里需要在spring的配置文件里加入
<bean class="com.synchrophy.framework.test.annotation.RPCAnnotationBeanProcessor"/>
<context:component-scan base-package="com. synchrophy" />
这样spring就会自动的掉到RPCAnnotationBeanProcessor来进行处理
public class RPCAnnotationBeanProcessor implements BeanPostProcessor,PriorityOrdered
{
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException
{
System.out.println(beanName + "(Before) : " + bean);
Class clazz = bean.getClass();
RPC rpc = (RPC)clazz.getAnnotation(RPC.class);
if(rpc!=null)
{
boolean required = rpc.required().value();
RPCServiceDescription desciption = new RPCServiceDescription();
try
{
clazz = Class.forName(clazz.getName());
}
catch (Exception e) {
throw new IllegalArgumentException(e);
}
String servicename;
if(StringUtils.isBlank(rpc.name()))
{
servicename = beanName;
}
else
{
servicename = rpc.name();
}
desciption.setServicename(servicename);
desciption.setClazz(clazz);
Method[] ms = clazz.getMethods();
for(Method m : ms)
{
if(!Modifier.isPublic(m.getModifiers()))
continue;
rpc = (RPC)m.getAnnotation(RPC.class);
if( (required && (rpc==null||rpc.required()==Required.YES))
|| (required==false && rpc!=null && rpc.required()==Required.YES))
{
RPCServiceAPIDescription apiDesc = new RPCServiceAPIDescription();
apiDesc.setMethod(m);
apiDesc.setMethodname((rpc==null||StringUtils.isBlank(rpc.name()))?m.getName():rpc.name());
Class[] pts = m.getParameterTypes();
int ind = 0;
for(Class pt : pts)
{
apiDesc.addParameters(ind+"", pt);
ind ++;
}
desciption.addApis(apiDesc);
}
}
System.out.println("=========== Annotation " + desciption);
}
return bean;
}
public int getOrder()
{
// TODO Auto-generated method stub
return Ordered.LOWEST_PRECEDENCE - 2;
}
}
结合上上一篇文章谈到的bean generation的流程,这里我们将这个RPCAnnotationBeanProcessor,
从BeanPostProcessor里扩展,当Application的BeanFactory进行处理的时候,会callback这里接口里定义的两个方法。
这里我是将annotation的处理放到before的方法里,而不是放到after里,这个也是基于bean generation的过程而决定的
当然这里也可以放到after,可以把ProrityOrder设置的High一些。
现在我们可以写一个测试的service了
接口
public interface BeanProcesserTestService
{
public void test1();
public void test2(String name);
}
实现
@Service("beanProcesserTestService")
@RPC()
public class BeanProcesserTestServiceImpl implements BeanProcesserTestService
{
/* (non-Javadoc)
* @see com.sunvalley.framework.test.BeanProcesserTestService#test1()
*/
@RPC(required=Required.YES)
public void test1()
{
// TODO Auto-generated method stub
System.out.println("test1 ......... ");
}
/* (non-Javadoc)
* @see com.sunvalley.framework.test.BeanProcesserTestService#test2(java.lang.String)
*/
@RPC(required=Required.YES, name="test2")
public void test2(String name)
{
// TODO Auto-generated method stub
System.out.println("test2 ........ ");
}
}
测试
public class TestBeanProcessor extends BaseTestCase
{
/* (non-Javadoc)
* @see junit.framework.TestCase#setUp()
*/
protected void setUp()
{
super.setUp();
}
public void testRPCAnnotation()
{
BeanProcesserTestService s = (BeanProcesserTestService)this.context.getBean("beanProcesserTestService");
System.out.println(s);
}
}
当load到context时,就可以自动的把我的BeanProcesserTestService的RPC service已经收集到了,
其中test1和test2都已经注册到, RPCService里去了。这样通过协议层的转换从而实现各种协议
的RPC调用了。