代码已经发布在GIT 源代码
自定义注解@SReference注解
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD, ElementType.METHOD })
public @interface SReference {
}
如何让这个注解所标注的属性可以被Spring注入相关的bean?
方法1 AutowiredAnnotationBeanPostProcessor
@Component
public class SonicAutowiredAnnotationBeanPostProcessor extends AutowiredAnnotationBeanPostProcessor {
public SonicAutowiredAnnotationBeanPostProcessor() {
super();
setAutowiredAnnotationType(SReference.class);// 用来设置自定义注解
}
}
这样的话就可以将@SReference标注的属性的引用指向Spring上下文的相关的bean。
但是我们想让注入的这个过程不注入Spring中的bean(因为压根我们就没有产生实例,实例在生产者,而我们是消费者,只有接口没有定义接口的实现)。而是注入我们的代理类。
方法3 BeanPostProcessor
@Component
public class SonicBeanPostProcessor implements BeanPostProcessor, ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
LogCore.BASE.info("beanName={}, bean={}", beanName, bean.getClass());
// 强制检索属性有无SReference
if (hasAnnotation(bean.getClass().getAnnotations(), SReference.class.getName())) {
Class<?> beanClass = bean.getClass();
do {
Field[] fields = beanClass.getDeclaredFields();
for (Field field : fields) {
setField(bean, field);
}
} while ((beanClass = beanClass.getSuperclass()) != null);
} else {
processMyInject(bean);
}
return bean;
}
private void processMyInject(Object bean) {
Class<?> beanClass = bean.getClass();
do {
Field[] fields = beanClass.getDeclaredFields();
for (Field field : fields) {
if (!hasAnnotation(field.getAnnotations(), SReference.class.getName())) {
continue;
}
setField(bean, field);
}
} while ((beanClass = beanClass.getSuperclass()) != null);
}
private void setField(Object bean, Field field) {
if (!field.isAccessible()) {
field.setAccessible(true);
}
try {
// field.set(bean, applicationContext.getBean(field.getType()));
field.set(bean, applicationContext.getBean(ConsumerProxyFactory.class).create(field.getType()));
} catch (Exception e) {
e.printStackTrace();
}
}
private boolean hasAnnotation(Annotation[] annotations, String annotationName) {
if (annotations == null) {
return false;
}
for (Annotation annotation : annotations) {
if (annotation.annotationType().getName().equals(annotationName)) {
return true;
}
}
return false;
}
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
private ConsumerHandler consumerHandler;// spring注入 consumerHandler
/* create()创建工厂bean speakInterface Class<?> interfaceClass = Class.forName(clazz); */
public Object create(Class<?> interfaceClass) {
return Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class[] { interfaceClass }, this);
}
....
}
最后
这样我们的注解很干净,但是我们利用Spring的IOC成功将实例的注入和依赖拆分为服务提供者加载RPC服务,并通过网络请求解析出参数用反射来调用他们。而消费者所引用的服务被注入了动态代理类,其调用被封装为网络请求发布到远程。
整个过程就跟我们使用本地的@Component和@Autowired一样简便。
这就是整个基于注解的简单的RPC框架的实现。