I have two beans PersonDAO
and JdbcConnection
with dependency on each other. The PersonDAO
bean is a singleton bean using @Component
. But the JdbcConnection
is a prototype
and because it is injected inside the PersonDAO
I am using proxyMode = ScopedProxyMode.TARGET_CLASS
to ensure that it is a different instance (not a singleton).
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.");
}
}
When I print the object instance of them the PersonDAO
is a singleton and the JdbcConnection
is a different instance. But the hashcode of the JdbcConnection
says that it is a singleton. Why is that?
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());
output JDBCConnection
of DAO01
and DAO02
has the same hashcode: 1596179075
but actually they are different instances: JdbcConnection@58a55449
and 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
Spring uses CGLIB by default when creating a proxy for the target prototype object. It seems this is a limitation by CGLIB where the hashCode()
and equals
methods are always intercepted by special interceptors that do comparison in such a way that does not go through the target object.
If you switch to JDK interface-based proxies , which requires that JdbcConnection
implements an interface, you can declare hashCode()
and equals()
in the interface:
@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's JdkDynamicAopProxy
will then call the hashCode()
and equals()
on the target object.
and use the @Qualifier("jdbcConnection")
with the interface on the PersonDAO
.
@Component
public class PersonDAO {
@Autowired
@Qualifier("jdbcConnection")
private IJdbcConnection jdbcConnection;
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.