经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Spring » 查看文章
spring?boot?动态生成接口实现类的场景分析
来源:jb51  时间:2021/11/29 12:51:36  对本文有异议

在某些业务场景中,我们只需要业务代码中定义相应的接口或者相应的注解,并不需要实现对应的逻辑。

比如 mybatis和feign: 在 mybatis 中,我们只需要定义对应的mapper接口;在 feign 中,我们只需要定义对应业务系统中的接口即可。

那么在这种场景下,具体的业务逻辑时怎么执行的呢,其实原理都是动态代理。

我们这里不具体介绍动态代理,主要看一下它在springboot项目中的实际应用,下面我们模仿feign来实现一个调用三方接口的 httpclient。

一: 定义注解

  1. package com.mysgk.blogdemo.annotation;
  2.  
  3. public @interface MyHttpClient {
  4. }

二: 建立动态代理类

  1. package com.mysgk.blogdemo.proxy;
  2.  
  3. import org.springframework.beans.factory.FactoryBean;
  4.  
  5. import java.lang.reflect.InvocationHandler;
  6. import java.lang.reflect.Method;
  7. import java.lang.reflect.Proxy;
  8.  
  9. public class RibbonAopProxyFactory<T> implements FactoryBean<T>, InvocationHandler {
  10.  
  11. private Class<T> interfaceClass;
  12.  
  13. public Class<T> getInterfaceClass() {
  14. return interfaceClass;
  15. }
  16.  
  17. public void setInterfaceClass(Class<T> interfaceClass) {
  18. this.interfaceClass = interfaceClass;
  19. }
  20.  
  21. @Override
  22. public T getObject() throws Exception {
  23. return (T) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{interfaceClass}, this);
  24. }
  25.  
  26. @Override
  27. public Class<?> getObjectType() {
  28. return interfaceClass;
  29. }
  30.  
  31. @Override
  32. public boolean isSingleton() {
  33. return true;
  34. }
  35.  
  36. /**
  37. 真正执行的方法
  38. */
  39. @Override
  40. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  41. return "invoke " + proxy.getClass().getName() + "." + method.getName() + " , do anything ..";
  42. }
  43. }

三: 注入spring容器

  1. package com.mysgk.blogdemo.start;
  2.  
  3. import cn.hutool.core.util.ClassUtil;
  4. import cn.hutool.core.util.StrUtil;
  5. import com.mysgk.blogdemo.annotation.MyHttpClient;
  6. import com.mysgk.blogdemo.proxy.RibbonAopProxyFactory;
  7. import org.slf4j.Logger;
  8. import org.slf4j.LoggerFactory;
  9. import org.springframework.beans.BeansException;
  10. import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
  11. import org.springframework.beans.factory.support.BeanDefinitionBuilder;
  12. import org.springframework.beans.factory.support.BeanDefinitionRegistry;
  13. import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
  14. import org.springframework.beans.factory.support.GenericBeanDefinition;
  15. import org.springframework.context.ApplicationContext;
  16. import org.springframework.context.ApplicationContextAware;
  17. import org.springframework.stereotype.Component;
  18.  
  19. import java.util.Set;
  20.  
  21. @Component
  22. public class ScanHttpClients implements BeanDefinitionRegistryPostProcessor, ApplicationContextAware {
  23.  
  24. private final Logger logger = LoggerFactory.getLogger(ScanHttpClients.class);
  25.  
  26. private ApplicationContext ctx;
  27.  
  28. public void run(BeanDefinitionRegistry registry) {
  29.  
  30. Set<Class<?>> scanPackage = ClassUtil.scanPackageByAnnotation("com.mysgk", MyHttpClient.class);
  31.  
  32. for (Class<?> cls : scanPackage) {
  33.  
  34. BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(cls);
  35. GenericBeanDefinition definition = (GenericBeanDefinition) builder.getRawBeanDefinition();
  36. definition.getPropertyValues().add("interfaceClass", definition.getBeanClassName());
  37. definition.setBeanClass(RibbonAopProxyFactory.class);
  38. definition.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_TYPE);
  39. String beanName = StrUtil.removePreAndLowerFirst(cls.getSimpleName(), 0) + "RibbonClient";
  40. registry.registerBeanDefinition(beanName, definition);
  41. }
  42.  
  43. }
  44.  
  45. @Override
  46. public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
  47. run(registry);
  48. }
  49.  
  50. @Override
  51. public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
  52.  
  53. }
  54.  
  55. @Override
  56. public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
  57. this.ctx = ctx;
  58. }
  59.  
  60.  
  61. }

四: 编写拦截器

  1. package com.mysgk.blogdemo.aop;
  2.  
  3. import org.aspectj.lang.ProceedingJoinPoint;
  4. import org.aspectj.lang.annotation.Around;
  5. import org.aspectj.lang.annotation.Aspect;
  6. import org.aspectj.lang.annotation.Pointcut;
  7. import org.springframework.beans.factory.annotation.Autowired;
  8. import org.springframework.http.HttpEntity;
  9. import org.springframework.http.HttpMethod;
  10. import org.springframework.http.ResponseEntity;
  11. import org.springframework.stereotype.Component;
  12. import org.springframework.web.client.RestTemplate;
  13. @Component
  14. @Aspect
  15. public class InterceptAnnotation {
  16.  
  17. @Autowired
  18. private RestTemplate ribbonLoadBalanced;
  19.  
  20. @Pointcut("@annotation(com.mysgk.blogdemo.annotation.MyHttpClient)")
  21. public void execute() {
  22.  
  23. }
  24.  
  25. @Around("execute()")
  26. public Object interceptAnnotation(ProceedingJoinPoint joinPoint) throws Throwable {
  27. /**
  28. * 此处省略 获取 url, httpMethod, requestEntity, responseType 等参数的处理过程
  29. */
  30. ResponseEntity<?> exchange = ribbonLoadBalanced.exchange("url", HttpMethod.GET, HttpEntity.EMPTY, Object.class);
  31. return exchange.getBody();
  32. }
  33.  
  34. }

五: 新建测试类

  1. package com.mysgk.blogdemo.client;
  2.  
  3. import com.mysgk.blogdemo.annotation.MyHttpClient;
  4. import org.springframework.web.bind.annotation.PostMapping;
  5. import org.springframework.web.bind.annotation.RequestBody;
  6.  
  7. @MyHttpClient
  8. public interface MyHttpClientTest {
  9.  
  10. @PostMapping(value = "test/t1")
  11. Object test(String param);
  12.  
  13. }

项目结构:

到此这篇关于spring boot 动态生成接口实现类的文章就介绍到这了,更多相关spring boot 接口实现类内容请搜索w3xue以前的文章或继续浏览下面的相关文章希望大家以后多多支持w3xue!

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号