在线不卡日本ⅴ一区v二区_精品一区二区中文字幕_天堂v在线视频_亚洲五月天婷婷中文网站

  • <menu id="lky3g"></menu>
  • <style id="lky3g"></style>
    <pre id="lky3g"><tt id="lky3g"></tt></pre>

    基于Spring實(shí)現(xiàn)策略模式

    基于Spring實(shí)現(xiàn)策略模式

    背景:

      看多很多策略模式,總結(jié)下來(lái)實(shí)現(xiàn)原理大體都差不多,在這里主要是講解下自己基于Spring更優(yōu)雅的實(shí)現(xiàn)方案;這個(gè)方案主要是看了一些開源rpc和Spring相關(guān)源碼后的一些思路,所以在此進(jìn)行總結(jié)

    首先看下比較常見的策略模式寫法

    • 一個(gè)接口或者抽象類,里面兩個(gè)方法(一個(gè)方法匹配類型,一個(gè)可替換的邏輯實(shí)現(xiàn)方法)
    • 不同策略的差異化實(shí)現(xiàn)(就是說(shuō),不同策略的實(shí)現(xiàn)類)
    • 使用策略模式

    1.3.1 一個(gè)接口,兩個(gè)方法

    public interface IFileStrategy { //屬于哪種文件解析類型 FileTypeResolveEnum gainFileType(); //封裝的公用算法(具體的解析方法) void resolve(Object objectparam);}

    1.3.2 不同策略的差異化實(shí)現(xiàn)

    A 類型策略具體實(shí)現(xiàn)

    @Componentpublic class AFileResolve implements IFileStrategy { @Override public FileTypeResolveEnum gainFileType() { return FileTypeResolveEnum.File_A_RESOLVE; } @Override public void resolve(Object objectparam) { logger.info(“A 類型解析文件,參數(shù):{}”,objectparam); //A類型解析具體邏輯 }}

    B 類型策略具體實(shí)現(xiàn)

    @Componentpublic class BFileResolve implements IFileStrategy { @Override public FileTypeResolveEnum gainFileType() { return FileTypeResolveEnum.File_B_RESOLVE; } @Override public void resolve(Object objectparam) { logger.info(“B 類型解析文件,參數(shù):{}”,objectparam); //B類型解析具體邏輯 }}

    默認(rèn)類型策略具體實(shí)現(xiàn)

    @Componentpublic class DefaultFileResolve implements IFileStrategy { @Override public FileTypeResolveEnum gainFileType() { return FileTypeResolveEnum.File_DEFAULT_RESOLVE; } @Override public void resolve(Object objectparam) { logger.info(“默認(rèn)類型解析文件,參數(shù):{}”,objectparam); //默認(rèn)類型解析具體邏輯 }}

    1.3.3 使用策略模式

    如何使用呢?我們借助spring的生命周期,使用ApplicationContextAware接口,把對(duì)用的策略,初始化到map里面。然后對(duì)外提供resolveFile方法即可。

    /** * */@Componentpublic class StrategyUseService implements ApplicationContextAware{ private Map iFileStrategyMap = new ConcurrentHashMap(); public void resolveFile(FileTypeResolveEnum fileTypeResolveEnum, Object objectParam) { IFileStrategy iFileStrategy = iFileStrategyMap.get(fileTypeResolveEnum); if (iFileStrategy != null) { iFileStrategy.resolve(objectParam); } } //把不同策略放到map @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { Map tmepMap = applicationContext.getBeansOfType(IFileStrategy.class); tmepMap.values().forEach(strategyService -> iFileStrategyMap.put(strategyService.gainFileType(), strategyService)); }}


    基于Spring服務(wù)策略實(shí)現(xiàn)

          稍微了解過(guò)Spring源碼都知道,在Spring里面我們定義好的bean被@Autowired修飾后,實(shí)際這個(gè)bean是被Spring進(jìn)行了統(tǒng)一管理,當(dāng)需要調(diào)用的時(shí)候?qū)嶋H是從Spring工廠里拿到這個(gè)bean;所以大致思路就是在如何拿到bean之前注入一個(gè)代理類,讓代理類根據(jù)元數(shù)據(jù)的一些自定義規(guī)則后去組裝成一個(gè)能從Spring里拿到實(shí)際的bean元素;基于以上的思路進(jìn)行編碼如下注解定義

    • 自定義一個(gè)@RouteBizService注解(作用可以理解為@Autowired)

    @Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})@Retention(RetentionPolicy.RUNTIME)public @interface RouteBizService { String serviceName();}

    • 自定義一個(gè)@RouteBizParam參數(shù)注解,用于給代理類組裝實(shí)際beanName

    @Target(ElementType.PARAMETER)@Retention(RetentionPolicy.RUNTIME)public @interface RouteBizParam {}

    • 定義一個(gè)代理類:RouteServiceProxy

    /** * */package com.gitee.adapter.proxy;import org.springframework.context.ApplicationContext;import java.lang.annotation.Annotation;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;public class RouteServiceProxy implements InvocationHandler{ private String serviceName; private ApplicationContext context; public RouteServiceProxy(String serviceName, ApplicationContext context) { this.serviceName = serviceName; this.context = context; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String routeCode = null; Annotation[ /* 參數(shù)個(gè)數(shù)索引 */][ /* 注解個(gè)數(shù)索引 */ ] paramsAnno = method.getParameterAnnotations(); if (paramsAnno != null) { for (int i = 0; i 0) { routeCode = (String) args[i]; // 獲取到路由的參數(shù)值 break; } } } return method.invoke(context.getBean(genBeanName(routeCode, serviceName)), args); } /** * * @param sellerCode 用于區(qū)分是哪個(gè)Service 編碼 * @param interfaceSimpleName 服務(wù)接口 * @return */ private String genBeanName(String sellerCode, String interfaceSimpleName) { return new StringBuilder(sellerCode.toLowerCase()).append(interfaceSimpleName).toString(); }}

    View Code

    • 基于BeanFactoryPostProcessor 定義一個(gè)用于掃描 @RouteBizService修飾的實(shí)現(xiàn)類,該類的作用是為了注入代理類

    package com.gitee.adapter.spring;import com.gitee.adapter.annation.RouteBizService;import com.gitee.adapter.proxy.RouteServiceProxy;import org.springframework.beans.BeansException;import org.springframework.beans.factory.config.BeanDefinition;import org.springframework.beans.factory.config.BeanFactoryPostProcessor;import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;import org.springframework.context.ApplicationContext;import org.springframework.context.ApplicationContextAware;import org.springframework.core.annotation.AnnotationUtils;import org.springframework.util.ClassUtils;import org.springframework.util.ReflectionUtils;import java.lang.reflect.Proxy;/** * @Classname BizRouteServiceProcessor * @Description bean 后置處理器 獲取所有bean * 判斷bean字段是否被 {@link com.gitee.adapter.annation.RouteBizService } 注解修飾 */public class BizRouteServiceProcessor implements BeanFactoryPostProcessor, ApplicationContextAware { private ApplicationContext applicationContext; @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) { BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanDefinitionName); String beanClassName = beanDefinition.getBeanClassName(); if (beanClassName != null) { Class clazz = ClassUtils.resolveClassName(beanClassName, this.getClass().getClassLoader()); ReflectionUtils.doWithFields(clazz, field -> { RouteBizService routeBizService = AnnotationUtils.getAnnotation(field, RouteBizService.class); if (routeBizService != null) { Object bean = applicationContext.getBean(clazz); field.setAccessible(true); // 修改為代理對(duì)象 ReflectionUtils.setField(field, bean, Proxy.newProxyInstance(field.getType().getClassLoader(), new Class[] { field.getType() }, new RouteServiceProxy(routeBizService.serviceName(),this.applicationContext))); } }); } } } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; }}

    View Code

    測(cè)試

    環(huán)境搭建

    • 操作系統(tǒng):Windows
    • 集成開發(fā)工具:IntelliJ IDEA 2021
    • 項(xiàng)目技術(shù)棧:SpringBoot 2.2.11 + JDK 1.8
    • 項(xiàng)目依賴管理工具:Maven 4.0.0

    小伙伴們有興趣想了解內(nèi)容和更多相關(guān)學(xué)習(xí)資料的請(qǐng)點(diǎn)贊收藏+評(píng)論轉(zhuǎn)發(fā)+關(guān)注我,后面會(huì)有很多干貨。

    我有一些面試題、架構(gòu)、設(shè)計(jì)類資料可以說(shuō)是程序員面試必備!所有資料都整理到網(wǎng)盤了,需要的話歡迎下載!私信我回復(fù)【07】即可免費(fèi)獲取

    原文出處:www.shaoqun.com/a/1437729.html

    鄭重聲明:本文內(nèi)容及圖片均整理自互聯(lián)網(wǎng),不代表本站立場(chǎng),版權(quán)歸原作者所有,如有侵權(quán)請(qǐng)聯(lián)系管理員(admin#wlmqw.com)刪除。
    (0)
    用戶投稿
    上一篇 2022年6月18日 19:00
    下一篇 2022年6月18日 19:01

    相關(guān)推薦

    聯(lián)系我們

    聯(lián)系郵箱:admin#wlmqw.com
    工作時(shí)間:周一至周五,10:30-18:30,節(jié)假日休息