使用自定义注解发布webservice服务

2023-09-20 18:09:17

概要

在springboot使用webservice,发布webservice服务的时候,我们经常需要手动在添加一些发布的代码,比如:

@Bean
public Endpoint organizationEndpoint() {
    EndpointImpl endpoint = new EndpointImpl(bus, organizationProvider);
    endpoint.publish("/organization");
    //在服务端添加日志拦截器。
    endpoint.getInInterceptors().add(new LoggingInInterceptor());
    endpoint.getOutInterceptors().add(new LoggingOutInterceptor());
    return endpoint;
}

每写一个服务就要发布一次,上面的代码就要重复一次,如是就想把这重复的代码通过注解的形式来简化,下面是具体实现。

代码

自定义注解

/**
 * 自定义发布webservice服务注解
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface WsEndpoint {

    @NotNull
    @AliasFor("name")
    String value() default "";
}

WebService接口服务发布配置


/**
 * 负责发布WebService服务的配置
 *
 * 该方法通过WsEndpoint自定义注解来进行统一发布webservice服务
 * 下方注释部分为正常写法的示例
 */
@Configuration
@Slf4j
public class CxfConfig implements CommandLineRunner, ApplicationContextAware, BeanDefinitionRegistryPostProcessor{
    private ApplicationContext applicationContext;
    private ConfigurableListableBeanFactory beanFactory;



    /*@Autowired
    private Bus bus;
    @Resource
    private OrganizationProvider organizationProvider;
    */


    /**
     * 发布 机构endpoint
     *
     * @return
     */
   /* @Bean
    public Endpoint organizationEndpoint() {
        EndpointImpl endpoint = new EndpointImpl(bus, organizationProvider);
        endpoint.publish("/organization");
        //在服务端添加日志拦截器。后续还有更好的方法。
        endpoint.getInInterceptors().add(new LoggingInInterceptor());
        endpoint.getOutInterceptors().add(new LoggingOutInterceptor());
        return endpoint;
    }*/



    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {

    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        // 拿到bean工厂对象
        this.beanFactory = configurableListableBeanFactory;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        // 拿到上下文对象
        this.applicationContext = applicationContext;
    }


    /**
     * 项目启动完成后发布webservice服务,在项目没有启动完成前,
     * 由于bean依赖之类的还没有注入,提前从上下文对象中拿到相关bean发布webservice服务可能会引发依赖问题。
     * @param args
     * @throws Exception
     */
    @Override
    public void run(String... args) throws Exception {
        log.info("===============================..................   springboot启动完成,发布webservice服务 ...");
        try {
            Bus bus = applicationContext.getBean(Bus.class);
            // 拿到标记了webservice注解的bean
            String[] beanNamesForAnnotation = applicationContext.getBeanNamesForAnnotation(WebService.class);
            if (null == beanNamesForAnnotation || beanNamesForAnnotation.length == 0) {
                return;
            }
            // 需要发布的webservice服务
            for (String beanName : beanNamesForAnnotation) {
                Object bean = applicationContext.getBean(beanName);
                // 解析自定义注解并拿到值
                String path = analyzeClassAndInterfaceAnnotation(bean.getClass());
                if (StringUtils.isBlank(path)) {
                    // 没有标记自定义注解的webservice服务不会发布
                    continue;
                }
                EndpointImpl endpoint = new EndpointImpl(bus, bean);
                endpoint.publish(path);
                //在服务端添加日志拦截器。后续还有更好的方法。
                endpoint.getInInterceptors().add(new LoggingInInterceptor());
                //返回200时,会记录下返回的SOAP报文。但未能返回200时,看上去记录的依然是输入时的SOAP报文
                endpoint.getOutInterceptors().add(new LoggingOutInterceptor());
                beanFactory.registerSingleton(path, endpoint);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    /**
     * 判断当前类及其实现的接口上是否有自定义注解,并且拿到自定义注解的值
     *
     * @param aClass
     */
    private String analyzeClassAndInterfaceAnnotation(Class<?> aClass) {
        // 判断当前类上是否有自定义注解
        Annotation[] annotations = aClass.getAnnotations();
        for (Annotation annotation : annotations) {
            if (annotation instanceof WsEndpoint) {
                return ((WsEndpoint) annotation).value();
            }
        }
        // 判断实现的接口上是否有自定义注解
        Class<?>[] interfaces = aClass.getInterfaces();
        if (null == interfaces || interfaces.length == 0) {
            return null;
        }
        for (Class<?> anInterface : interfaces) {
            Annotation[] interfaceAnnotations = anInterface.getAnnotations();
            if (null == interfaceAnnotations || interfaceAnnotations.length == 0) {
                continue;
            }
            for (Annotation interfaceClassAnnotation : interfaceAnnotations) {
                if (interfaceClassAnnotation instanceof WsEndpoint) {
                    return ((WsEndpoint) interfaceClassAnnotation).value();
                }
            }
        }
        return null;
    }
}

使用

@WebService(targetNamespace = "http://www.chiss.org.cn/rhin/2015", name = "OrganizationProvider")
@XmlSeeAlso({ObjectFactory.class})
@WsEndpoint("organization")  // 使用自定义注解发布webservice服务接口
public interface OrganizationProvider {

    /**
     * 机构注册
     *
     * @param message
     * @return
     * @throws SOAPException
     */
    @WebMethod(operationName = "OrganizationFeed", action = "OrganizationFeed")
    @SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
    @WebResult(name = "OrganizationFeedResponse", targetNamespace = "http://www.chiss.org.cn/rhin/2015", partName = "message")
    public OrganizationFeedResponse organizationFeed(
            @WebParam(partName = "message", name = "OrganizationFeed", targetNamespace = "http://www.chiss.org.cn/rhin/2015")
                    OrganizationFeed message
    ) throws SOAPException;

    /**
     * 机构分页查询
     *
     * @param message
     * @return
     */
    @WebMethod(operationName = "OrganizationQuery", action = "OrganizationQuery")
    @SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
    @WebResult(name = "OrganizationQueryResponse", targetNamespace = "http://www.chiss.org.cn/rhin/2015", partName = "message")
    public OrganizationQueryResponseMessage organizationQuery(
            @WebParam(partName = "message", name = "OrganizationQuery", targetNamespace = "http://www.chiss.org.cn/rhin/2015")
                    OrganizationQueryRequest message
    ) throws SOAPException;

}

结果

springboot启动完成后进行webservice服务接口发布
在这里插入图片描述
发布后的接口
在这里插入图片描述

更多推荐

机器学习 day35(决策树)

决策树上图的数据集是一个特征值X采用分类值,即只取几个离散值,同时也是一个二元分类任务,即标签Y只有两个值上图为之前数据集对应的决策树,最顶层的节点称为根节点,椭圆形节点称为决策节点,矩形节点称为叶子节点决策树学习算法的工作是,在所有可能的决策树中,选择一个在训练集上能表现良好,并能很好的推广到新数据(即交叉验证集和测

CUDA小白 - NPP(9) 图像处理 Statistical Operations

cuda小白原始API链接NPPGPU架构近些年也有不少的变化,具体的可以参考别的博主的介绍,都比较详细。还有一些cuda中的专有名词的含义,可以参考《详解CUDA的Context、Stream、Warp、SM、SP、Kernel、Block、Grid》常见的NppStatus,可以看这里。本文主要介绍的是NPP的统计

今天开课,欢迎学习!公益课“14天学会统计学与SPSS”,课程结束赠送全套视频...

新一期的课程今天开课!来学习吧!我们精心整理的600页彩色纸质版教程就可以帮助你更好得掌握本课程!“14天学会医学统计学与SPSS”,是浙江中医药大学医学统计教研室、浙江省预防医学会卫生统计学专业委员会共同主持的公益网课!不是忽悠人的商业收费课程!高校公开课,免费的!自2021年起,浙江中医药大学医学统计教研室教研书主

【ijkplayer】编译 Android 版本的 ijkplayer ⑦ ( 使用 AS 打开源码 | 重新设置 AGP 和 Gradle 版本号 | 设置依赖仓库 | 设置依赖 | 编译运行 )

文章目录一、AndroidStudio打开编译后的ijkplayer源码二、重新设置AndroidGradle插件版本号和Gradle构建工具版本号三、设置依赖仓库1、取消jcenter仓库2、添加google和mavenCentral仓库3、添加阿里云仓库四、取消jcenter上传相关插件五、设置编译工具版本号六、取

Tomcat调优【精简版】

Tomcat调优优化Tomcat内存分配调整Tomcat启动脚本contalina.sh,设置tomcat启动时分配的内存很可使用的最大内存;CATALINA_OPTS调整Tomcat线程池Tomcat默认使用的线程池:ThreadPoolExecutor可以通过修改server.xml的Connector节点下的ma

在Android Studio中,如何通过CMake 配置文件来实现多个动态依赖库的编译?

在AndroidStudio中,如何通过CMake配置文件来实现多个动态依赖库的编译?Author:LycanNote:以下问题解答通过大模型生成,主要用于个人学习和备忘,仅供参考,若有错误或者侵权,请联系我修正,谢谢。问题在AndroidStudio中,如何通过CMake配置文件来实现多个动态依赖库的编译?请一步一步

离散高斯抽样(Discrete Gaussian Sampling)

离散高斯抽样离散高斯抽样(DiscreteGaussianSampling)是一种常见于密码学和数学领域的随机采样方法。它通常用于构建基于格(lattice)的密码学方案,如基于格的加密和数字签名。DiscreteGaussianSampling的主要目的是从一个离散的集合中随机选择元素,同时遵循高斯分布(Gaussi

C# 随机数生成 Mersenne Twister 马特赛特旋转演算法 梅森旋转算法

NuGet安装MathNet.Numerics引用:usingMathNet.Numerics.Random;///<summary>///包括lower,不包括upper///</summary>///<paramname="lower"></param>///<paramname="upper"></param>/

vue3 的CreateApp

🎬岸边的风:个人主页🔥个人专栏:《VUE》《javaScript》⛺️生活的理想,就是为了理想的生活!目录从一个例子开始从一个例子开始constHelloVueApp={data(){return{message:'HelloVue!'}}}Vue.createApp(HelloVueApp).mount('#he

【Acorn】JS解析器编译原理

Acorn是什么?Acorn是一个用JavaScript编写的解析器,专门用于将源代码解析为抽象语法树(AbstractSyntaxTree,AST)。它是一个轻量级、高性能的解析器,被广泛应用于许多JavaScript工具和框架中。Acorn的整体工作流程输入源代码(InputSourceCode):接收JavaSc

虚拟列表 - Vue3实现一个可动态改变高度的虚拟滚动列表

虚拟列表-Vue3实现一个可动态改变高度的虚拟滚动列表前言在开发中经常遇到大量的渲染列表数据问题,往往我们就只是简单地遍历渲染,没有过多地去关注是否会存在性能问题,这导致如果数据量较大的时候,比如上万条数据,将会在dom中渲染上万个节点,这将加大浏览器的开销,可能会导致页面卡顿,加载慢等性能问题。因此,在渲染大量数据时

热文推荐