如何把接口加入到Spring容器(任何類/接口都可以用這個方式,例如動態代理)

問題緣由

起因是設計一款RPC框架,但是客戶端由於只有接口,沒有實現,所以加入Spring不能實現。因此和分享小組成員討論研究,最後得到自己想要的是什麼。

gitee地址:https://gitee.com/kylin1991_admin/rpc_handwriting

快速開始

1、加入maven包

  • 加入jarreflections-可以選擇不加入,我只是爲了掃包方便(後面可以自己寫掃描)

        <!-- https://mvnrepository.com/artifact/org.reflections/reflections -->
        <dependency>
          <groupId>org.reflections</groupId>
          <artifactId>reflections</artifactId>
          <version>0.9.11</version>
          <exclusions>
            <exclusion>
              <groupId>javassist</groupId>
              <artifactId>javassist</artifactId>
            </exclusion>
          </exclusions>
        </dependency>
    
  • Spring-context 這個需要的,因爲我們要用容器和註解和bean

        <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-context</artifactId>
          <version>5.2.4.RELEASE</version>
        </dependency>
    

2、寫一個自己的FactoryBean

  • 例如:我是要實現動態代理,自己寫了一個

    public class FactoryRpcClientBean<T> implements FactoryBean<T> {
        private Class<T> interfaceType;
        private String host;
        private int port;
    
        public FactoryRpcClientBean(Class<T> interfaceType, String host, int port) {
            // 構造器的參數可以自己定義,
            // 只需要在beanDefinition註冊的時候傳遞過來即可
            this.interfaceType = interfaceType;
            this.host = host;
            this.port = port;
        }
    
        @Override
        public T getObject() throws Exception {
            // 這裏主要是創建接口對應的實例,便於注入到spring容器中
            // 所以這裏也是控制實例的結果的。
            return new RpcProxyClient().proxyClient(interfaceType, host, port);
        }
    
        @Override
        public Class<T> getObjectType() {
            // 這裏是控制類型,同時也可以根據這個類型來獲取bean
            return interfaceType;
        }
    
        @Override
        public boolean isSingleton() {
            return true;
        }
    }
    

3、干預BeanDefinition

  • 只需要注意bean的註冊和需要什麼參數就行了,其他忽略(是我個人的框架需要而已)

    @Configuration
    public class SpringConfig implements BeanDefinitionRegistryPostProcessor {
    
        private static final String host = "localhost";
        private static final int port = 8080;
        private static final String SCANNER_PATH = "org.example";
    
        @Override
        public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
    
            // 掃描xx路徑下的@註解的接口或類
            Reflections reflections = new Reflections(SCANNER_PATH);
            Set<Class<?>> set = reflections.getTypesAnnotatedWith(RpcClient.class);
            for (Class<?> aClass : set) {
    
                // 通過FactoryRpcClientBean來生成一個新的BeanDefinition
                BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(FactoryRpcClientBean.class);
                BeanDefinition definition =builder.getRawBeanDefinition();
    
                // 傳入構造參數
                definition.getConstructorArgumentValues().addGenericArgumentValue(aClass);
     			definition.getConstructorArgumentValues().addGenericArgumentValue(host);
     			definition.getConstructorArgumentValues().addGenericArgumentValue(port);
    
                // 註冊BeanDefinitionBuilder
                beanDefinitionRegistry.registerBeanDefinition(aClass.getSimpleName(), definition);
            }
        }
    
        @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
    
        }
    }
    

上面已經完成,可以直接使用了

下面就是加入自己的註解,不過和上面沒多大關係了

1、自定義Autowired註解

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Autowired
public @interface RpcClient {
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章