java—如何检查spring中使用scope\u prototype和scopedproxymode.target\u类的对象示例是否不同?

kpbwa7wx  于 2021-07-13  发布在  Java
关注(0)|答案(1)|浏览(333)

我有两颗豆子 PersonDAO 以及 JdbcConnection 彼此依赖。这个 PersonDAO bean是使用 @Component . 但是 JdbcConnection 是一个 prototype 因为它被注射在 PersonDAO 我正在使用 proxyMode = ScopedProxyMode.TARGET_CLASS 以确保它是一个不同的示例(不是单例)。

import com.github.felipegutierrez.explore.spring.basics.beans.JdbcConnection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class PersonDAO {
    @Autowired
    private JdbcConnection jdbcConnection;
    public PersonDAO(JdbcConnection jdbcConnection) {
        this.jdbcConnection = jdbcConnection;
    }
    public JdbcConnection getJdbcConnection() {
        return jdbcConnection;
    }
    public void setJdbcConnection(JdbcConnection jdbcConnection) {
        this.jdbcConnection = jdbcConnection;
    }
}

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.stereotype.Component;
@Component
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class JdbcConnection {
    private static final Logger LOGGER = LoggerFactory.getLogger(JdbcConnection.class);
    public JdbcConnection() {
        // LOGGER.info("This is my JdbcConnection that is not a singleton bean.");
    }

}

当我打印它们的对象示例时 PersonDAO 是独生子女 JdbcConnection 是另一个例子。但是 JdbcConnection 说是独生子。为什么?

ApplicationContext applicationContext = SpringApplication.run(ExploreSpringApplication.class, args);

PersonDAO personDAO01 = applicationContext.getBean(PersonDAO.class);
PersonDAO personDAO02 = applicationContext.getBean(PersonDAO.class);

LOGGER.info("DAO 01: {}, {}, JDBCConnection: {}, {}", personDAO01, personDAO01.hashCode(), personDAO01.getJdbcConnection().hashCode(), personDAO01.getJdbcConnection());
LOGGER.info("DAO 02: {}, {}, JDBCConnection: {}, {}", personDAO02, personDAO02.hashCode(), personDAO02.getJdbcConnection().hashCode(), personDAO02.getJdbcConnection());

输出 JDBCConnectionDAO01 以及 DAO02 具有相同的哈希代码: 1596179075 但实际上它们是不同的例子: JdbcConnection@58a55449 以及 JdbcConnection@5949eba8 :

2021-03-08 18:13:29.527  INFO 10329 --- [           main] c.g.f.e.spring.ExploreSpringApplication  : DAO 01: 1187972599, com.github.felipegutierrez.explore.spring.basics.dao.PersonDAO@46cf05f7
2021-03-08 18:13:29.527  INFO 10329 --- [           main] c.g.f.e.spring.ExploreSpringApplication  : DAO 01 JDBCConnection: 1596179075, com.github.felipegutierrez.explore.spring.basics.beans.JdbcConnection@58a55449
2021-03-08 18:13:29.529  INFO 10329 --- [           main] c.g.f.e.spring.ExploreSpringApplication  : DAO 02: 1187972599, com.github.felipegutierrez.explore.spring.basics.dao.PersonDAO@46cf05f7
2021-03-08 18:13:29.529  INFO 10329 --- [           main] c.g.f.e.spring.ExploreSpringApplication  : DAO 02 JDBCConnection: 1596179075, com.github.felipegutierrez.explore.spring.basics.beans.JdbcConnection@5949eba8
qhhrdooz

qhhrdooz1#

spring在为目标原型对象创建代理时默认使用cglib。似乎这是cglib的一个限制 hashCode() 以及 equals 方法总是被特殊的拦截器截获,这些拦截器以不经过目标对象的方式进行比较。
如果您切换到基于jdk接口的代理,这需要 JdbcConnection 实现一个接口,您可以声明 hashCode() 以及 equals() 在界面中:

@Component
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE, proxyMode = ScopedProxyMode.INTERFACES)
public class JdbcConnection implements IJdbcConnection {

    ...
}

interface IJdbcConnection {

    @Override
    boolean equals(Object obj);

    @Override
    int hashCode();
}

Spring的 JdkDynamicAopProxy 然后打电话给 hashCode() 以及 equals() 在目标对象上。
使用 @Qualifier("jdbcConnection") 界面在 PersonDAO .

@Component
public class PersonDAO {

    @Autowired
    @Qualifier("jdbcConnection")
    private IJdbcConnection jdbcConnection;

相关问题