¿Por qué la adición de una super-clase romper mis granos de la primavera?

Dave:

Tengo una aplicación web de Primavera de arranque que está funcionando correctamente. Me di cuenta de que dos @Repositorygranos tenía mucho en común, por lo que les refactorizado utilizando una superclase abstracta y ahora mi solicitud está roto. Tengo una doble comprobación y este es el único cambio que he hecho entre el trabajo y los estados que no trabajan. ¿Puede alguien ver lo que he hecho mal?

Aquí está mi código de trabajo:

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);
        ...
    }
}

Aquí está mi re-factorizado código donde presenté una, genérica super-clase abstracta.

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; }
}

Cuando se utiliza el código de re-factorizada consigo una NullPointerExceptionen AbstractRepo::get(). He confirmado a través del depurador que cachees null(junto con source). Sin embargo, también confirmó a través del depurador que los casos de RepoOne y RepoTwo se crean y su createCache()método llamado. Es como si se crean dos instancias de cada uno y sólo uno es inicializado. ¿Alguna idea?

Marcus continuación:

No es el hecho de que usted introdujo una clase padre, pero el hecho de que se activó el getmétodo en un finalmétodo.

Una clase anotado con @Repositoryobtendrá traducción automática es una excepción. Se añade esta traducción automática excepción mediante el uso de AOP. El mecanismo por defecto para aplicar AOP en la primavera es a proxies de uso y en este caso un proxy basado en la clase.

Lo que pasa es que CGLIB crea un proxy para sus clases subclasificando, de modo que cuando se llama a un método de un consejo puede ser añadido. Sin embargo, un finalmétodo no puede ser anulado en una subclase. Lo que conducirá a la getmétodo que se llama en el proxy en lugar de la instancia real.

Hay 2 maneras de fijar este

  1. Quitar la finalpalabra clave
  2. Introducir una interfaz que define el contrato para sus repositorios. Esto dará lugar a un proxy dinámico JDK se está creando. JDK dinámicos La representación se basan interfaz y no necesita subclase de su clase real (que es sólo para los proxies basados ​​en la clase).

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=190529&siteId=1
Recomendado
Clasificación