我有一个正常运行的Spring Boot Web应用程序。我注意到两个@Repository
bean有很多共同点,所以我使用抽象超类重构了它们,现在我的应用程序坏了。我已经仔细检查过,这是我在工作状态和非工作状态之间所做的唯一更改。谁能看到我做错了什么?
这是我的工作代码:
public class One { ... }
public class Two { ... }
@Repository
public class RepoOne {
private final ISource<One> sourceOne;
private ICache<One> cache;
@Value("${com.example.lifetime.one}")
private int lifetime;
public RepoOne(ISource<One> sourceOne) {
this.sourceOne = sourceOne;
}
@PostConstruct
public void createCache() {
Duration lifetime = Duration.ofMinutes(this.lifetime);
this.cache = new Cache<>(lifetime, sourceOne);
}
public One get(String key) {
return cache.get(key);
}
}
@Repository
public class RepoTwo {
private final ISource<Two> sourceTwo;
private ICache<Two> cache;
@Value("${com.example.lifetime.two}")
private int lifetime;
public RepoOne(ISource<Two> sourceTwo) {
this.sourceTwo = sourceTwo;
}
@PostConstruct
public void createCache() {
Duration lifetime = Duration.ofMinutes(this.lifetime);
this.cache = new Cache<>(lifetime, sourceTwo);
}
public Two get(String key) {
return cache.get(key);
}
}
@Service
public class RepoService {
private final RepoOne repoOne;
private final RepoTwo repoTwo;
public RepoService(RepoOne repoOne, RepoTwo repoTwo) {
this.repoOne = repoOne;
this.repoTwo = repoTwo;
}
public void doSomething(String key) {
One one = repoOne.get(key);
...
}
}
这是我的重构代码,在其中我引入了抽象的通用超类。
abstract class AbstractRepo<T> {
private final ISource<T> source;
private ICache<T> cache;
AbstractRepo (ISource<T> source) {
this.source = source;
}
@PostConstruct
private void createCache() {
Duration lifetime = Duration.ofMinutes(lifetime());
this.cache = new Cache<>(lifetime, source);
}
protected abstract int lifetime();
public final T get(String key) {
return cache.get(key);
}
}
@Repository
public class RepoOne extends AbstractRepo<One> {
@Value("${com.example.lifetime.one}")
private int lifetime;
public RepoOne(ISource<One> sourceOne) {
super(source);
}
protected int lifetime() { return lifetime; }
}
@Repository
public class RepoTwo extends AbstractRepo<Two> {
@Value("${com.example.lifetime.two}")
private int lifetime;
public RepoTwo(ISource<Two> sourceTwo) {
super(source);
}
protected int lifetime() { return lifetime; }
}
使用重构的代码时,我在NullPointerException
中得到了一个AbstractRepo::get()
。我已经通过调试器确认cache
是null
(以及source
)。但是,我还通过调试器确认创建了RepoOne和RepoTwo实例,并调用了它们的createCache()
方法。好像每个实例都被创建了两个实例,而只有一个实例被初始化了。有什么想法吗?
答案 0 :(得分:3)
不是您引入了父类,而是您将get
方法变成了final
方法。
用@Repository
注释的类将获得自动异常翻译。通过使用AOP添加了自动异常转换。在Spring中应用AOP的默认机制是使用代理,在这种情况下是基于类的代理。
发生的事情是CgLib通过子类化为您的类创建了一个代理,以便在调用方法时可以添加建议。但是,final
方法不能在子类中覆盖。这将导致在代理而不是实际实例上调用get
方法。
有2种解决方法
final
关键字