简体   繁体   中英

Spring can't Autowired abstract class with final method

public abstract class BaseLoaneeRepayment implements Repayment {

    @Autowired
    protected LoanRepository loanRepository;

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public final void repay(RepaymentInfo repaymentInfo) {
        Loan loan = loanRepository.lockAndLoad(repaymentInfo.getLoan().id());
    }

    protected abstract void preCheck(final RepaymentInfo repaymentInfo);

    protected abstract void updateLoanee(final RepaymentInfo repaymentInfo);

    protected abstract void repayment(final RepaymentInfo repaymentInfo);

    protected abstract void calcDifference(final RepaymentInfo repaymentInfo);
}


@Service("loaneeNormalRepayment")
public class NormalRepayment extends BaseLoaneeRepayment implements Repayment {

    private static final CatLogger logger = CatLoggerFactory.getLogger(NormalRepayment.class);

    @Override
    public final void preCheck(RepaymentInfo repaymentInfo) {}
    @Override
    public final void updateLoanee(RepaymentInfo repaymentInfo) {}
    @Override
    public final void repayment(RepaymentInfo repaymentInfo) {}
    @Override
    public final void calcDifference(RepaymentInfo repaymentInfo) {}
}

in Junit,

@TransactionConfiguration(defaultRollback = true)
public class NormalRepaymentTest extends ServiceTest {

    @Autowired
    @Qualifier("normalRepayment2")
    private NormalRepayment normalRepayment;

    @Autowired
    private LoanService loanService;


    @Test
    public void test() {
        normalRepayment.repay(repaymentInfo);
    }
}

This normalRepayment.repay(repaymentInfo); in NormalRepayment loanRepository is null. The autowire not work.

The behavior you see is related to proxies. In certain cases, for Spring managed beans, Spring will create a proxy for the target class. In this case, methods are marked as @Transactional , and Spring will create a proxy which implements transaction handling for your service. Depending on the proxy strategy, Spring may proxy by subclass , which means a subclass will override methods of the target class and implement various logic such as transaction handling in those methods. In this case, the dependencies will be injected in the proxy, not the target class.

Java, by design, does now allow overriding final methods, and because of this, the proxy subclass will not be able to override the final methods in your concrete class.

The calling code will, in this case, in fact call the non-proxied target methods, where dependencies are not injected and no transactional handling is present.

Solution: Remove the final modifier from the methods in your concrete class, which will allow Spring to properly proxy your service class.

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM