从0开始写一个基于注解的轻量级分布式RPC框架(4)自定义Spring的IOC,自定义属性注入bean的过程

10 篇文章 0 订阅
6 篇文章 0 订阅

代码已经发布在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框架的实现。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值