记通过Springboot开发Webservice服务时不能使用@Transactional注解,原因剖析,事务如何实现

WebService就是一种跨编程语言和跨操作系统平台的远程调用技术。具体的实现不是本文探讨重点,在此就不多说了。
先说说我的场景:我们的服务是一种同时对外提供webservice远程调用,以及普通的http请求调用的服务,整个服务是基于springboot框架和cxf建立的。同时,为了简化开发,我定义了一个注解,当需要发布为webservice的类添加注解并填写发布路径后,配置类初始化时就会根据反射原理获取发布的相关信息,完成自动发布。
由于一些操作涉及到事务,所以我很自然的直接使用spring的事务注解,也就是@Transactional来实现。但是,当我添加这行注解之后,重启服务就发现webservice发布时开始报错。
先看下主体代码:

/**
 * 测试案例类:这里采用@AutoPublish注解实现自动发布
 * 不添加@Transactional时并不会报错
 * @author GrainRain
 * @date 2020/05/10 14:41
 **/
@WebService(serviceName = "TestService",targetNamespace = "http://service.whitetown.com",
        endpointInterface = "cn.whitetown.webdemo.service.Testservice")
@AutoPublish("/tess")
@Service
public class TestServiceImpl implements Testservice {

    @Override
    @Transactional
    public String sendMessage() {
        /**
         * 服务代码
         */
        return "success";
    }
}

以下是自动发布的配置方法

    @Override
    public void run(ApplicationArguments applicationArguments) throws Exception {
        String[] beanNames = applicationContext.getBeanNamesForAnnotation(AutoPublish.class);
        for(String beanName:beanNames){
           //这行代码是我在debug时添加的,具体后续说明            
            System.out.println("bean:"+applicationContext.getType(beanName));
            String addr = applicationContext.getType(beanName).getAnnotation(AutoPublish.class).value();
            Endpoint endpoint = new EndpointImpl(bus,applicationContext.getBean(beanName));
            endpoint.publish(addr);
            System.out.println("服务发布成功,地址为:"+addr);
        }
    }

报错的内容如下:

Caused by: java.lang.NullPointerException: null
	at cn.whitetown.webdemo.config.AutoPublishConfig.run(AutoPublishConfig.java:37) ~[classes/:na]

以上报错对应 String addr = applicationContext.getType(beanName).getAnnotation(AutoPublish.class).value(); 这行代码。
因此,为了判断哪里出了问题,我添加了上面注释标注的那行代码,看看到底有没有获取到容器中的bean对象。结果,还真的获取到了:

bean: class cn.whitetown.webdemo.service.impl.TestServiceImpl$$EnhancerBySpringCGLIB$$f3d01031

细心的读者应该找到报错的原因了。因为添加了事务注解,spring在初始化时会为我们创建一个代理类,注册的bean对象也是代理类对象,因而我获取到的bean对象自然是这个代理类对象,而不再是原来自己写的那个类创建的对象了。自然而然的,代理类上并没有我们添加的注解,也就不可能获取得到相应的值。
这也就是出现空指针异常的原因。看来还是对框架底层理解不够透彻导致的,这也体现出读源码,理解底层原理的重要性。

那么,这样的情况下事务如何实现呢。
其实知道了原因那么解决也很简单,必定有那么多种事务实现方式呢。我这里直接使用编程式事务实现,代码如下:

@WebService(serviceName = "TestService",targetNamespace = "http://service.whitetown.com",
        endpointInterface = "cn.whitetown.webdemo.service.Testservice")
@AutoPublish("/tess")
@Service
public class TestServiceImpl implements Testservice {
    
    @Autowired
    private PlatformTransactionManager platformTransactionManager;

    @Override
    public String sendMessage() {
        DefaultTransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
        //start transaction
        TransactionStatus transactionStatus = platformTransactionManager.getTransaction(transactionDefinition);
        /**
         * 一个事务内的代码
         */
        //commit
        platformTransactionManager.commit(transactionStatus);
        return "success";
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值