Почему у spring бина методы toString() и hashCode() дают разные результаты?

Рейтинг: 0Ответов: 1Опубликовано: 13.05.2023

Есть класс с аннотацией @RequestScope:

@Component
@RequestScope
public class ComponentRequestScope {
    private String username;
    private String password;

    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
}

hashCode() и toString() у него не переопределены.
И есть контроллер, который использует этот класс:

@Controller
public class LoginController {
    @Autowired
    private ComponentRequestScope component;

    @GetMapping("/")
    public String loginGet() {
        System.out.println(component + " - " + Integer.toHexString(component.hashCode()));
        return "login.html";
    }
}

Если сделать запрос, то получается такой ответ:

ComponentRequestScope@3be1a523 - 16035cfa

Кроме того, если сделать еще запрос, получается следующий ответ:

ComponentRequestScope@3575d568 - 16035cfa

Почему получается разный хэш при работе не переопределенных методов toString() и hashCode()?
Почему при работе метода hashCode() при двух запросах одинаковый хэш, ведь объекты должны быть разные?

Ответы

▲ 4

Все дело в том, что spring перехватывает выполнение методов toString() и hashCode().
При выполнении метода toString() выполняется метод intercept() класса DynamicAdvisedInterceptor вложенного в класс CglibAopProxy.
При выполнении метода hashCode() выполняется метод intercept() класса HashCodeInterceptor вложенного так же в CglibAopProxy.
Если посмотреть на последний метод:

private static class HashCodeInterceptor implements MethodInterceptor, Serializable {
    private final AdvisedSupport advised;

    public HashCodeInterceptor(AdvisedSupport advised) {
        this.advised = advised;
    }

    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) {
        return CglibAopProxy.class.hashCode() * 13 + this.advised.getTargetSource().hashCode();
    }
}

получается что он вычисляет hashCode у класса CglibAopProxy и объекта, полученного из this.advised.getTargetSource(). При этом не используя переданный объект Object proxy (который component).
Следовательно hashCode() зависит от Spring Boot, его классов и объектов, и никак не зависит самого объекта класса ComponentRequestScope.