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;
}
}
至此,终于完美实现了我的现阶段所有目标.做个记录
代码写的有点混乱,还有很多不规范的地方,如果有路过的大佬,还请不吝指点!
拜谢~
本文介绍了如何通过AOP切面简化JAX-WS WebService的日志记录,并解决服务实例化问题,以实现Spring管理的单例WorkflowEngineService。作者详细记录了解决过程和关键代码片段,包括切面配置和依赖管理。


被折叠的 条评论
为什么被折叠?



