You signed in with another tab or window.
Reload
to refresh your session.
You signed out in another tab or window.
Reload
to refresh your session.
You switched accounts on another tab or window.
Reload
to refresh your session.
By clicking “Sign up for GitHub”, you agree to our
terms of service
and
privacy statement
. We’ll occasionally send you account related emails.
Already on GitHub?
Sign in
to your account
Steps to reproduce this issue
xml配置dubbo:reference方式,dubbo:method配置的onreturn,onthrow方法为spring bean(以下称A)的方法,这些方法上还有诸如
@Transactional
之类的Spring AOP注解。
A里面
@Autowired
注解的成员均注入失败,使用时均为null对象。
我们采取的补救方法是去掉
@Autowired
注解,将A增加
ApplicationListener<ContextRefreshedEvent>
接口实现,在onApplicationEvent方法里重新从ApplicationContext里取得相应的bean赋给本该由
@Autowired
注入的成员。
onreturn,onthrow方法上的Spring AOP注解均失效。
我们采取的补救方法是将onreturn,onthrow方法拆分,相关业务处理代码以及Spring AOP注解移到另外一个bean,A里面的onreturn,onthrow方法只是调用另外那个bean带注解的方法。
onThrow方法捕获不了dubbo客户端抛出的RpcException。
重现方法:删除dubbo服务接口入参class上的序列化接口定义,在事件通知方式下客户端的onThrow方法未捕获到任何异常,在
@Reference
注解方式下调用会抛出dubbo入参未实现java.io.Serializable接口的RPC异常。
@Reference
注解配置oninvoke,onreturn,onthrow无效,我们看到
#6833
已经描述过这个问题,5月份已修复,我们看到最新发布的3.0代码里已包含了修复,但是修复的方法上还有
@Deprecated
注解,是否还有进一步修订计划?
@reference
注解配置oninvoke,onreturn,onthrow无效,我们看到
#6833
已经描述过这个问题,5月份已修复,我们看到最新发布的3.0代码里已包含了修复,但是修复的方法上还有
@deprecated
注解,是否还有进一步修订计划?
3.0 分支重构了ReferenceBean的逻辑,统一了xml及Annotation的初始化过程,方法回调配置解析改为: org.apache.dubbo.config.spring.reference.ReferenceCreator#createMethodConfig。 相关pr:
#8109
xml配置dubbo:reference方式,dubbo:method配置的onreturn,onthrow方法为spring bean(以下称A)的方法,这些方法上还有诸如
@transactional
之类的Spring AOP注解。
A里面
@Autowired
注解的成员均注入失败,使用时均为null对象。
可以提供一个具体的测试用例吗?
package com.test.notifyApi;
public interface UserNotifyService {
String getName(NotifyDto dto);
接口方法入参NotifyDto:
package com.test.notifyApi;
import java.io.Serializable;
import javax.validation.constraints.NotNull;
import lombok.Data;
@Data
public class NotifyDto implements Serializable {
private static final long serialVersionUID = 1L;
private String id;
@NotNull
private String sex;
consumer工程notifyConsumer.jar
配置类DubboReferenceConfig:
package com.test.notifyConsumer.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
@Configuration
@ImportResource({"classpath:notify.xml"})
public class DubboReferenceConfig {
定义Dubbo Reference bean的notify.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://dubbo.apache.org/schema/dubbo
http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<dubbo:reference id="userNotifyService"
interface="com.test.notifyApi.UserNotifyService"
check="false" timeout="3000">
<dubbo:method name="getName" validation="true"
retries="0" async="true"
oninvoke="consumerNotifyServiceImpl.onInvoke"
onreturn="consumerNotifyServiceImpl.onReturn"
onthrow="consumerNotifyServiceImpl.onThrow" />
</dubbo:reference>
</beans>
事件通知接口ConsumerNotifyService:
package com.test.notifyConsumer.service;
import com.test.notifyApi.NotifyDto;
public interface ConsumerNotifyService {
void onInvoke(NotifyDto dto);
void onReturn(String name, NotifyDto dto);
void onThrow(Throwable e, NotifyDto dto);
void getName(NotifyDto dto);
事件通知接口实现类ConsumerNotifyServiceImpl :
package com.test.notifyConsumer.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
import com.test.notifyApi.NotifyDto;
import com.test.notifyApi.UserNotifyService;
import com.test.notifyConsumer.aspect.MethodAnnotation;
import com.test.notifyConsumer.service.ConsumerNotifyService;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Component
public class ConsumerNotifyServiceImpl implements ConsumerNotifyService {
@Autowired
UserNotifyService userNotifyService;
@Autowired
NotifyWork work;
@MethodAnnotation("invoke-annotation")
public void onInvoke(NotifyDto dto) {
log.info("invoke for {}", dto);
work.workInvoke(dto);
@MethodAnnotation("return-annotation")
public void onReturn(String name, NotifyDto dto) {
log.info("return {} for {}", name, dto);
work.workReturn(name, dto);
@MethodAnnotation("throw-annotation")
public void onThrow(Throwable e, NotifyDto dto) {
log.info("throw exception {} for {}", e, dto);
work.workThrow(e, dto);
public void getName(NotifyDto dto) {
userNotifyService.getName(dto);
注解MethodAnnotation:
package com.test.notifyConsumer.aspect;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface MethodAnnotation {
String value() default "";
切面MethodAspect :
package com.test.notifyConsumer.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Component
@Aspect
public class MethodAspect {
@Around("@annotation(annotation)")
public Object aroundMethod(ProceedingJoinPoint pjp, MethodAnnotation annotation) throws Throwable {
log.info("aspect {} for {}", annotation.value(), pjp.getSignature().getName());
return pjp.proceed();
package com.test.notifyConsumer;
import javax.validation.ValidationException;
import org.junit.AfterClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.test.notifyApi.NotifyDto;
import com.test.notifyConsumer.service.ConsumerNotifyService;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = App.class)
public class AppTest
@Autowired
ConsumerNotifyService consumerNotifyService;
@Test
public void test1() {
NotifyDto dto = new NotifyDto();
dto.setId("12345");
dto.setSex("M");
consumerNotifyService.getName(dto);
// 2.7.5: ConstraintViolationException, 2.7.12: ValidationException(前者的超类)
@Test(expected = ValidationException.class)
public void test2() {
NotifyDto dto = new NotifyDto();
dto.setId("67890");
consumerNotifyService.getName(dto);
@Test
public void test3() {
NotifyDto dto = new NotifyDto();
dto.setSex("W");
consumerNotifyService.getName(dto);
@AfterClass
public static void waitForNotify() throws InterruptedException {
log.info("WAIT 1s");
Thread.sleep(1000);
provider工程
服务UserNotifyServiceImpl:
package com.test.notifyService.service.impl;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.Service;
import org.apache.dubbo.rpc.RpcException;
import com.test.notifyApi.NotifyDto;
import com.test.notifyApi.UserNotifyService;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service
public class UserNotifyServiceImpl implements UserNotifyService {
@Override
public String getName(NotifyDto dto) {
log.info("getname param={}", dto);
if (StringUtils.isEmpty(dto.getId())) {
throw new RpcException("null id");
return "name-" + dto.getId() + "(" + dto.getSex() + ")";
dubbo2.7.5版本
无论是在启动类加@EnableDubbo注解,还是在application.yml配置dubbo.scan.basePackages都存在问题1、2、3;两种方式启动时间都是12秒左右。
dubbo2.7.12版本
启动类上加@EnableDubbo注解的方式,运行正常,问题1、2、3都没有了;只是改成这种方式之后启动测试程序耗时从18秒变成了80秒,也是醉了。
只在application.yml配置dubbo.scan.basePackages的方式还有问题1、2,而问题3没有了,启动耗时不到18秒。
启动慢的原因找到了,有1台nacos注册中心down了,up之后重新测试,两个dubbo版本每种方式各测试10次左右,情况如下。
dubbo2.7.5版本:两种方式下启动耗时均在5~7秒之间;
dubbo2.7.12版本:@EnableDubbo方式下启动耗时在9~12秒之间;application.yml配置dubbo.scan.basePackages方式下启动耗时在6~10秒之间。