spring cloud - feign的核心原理

77 阅读2分钟

世界上并没有完美的程序,但是我们并不因此而沮丧,因为写程序就是一个不断追求完美的过程。

无论是看源码还是手动实现,对于Feign我们的唯一目的就是弄懂其核心原理,因为Feign是一个顶级封装,并且其实现也是使用的非常规的Rxjava的Obversable,所以这里有一个常规的基于动态代理的手动实现以诠释Feign的核心原理。

首先创建注解:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface FeignClient {
    String baseUrl() default "";
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FeignGet {
    String url() default "";
}

定义使用

@Component
@FeignClient(baseUrl = "http://www.baidu.com")
public interface TestFeign {

    @FeignGet(url = "/index.html")
    String get();
}

控制层输出

@RestController
public void TestController {
	@Autowired
	private TestFeign testFeign;
	    
	@RequestMapping("/feign")
   public String feign () {
        return testFeign.get();
    }
}    

然后是核心实现,主要目的是包扫描、动态代理以及注册Bean

/**
 * 通过动态代理将Feign的Bean注册到spring容器中
 */
public class FeignRegister implements
        ImportBeanDefinitionRegistrar,
        EnvironmentAware,
        BeanClassLoaderAware,
        ResourceLoaderAware,
        BeanFactoryAware {

    private Environment environment;
    private ClassLoader classLoader;
    private ResourceLoader resourceLoader;
    private BeanFactory beanFactory;

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
                                        BeanDefinitionRegistry registry) {
        scan();
    }

    private void scan () {
        // 构建包扫描器
        ClassPathScanningCandidateComponentProvider scan =
                new ClassPathScanningCandidateComponentProvider(false, environment) {
                    @Override
                    protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
                        if (beanDefinition.getMetadata().isInterface()) {
                            try {
                                Class<?> clazz = ClassUtils.forName(
                                        beanDefinition.getMetadata().getClassName(),
                                        classLoader);
                                return !clazz.isAnnotation();
                            } catch (ClassNotFoundException e) {
                                e.printStackTrace();
                            }
                        }
                        return super.isCandidateComponent(beanDefinition);
                    }
                };
        scan.setResourceLoader(resourceLoader);
        AnnotationTypeFilter typeFilter = new AnnotationTypeFilter(FeignClient.class);
        scan.addIncludeFilter(typeFilter);

        // 扫描指定的包
        String basePackage = "com.test.demo.feign";
        Set<BeanDefinition> beanDefinitionSet = scan.findCandidateComponents(basePackage);

        // 注册bean
        beanDefinitionSet.forEach(beanDefinition -> {
            try {
                if (beanDefinition instanceof AnnotatedBeanDefinition) {
                    String className = beanDefinition.getBeanClassName();

                    // 创建动态代理
                    Class<?> target = Class.forName(className);
                    InvocationHandler invocationHandler = new InvocationHandler() {
                        @Override
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                            FeignClient feignClient = target.getAnnotation(FeignClient.class);
                            FeignGet feignGet = method.getAnnotation(FeignGet.class);
                            String baseUrl = feignClient.baseUrl();
                            String url = feignGet.url();
                            String allUrl = StrUtil.concat(true, baseUrl, url);
                            String re = new RestTemplate().getForObject(allUrl, String.class, "");
                            System.out.println("re : " + re);
                            return re;
                        }
                    };
                    Object proxy = Proxy.newProxyInstance(classLoader, new Class[]{target}, invocationHandler);

                    // 注册
                    ((DefaultListableBeanFactory) beanFactory).registerSingleton(className, proxy);
                }
            } catch (Exception e) {e.printStackTrace();}
        });
    }

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        this.classLoader = classLoader;
    }

    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }
}

启动类中引入注册类

@SpringBootApplication
@Import(FeignRegister.class)
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

}

然后启动运行即可,最终结果
在这里插入图片描述
代码有自解释的能力,所以在这里不多做赘述。并且我认为里面有好多我们实际开发中用到的片段,比如如何进行包扫描,如何实现动态代理,如何注册自定义Bean等,希望对大家有所帮助。
在这里插入图片描述