记springboot集成webservice接口后对接口进行aop切面日志管理问题

本文介绍了如何通过AOP切面简化JAX-WS WebService的日志记录,并解决服务实例化问题,以实现Spring管理的单例WorkflowEngineService。作者详细记录了解决过程和关键代码片段,包括切面配置和依赖管理。

1. 已通过jax生成客户端代码

/**
 * This class was generated by the JAX-WS RI.
 * JAX-WS RI 2.2.9-b130926.1035
 * Generated source version: 2.2
 * 
 */
@WebService(name = "WorkflowEngineService", targetNamespace = "http://cxf.workflow.dhcc.com/")
@XmlSeeAlso({
    ObjectFactory.class
})
@EndpointProperties({
    @EndpointProperty(key = "set-jaxb-validation-event-handler", value ="false")
})
@Service
public interface WorkflowEngineService {
    ...
}

2. 因之前接口调用日志记录太过繁琐累赘(每个方法都有重复的这一段日志记录代码), 遂想要通过aop切面进行日志记录

   /**
     * 先获取用户可起草的流程列表,如果此用户有可起草流程则返回结果,否则返回空报文。
     */
    @Override
    public List<DraftFlowEntityCXF> getToDraftList(String employeeNumber) {
        // workflowEngineService = WorkflowEngineServiceFactory.getWorkFlowEngine();

        //调用服务
        ResquestEntity resquestEntity = new ResquestEntity();
        resquestEntity.setEmployeeNumber(employeeNumber);
        log.info("开始调用接口:获取用户可起草的流程列表");
        log.info("请求方法为:" + "getToDraftList(resquestEntity)");
        log.info("请求参数为:" + JSON.toJSONString(resquestEntity));
        long startTime = System.currentTimeMillis();
        DraftFlowEntityCXF result = workflowEngineService.getToDraftList(resquestEntity);
        long endTime = System.currentTimeMillis();
        log.info("接口返回信息为:" + JSON.toJSONString(result));
        log.info("消耗时间:" + (endTime - startTime));
        List<DraftFlowEntityCXF> reslist = result.getMessage().getResponse().getList();
        return reslist;
    }

3. 创建切面类,切入类方法进行日志管理

package com.metarnet.kpi.ws.client.engine.aspect;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

/**
 * @author wangyj
 * @className WorkFlowLogAspect
 * @description 统一工作流引擎调用日志记录
 * @date 21/8/25
 */
@Aspect
@Component
@Slf4j
public class WorkFlowLogAspect {

    /**
     * 定义切入点,切入点为com.example.aop下的所有函数
     * com.metarnet.kpi.ws.client.engine.WorkFlowEngineServiceImpl
     */
    @Pointcut("execution(public * com.metarnet.kpi.ws.client.engine.WorkflowEngineService.*(..)))")
    public void workFlowLog(){}

    /**
     * 前置通知:在连接点之前执行的通知
     * @param joinPoint
     * @throws Throwable
     */
    @Before("workFlowLog()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
        // 接收到请求,记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        log.info("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        // ...日志记录代码段...
    }

}

这里出现了问题:

service接口调用时没有进入切面类中,通过一番搜索,猜想发现webservice接口是每次用时直接new一个新对象,并不交给spring容器管理,所以切面不生效

解决思考:

创建简单工厂配置类(这儿有些杂乱,都是当时尝试解决办法时遗留,懒得改了),创建一个单例service(这里其实是假单例,只是参考了单例模式,实际使用并不成熟),交给spring管理

交给spring管理后即可正常注入和进行aop切入了

package com.metarnet.kpi.ws.client.engine.config;

import com.metarnet.kpi.ws.client.engine.AddSoapHeader;
import com.metarnet.kpi.ws.client.engine.WorkflowEngineService;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

/**
 * @author wangyj
 * @className WorkflowEngineServiceFactory
 * @description 工作流引擎接口服务工厂类
 * @date 21/8/16
 */
@Configuration
public class WorkflowEngineServiceFactory {

    private static final JaxWsProxyFactoryBean FACTORY_BEAN = new JaxWsProxyFactoryBean();

    private static WorkflowEngineService workflowEngineService;

    @Bean
    @DependsOn("workFlowConfig")
    public static WorkflowEngineService getWorkFlowEngine(){

        if(workflowEngineService == null){

            FACTORY_BEAN.setServiceClass(WorkflowEngineService.class);
            FACTORY_BEAN.setAddress(WorkFlowConfig.getWorkFlowAddress());

            // 加入自定义的拦截器
            FACTORY_BEAN.getOutInterceptors().add(new AddSoapHeader());
            workflowEngineService = (WorkflowEngineService) FACTORY_BEAN.create();
        }

        //获取服务对象
        return workflowEngineService;
    }

}

这里出现了一个困扰我很久的问题,注册service对象的时候,中间有个公共配置类WorkFlowConfig获取Address值为空,但这个公共配置类我只想要有着一个入口(WorkFlowConfig),不想别的类再去做重复的获取同样配置的操作

package com.metarnet.kpi.ws.client.engine.config;

import com.metarnet.kpi.dictionary.service.SysDictService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.Map;

/**
 * @author wangyj
 * @className WorkFlowConfig
 * @description 统一工作流配置初始化获取工具类
 * @date 21/8/16
 */
@Component
public class WorkFlowConfig {

    @Autowired
    private SysDictService AutowiredSysDictService;

    private static SysDictService sysDictService;

    private static Map<String, String> results;

    private final String MODULE_NAME = "WORK_FLOW";
    private final String KEY_GROUP = "WORK_FLOW_PARAMS";

    @PostConstruct
    public void init(){
        sysDictService = AutowiredSysDictService;
        results = sysDictService.findMapsByModuleAndGroup(MODULE_NAME,KEY_GROUP);
    }


    public static String getWorkFlowAddress(){
        return results.get("address");
    }

    public static String getSystemMark(){
        return results.get("systemMark");
    }

}

debug后发现是当时下面这段代码的bean实例化在WorkFlowConfig工具类之前,所以无法获取工具类静态值

@Bean
public static WorkflowEngineService getWorkFlowEngine(){}

期间尝试了各种方法:

@Import
@Lazy
spring bean延迟注入
spring指定bean优先加载
WorkFlowConfig工具类构造方法注入
WorkFlowConfig工具类@Configuration
构造方法依赖
@DependOn 注解
实现CommandLineRunner接口
实现ApplicationRunner接口
@ConditionalOnClass({xxx.class})
@ConditionalOnBean
springboot @configuration 加载顺序(这个感觉有点脱离代码当时做了最后备选)

以上方法都不行,可能是我自己的使用方法不对

之前@DependOn 注解我用在了这个地方,因为注解位置错误,所以没生效

@Configuration
@DependOn
public class WorkflowEngineServiceFactory {
    ...
}

继续百度.....

最后发现可能是我注解位置不对

应该是在bean本身上注入才生效

更改后代码

@Configuration
public class WorkflowEngineServiceFactory {
    ...
    @Bean
    @DependsOn("workFlowConfig")
    public static WorkflowEngineService getWorkFlowEngine(){
        ...
        return workflowEngineService;
    }
    
}

至此,终于完美实现了我的现阶段所有目标.做个记录

代码写的有点混乱,还有很多不规范的地方,如果有路过的大佬,还请不吝指点!

拜谢~

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值