spring?boot?動態(tài)生成接口實(shí)現(xiàn)類的場景分析
在某些業(yè)務(wù)場景中,我們只需要業(yè)務(wù)代碼中定義相應(yīng)的接口或者相應(yīng)的注解,并不需要實(shí)現(xiàn)對應(yīng)的邏輯。
比如 mybatis和feign: 在 mybatis 中,我們只需要定義對應(yīng)的mapper接口;在 feign 中,我們只需要定義對應(yīng)業(yè)務(wù)系統(tǒng)中的接口即可。
那么在這種場景下,具體的業(yè)務(wù)邏輯時怎么執(zhí)行的呢,其實(shí)原理都是動態(tài)代理。
我們這里不具體介紹動態(tài)代理,主要看一下它在springboot項(xiàng)目中的實(shí)際應(yīng)用,下面我們模仿feign來實(shí)現(xiàn)一個調(diào)用三方接口的 httpclient。
一: 定義注解
package com.mysgk.blogdemo.annotation; public @interface MyHttpClient { }
二: 建立動態(tài)代理類
package com.mysgk.blogdemo.proxy; import org.springframework.beans.factory.FactoryBean; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class RibbonAopProxyFactory<T> implements FactoryBean<T>, InvocationHandler { private Class<T> interfaceClass; public Class<T> getInterfaceClass() { return interfaceClass; } public void setInterfaceClass(Class<T> interfaceClass) { this.interfaceClass = interfaceClass; } @Override public T getObject() throws Exception { return (T) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{interfaceClass}, this); } @Override public Class<?> getObjectType() { return interfaceClass; } @Override public boolean isSingleton() { return true; } /** 真正執(zhí)行的方法 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return "invoke " + proxy.getClass().getName() + "." + method.getName() + " , do anything .."; } }
三: 注入spring容器
package com.mysgk.blogdemo.start; import cn.hutool.core.util.ClassUtil; import cn.hutool.core.util.StrUtil; import com.mysgk.blogdemo.annotation.MyHttpClient; import com.mysgk.blogdemo.proxy.RibbonAopProxyFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; import org.springframework.beans.factory.support.GenericBeanDefinition; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; import java.util.Set; @Component public class ScanHttpClients implements BeanDefinitionRegistryPostProcessor, ApplicationContextAware { private final Logger logger = LoggerFactory.getLogger(ScanHttpClients.class); private ApplicationContext ctx; public void run(BeanDefinitionRegistry registry) { Set<Class<?>> scanPackage = ClassUtil.scanPackageByAnnotation("com.mysgk", MyHttpClient.class); for (Class<?> cls : scanPackage) { BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(cls); GenericBeanDefinition definition = (GenericBeanDefinition) builder.getRawBeanDefinition(); definition.getPropertyValues().add("interfaceClass", definition.getBeanClassName()); definition.setBeanClass(RibbonAopProxyFactory.class); definition.setAutowireMode(GenericBeanDefinition.AUTOWIRE_BY_TYPE); String beanName = StrUtil.removePreAndLowerFirst(cls.getSimpleName(), 0) + "RibbonClient"; registry.registerBeanDefinition(beanName, definition); } } @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { run(registry); } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.ctx = ctx; } }
四: 編寫攔截器
package com.mysgk.blogdemo.aop; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpEntity; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; import org.springframework.web.client.RestTemplate; @Component @Aspect public class InterceptAnnotation { @Autowired private RestTemplate ribbonLoadBalanced; @Pointcut("@annotation(com.mysgk.blogdemo.annotation.MyHttpClient)") public void execute() { } @Around("execute()") public Object interceptAnnotation(ProceedingJoinPoint joinPoint) throws Throwable { /** * 此處省略 獲取 url, httpMethod, requestEntity, responseType 等參數(shù)的處理過程 */ ResponseEntity<?> exchange = ribbonLoadBalanced.exchange("url", HttpMethod.GET, HttpEntity.EMPTY, Object.class); return exchange.getBody(); } }
五: 新建測試類
package com.mysgk.blogdemo.client; import com.mysgk.blogdemo.annotation.MyHttpClient; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @MyHttpClient public interface MyHttpClientTest { @PostMapping(value = "test/t1") Object test(String param); }
項(xiàng)目結(jié)構(gòu):
到此這篇關(guān)于spring boot 動態(tài)生成接口實(shí)現(xiàn)類的文章就介紹到這了,更多相關(guān)spring boot 接口實(shí)現(xiàn)類內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java static(靜態(tài)變量)和私有化功能與用法分析
這篇文章主要介紹了Java static(靜態(tài)變量)和私有化功能與用法,結(jié)合具體實(shí)例形式分析了Java static(靜態(tài)變量)和私有化的相關(guān)概念、原理、使用方法及操作注意事項(xiàng),需要的朋友可以參考下2019-07-07SpringBoot使用JPA實(shí)現(xiàn)查詢部分字段
這篇文章主要介紹了SpringBoot使用JPA實(shí)現(xiàn)查詢部分字段方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-08-08mybatis中insert主鍵ID獲取和多參數(shù)傳遞的示例代碼
這篇文章主要介紹了mybatis中insert主鍵ID獲取和多參數(shù)傳遞的示例代碼,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-03-03OpenFeign設(shè)置header的三種方式總結(jié)
在微服務(wù)間使用Feign進(jìn)行遠(yuǎn)程調(diào)用時需要在header中添加信息,下面這篇文章主要給大家介紹了關(guān)于OpenFeign設(shè)置header的三種方式,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-04-04java并發(fā)編程關(guān)鍵字volatile保證可見性不保證原子性詳解
這篇文章主要為大家介紹了java并發(fā)編程關(guān)鍵字volatile保證可見性不保證原子性詳解,文中附含詳細(xì)示例說明,有需要的朋友可以借鑒參考下,希望能夠有所幫助2022-02-02詳解在Spring-Boot中實(shí)現(xiàn)通用Auth認(rèn)證的幾種方式
這篇文章主要介紹了詳解在Spring-Boot中實(shí)現(xiàn)通用Auth認(rèn)證的幾種方式,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-07-07基于線程的wait和notify使用,生產(chǎn)消費(fèi)案例
這篇文章主要介紹了基于線程的wait和notify使用,生產(chǎn)消費(fèi)案例,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-08-08