企业网站设计专业好吗,东莞网站建制作,哪个电商平台最能卖货,2021年最新的网站文章目录 前言Openfeign实现思路前期准备基本依赖项 开始实现自定义注解自定义代理类定义创建代理对象的工厂InstantiationAwareBeanPostProcessor实现bean的注入OpenInstantiationAwareBeanPostProcessor 自定义 feign接口启动类小结 踩坑记录ImportComponent和Configuration区… 文章目录 前言Openfeign实现思路前期准备基本依赖项 开始实现自定义注解自定义代理类定义创建代理对象的工厂InstantiationAwareBeanPostProcessor实现bean的注入OpenInstantiationAwareBeanPostProcessor 自定义 feign接口启动类小结 踩坑记录ImportComponent和Configuration区别是什么 总结 前言
最近开发cloud项目里面涉及到服务间调用最后使用的openfeign解决的于是对于openfeign的底层原理有些兴趣了提前透露一下底层无非就是使用一些http调用的工具帮助我们实现了请求调用
Openfeign实现思路 前期准备
基本依赖项
首先创建一个springboot项目有一个发送请求的工具这里使用的ribbon dependencygroupIdorg.springframework.cloud/groupIdartifactIdspring-cloud-starter-netflix-ribbon/artifactIdversion2.2.9.RELEASE/versionscopecompile/scopeoptionaltrue/optional/dependency开始实现
自定义注解
创建两个自定义注解分别用于在启动类和接口上添加
Target(ElementType.TYPE)
Retention(RetentionPolicy.RUNTIME)
Configuration
Import(OpenInstantiationAwareBeanPostProcessor.class)//这个类重点注意
public interface EnableRemoteClient {
}Target(ElementType.TYPE)
Retention(RetentionPolicy.RUNTIME)
Component
public interface CustomProxy {String servie();String address();
}自定义代理类
代理类中有一个RestTemplate 用于发送请求
public class CustomProxyHandler implements InvocationHandler {RestTemplate restTemplatenew RestTemplate();Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//首先获取对象Class? declaringClass method.getDeclaringClass();//判断当前的被代理对象是否使用了自定的注解if(declaringClass.isAnnotationPresent(CustomProxy.class)){CustomProxy annotation declaringClass.getAnnotation(CustomProxy.class);String servie annotation.servie();String address annotation.address();String urladdressservie;RequestMapping annotation1 method.getAnnotation(RequestMapping.class);urlurlannotation1.value()[0];//判断请求方法是否入参if(args!nullargs.length!0){return restTemplate.getForObject(url,method.getReturnType(),args);}else {return restTemplate.getForObject(url,method.getReturnType());}}else{return null;}}
}定义创建代理对象的工厂
用于创建代理对象使用
public class ProxyFactory {/*** description: 创建具体的代理对象* author: * date: 2023/9/1 17:30* param: [targetInterface]* return: T**/public static T T createProxy(ClassT targetInterface) {return (T) Proxy.newProxyInstance(targetInterface.getClassLoader(),new Class[]{targetInterface},new CustomProxyHandler());}
}InstantiationAwareBeanPostProcessor实现bean的注入
InstantiationAwareBeanPostProcessor 是 Spring 框架提供的一个扩展接口它在 Spring 容器实例化 bean 之前和之后对 bean 进行处理。其主要功能如下 实例化前置处理Before Instantiation在 Spring 容器实例化 bean 之前可以通过这个接口来自定义 bean 的实例化方式。可以在此处进行一些特殊的准备工作比如使用自定义的实例化逻辑或者切入点的选择。 实例化后置处理After Instantiation在 Spring 容器实例化 bean 之后可以通过这个接口对实例化后的 bean 进行处理。可以在此处做一些初始化的操作比如对属性进行赋值、调用初始化方法等。 属性设置前置处理Before Property Set在 Spring 容器对 bean 的属性进行设置之前可以通过这个接口来自定义属性的设置方式。可以在此处对属性进行修改或者校验操作。 属性设置后置处理After Property Set在 Spring 容器对 bean 的属性进行设置之后可以通过这个接口对属性设置后的 bean 进行处理。可以在此处做一些属性设置后的额外操作。 初始化前置处理Before Initialization在 Spring 容器对 bean 进行初始化之前可以通过这个接口来自定义初始化的方式。可以在此处添加一些额外的初始化逻辑。 初始化后置处理After Initialization在 Spring 容器对 bean 进行初始化之后可以通过这个接口对初始化后的 bean 进行处理。可以在此处做一些初始化后的额外操作。
通过实现 InstantiationAwareBeanPostProcessor 接口并重写其中的方法可以在 Spring 容器实例化和初始化 bean 的各个阶段进行自定义处理从而灵活地对 bean 进行定制化的操作。
OpenInstantiationAwareBeanPostProcessor 自定义
public class OpenInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor, ApplicationContextAware {private ApplicationContext applicationContext;/*** 实例化前后面的方法可以不用看了* param beanClass* param beanName* return* throws BeansException*/Overridepublic Object postProcessBeforeInstantiation(Class? beanClass, String beanName) throws BeansException {log.info(正在为{}生成代理对象,被代理的类为{},beanName,beanClass.getName());if(!beanClass.isAnnotationPresent(CustomProxy.class)){return null;}//动态代理里面需要实现的方法本文采用的是jdk动态代理//返回代理对象Object object ProxyFactory.createProxy(beanClass);return object;}/*** 实例化后* param bean* param beanName* return* throws BeansException*/Overridepublic boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {return true;}Overridepublic PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {return pvs;}/*** 初始化钱* param bean* param beanName* return* throws BeansException*/Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {return bean;}/*** 初始化后* param bean* param beanName* return* throws BeansException*/Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {return bean;}Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContextapplicationContext;}
}feign接口
这里的servie没有参数是因为我的另一个服务中没有配置context-path如果你们自己的被调用的那个demo中有配置一定要加上哦
CustomProxy(servie ,address http://localhost:8082/)
public interface MyService {RequestMapping(value /QuerySubselect,method RequestMethod.GET)String test();
}启动类
SpringBootApplication
EnableRemoteClient
Import({MyService.class})//接口注册注意接口上面加Se
public class OpenfeignDemoApplication {public static void main(String[] args) {SpringApplication.run(OpenfeignDemoApplication.class, args);}}小结
这个版本的实现目前spring还不能识别我添加了注解的这个接口需要在启动类中使用Import注解手动配置所以还不完善不过后期会继续完善的目前博主也在学习这个这个思路就是基于我们正常的发送请求然后有一个人帮助我们去发送请求这个思路。
踩坑记录
Import
将接口 MyService 标识为 Import 的目的是为了在启动类中将该接口的实现类动态代理对象注册到 Spring 容器中。
当你使用 Import({MyService.class}) 注解时Spring 在启动时会扫描被注解的类并根据其类型进行相应的处理。在这种情况下MyService 类型是一个接口而不是一个具体的类。
由于接口无法直接实例化因此你需要在某处提供对 MyService 接口的实现类的创建逻辑。通常情况下使用动态代理是一种常见的方式。
动态代理是一种在运行时生成代理类的机制可以在不修改原始接口源代码的情况下通过代理类来增强接口的功能。你可以编写一个动态代理类实现 MyService 接口并在动态代理类中实现你所需的增强逻辑。
然后在启动类上使用 Import 注解并传入该动态代理类的类型告诉 Spring 在启动时需要将该动态代理类注册到容器中。
这样当其他组件需要使用 MyService 接口时Spring 容器会从容器中获取该接口的实例而实际上获得的是动态代理对象该代理对象会在实际调用接口方法时根据你的增强逻辑进行处理。
因为openfeign的标注的接口没有实现类所以需要这个Import注解帮助我们告诉spring容器可以去容器中去这个类型的代理对象目前还没有想到其他的方式不用使用Import注解声明的。后续再想想办法
Component和Configuration区别是什么
Configuration 注解不能直接添加到接口上因为 Configuration 注解是用于标识一个类为配置类的注解它主要用于定义和配置 Bean 对象以及其他的配置信息。 一开始使用这个注解导致使用了自定义注解的接口一直扫描不到后来修改为Component注解后就可以了。 Component 是 Spring Framework 中的一个核心注解之一用于将一个普通的 Java 类标识为一个可以被 Spring 自动扫描并管理的组件。
具体来说Component 注解可以应用于以下场景 Bean 的自动扫描和注册通过在类上添加 Component 注解Spring 容器会自动扫描并将该类作为 Bean 进行注册使得我们可以通过依赖注入等方式方便地使用该类的实例。 类型指定的自动装配当需要进行自动装配时Spring 容器会检测所有被 Component 注解标记的类并根据类型进行自动装配。
Component 注解是一个通用的注解如果对应的类有更具体的角色或作用还可以使用其他派生注解例如
Controller标识一个类是控制器Controller组件用于接收和处理用户请求。Service标识一个类是服务Service组件用于封装业务逻辑。Repository标识一个类是数据访问仓库Repository组件用于访问持久化数据。
这些派生注解都是基于 Component 注解的继承了 Component 的功能并且更明确地表示了对应类的角色和用途。
总结
对于这次去实现这么一个框架的小demo自己思考了一天不能说很长时间吧主要是因为对于spring中提供的一些扩展机制还不是很了解但是我相信它一定提供了能够解决我上面问题的一些api的只是我还没有发现而已。对于这些技术的应用底层原理还是很简单的可以发现无非就是没让你做的事情有人帮你做了这么一个过程只不过这个过程被人封装起来以后就是一个技术或者一个框架了。