文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Springboot插件如何开发

2023-06-30 16:09

关注

本篇内容主要讲解“Springboot插件如何开发”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Springboot插件如何开发”吧!

一 背景

项目新增监控系统,对各个系统进行监控接口调用情况,初期的时候是在各个项目公共引用的依赖包里面新增aop切面来完成对各个系统的接口调用进行监控,但是这样有缺点,一是不同项目的接口路径不同,导致aop切面要写多个切面路径,二是一些不需要进行监控的系统,因为引入了公共包也被监控了,这样侵入性就太强了。为了解决这个问题,就可以通过springboot的可插拔属性了。

二 监控日志插件开发

1 新建aop切面执行类MonitorLogInterceptor

@Slf4jpublic class MonitorLogInterceptor extends MidExpandSpringMethodInterceptor<MonitorAspectAdviceProperties> {   @Override   public Object invoke(MethodInvocation methodInvocation) throws Throwable {       Object result = null;       HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();       //拿到请求的url       String requestURI = request.getRequestURI();       if (StringUtils.isEmpty(requestURI)) {           return result;       }       try {           result = methodInvocation.proceed();       } catch (Exception e) {           buildRecordData(methodInvocation, result, requestURI, e);           throw e;       }       //参数数组       buildRecordData(methodInvocation, result, requestURI, null);       return result;

我们可以看到它实现了MidExpandSpringMethodInterceptor<T>

@Slf4jpublic abstract class MidExpandSpringMethodInterceptor<T> implements MethodInterceptor {    @Setter    @Getter    protected T properties;        protected String getExpression() {        return null;    }    @SuppressWarnings({"unchecked"})    public AbstractBeanDefinition doInitiativeRegister(Properties properties) {        String expression = StringUtils.isNotBlank(this.getExpression()) ? this.getExpression() : properties.getProperty("expression");        if (StringUtils.isBlank(expression)) {            log.warn("中台SpringAop插件 " + this.getClass().getSimpleName() + " 缺少对应的配置文件 或者 是配置的拦截路径为空 导致初始化跳过");            return null;        }        BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(AspectJExpressionPointcutAdvisor.class);        this.setProperties((T) JsonUtil.toBean(JsonUtil.toJson(properties), getProxyClassT()));        definition.addPropertyValue("advice", this);        definition.addPropertyValue("expression", expression);        return definition.getBeanDefinition();    }        private Class<?> getProxyClassT() {        Type genericSuperclass = this.getClass().getGenericSuperclass();        ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;        return (Class<?>) parameterizedType.getActualTypeArguments()[0];    }}

而最终是实现了MethodInterceptor,这个接口是 方法拦截器,用于Spring AOP编程中的动态代理.实现该接口可以对需要增强的方法进行增强.

我们注意到我的切面执行类并没有增加任何@Compont和@Service等将类注入到spring的bean中的方法,那他是怎么被注入到bean中的呢,因为使用了spi机制

SPI机制的实现在项目的资源文件目录中,增加spring.factories文件,内容为

com.dst.mid.common.expand.springaop.MidExpandSpringMethodInterceptor=\
  com.dst.mid.monitor.intercept.MonitorLogInterceptor

这样就可以在启动过程直接被注册,并且被放到spring容器中了。还有一个问题就是,切面执行类有了,切面在哪里呢。

@Configuration@Slf4j@Import(MidExpandSpringAopAutoStarter.class)public class MidExpandSpringAopAutoStarter implements ImportBeanDefinitionRegistrar {    private static final String BEAN_NAME_FORMAT = "%s%sAdvisor";    private static final String OS = "os.name";    private static final String WINDOWS = "WINDOWS";    @SneakyThrows    @SuppressWarnings({"rawtypes"})    @Override    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {        // 1 获取MidExpandSpringMethodInterceptor类的所有实现集合        List<MidExpandSpringMethodInterceptor> list = SpringFactoriesLoader.loadFactories(MidExpandSpringMethodInterceptor.class, null);        if (!CollectionUtils.isEmpty(list)) {            String expandPath;            Properties properties;            BeanDefinition beanDefinition;            // 2 遍历类的所有实现集合            for (MidExpandSpringMethodInterceptor item : list) {                // 3 获取资源文件名称 资源文件中存储需要加入配置的                expandPath = getExpandPath(item.getClass());                // 4 加载资源文件                properties = PropertiesLoaderUtils.loadAllProperties(expandPath + ".properties");                // 5 赋值beanDefinition为AspectJExpressionPointcutAdvisor                if (Objects.nonNull(beanDefinition = item.doInitiativeRegister(properties))) {                    // 6 向容器中注册类  注意这个beanname是不存在的,但是他赋值beanDefinition为AspectJExpressionPointcutAdvisor是动态代理动态生成代理类所以不会报错                    registry.registerBeanDefinition(String.format(BEAN_NAME_FORMAT, expandPath, item.getClass().getSimpleName()), beanDefinition);                }            }        }    }        private static String getExpandPath(Class<?> clazz) {        String[] split = clazz.getProtectionDomain().getCodeSource().getLocation().getPath().split("/");        if (System.getProperty(OS).toUpperCase().contains(WINDOWS)) {            return split[split.length - 3];        } else {            return String.join("-", Arrays.asList(split[split.length - 1].split("-")).subList(0, 4));        }    }}

这个就是切面注册类的处理,首先实现了ImportBeanDefinitionRegistrar,实现他的registerBeanDefinitions方法可以将想要注册的类放入spring容器中,看下他的实现

看到这里,还有一个问题ImportBeanDefinitionRegistrar实际上是将类注册到容器中,但是还需要一个步骤就是他要被容器扫描才行,以往的方式是项目中通过路径扫描,但是我们是插件,不能依赖于项目,而是通过自己的方式处理,这时候就需要用@Import(MidExpandSpringAopAutoStarter.class)来处理了。

通过以上处理就实现了监控插件的处理,然后再使用时,只需要将这个项目引入到不同需要监控的项目上就可以了。

到此,相信大家对“Springboot插件如何开发”有了更深的了解,不妨来实际操作一番吧!这里是编程网网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯