class SpringResourceLoader<M> extends InitializableObject {
    private static final long NO_LAST_MODIFIED = -1;

    private final Lock lock = new ReentrantLock();
    private final AtomicBoolean byteArrayHasChanged = new AtomicBoolean(true);
    @Getter
    private long lastModified = NO_LAST_MODIFIED;

    protected final Resource resource;

    protected M loaded;

    /** {@inheritDoc} */
    protected final void internalInit(final boolean forceReinit) {
        internalLoad();
        hasChanged();
    }

    /**
     * <p>load.</p>
     *
     * @return a M object
     */
    public final M load() {
        if (lock.tryLock()) {
            try {
                if (hasChanged()) {
                    internalLoad();
                }
            } finally {
                lock.unlock();
            }
        }
        return loaded;
    }

    /**
     * <p>hasChanged.</p>
     *
     * @return a boolean
     */
    public boolean hasChanged() {<FILL_FUNCTION_BODY>}

    /**
     * <p>internalLoad.</p>
     */
    protected abstract void internalLoad();
}

        if (resource != null) {
            if (resource instanceof ByteArrayResource) {
                return byteArrayHasChanged.getAndSet(false);
            }

            long newLastModified;
            try {
                newLastModified = resource.lastModified();
            } catch (final Exception e) {
                newLastModified = NO_LAST_MODIFIED;
            }
            val hasChanged = lastModified != newLastModified;
            LOGGER.debug("lastModified: {} / newLastModified: {} -> hasChanged: {}", lastModified, newLastModified, hasChanged);
            lastModified = newLastModified;
            return hasChanged;
        }
        return false;
    
<methods>public non-sealed void <init>() ,public int getNbAttempts() ,public void init() ,public void init(boolean) ,public final boolean isInitialized() ,public void reinit() <variables>private java.util.concurrent.atomic.AtomicBoolean initialized,private volatile java.lang.Long lastAttempt,private int maxAttempts,private long minTimeIntervalBetweenAttemptsInMilliseconds,private java.util.concurrent.atomic.AtomicInteger nbAttempts