001/*
002 * Copyright 2002-2018 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.aop.target;
018
019import org.apache.commons.logging.Log;
020import org.apache.commons.logging.LogFactory;
021
022import org.springframework.aop.TargetSource;
023import org.springframework.lang.Nullable;
024
025/**
026 * {@link org.springframework.aop.TargetSource} implementation that will
027 * lazily create a user-managed object.
028 *
029 * <p>Creation of the lazy target object is controlled by the user by implementing
030 * the {@link #createObject()} method. This {@code TargetSource} will invoke
031 * this method the first time the proxy is accessed.
032 *
033 * <p>Useful when you need to pass a reference to some dependency to an object
034 * but you don't actually want the dependency to be created until it is first used.
035 * A typical scenario for this is a connection to a remote resource.
036 *
037 * @author Rob Harrop
038 * @author Juergen Hoeller
039 * @since 1.2.4
040 * @see #isInitialized()
041 * @see #createObject()
042 */
043public abstract class AbstractLazyCreationTargetSource implements TargetSource {
044
045        /** Logger available to subclasses. */
046        protected final Log logger = LogFactory.getLog(getClass());
047
048        /** The lazily initialized target object. */
049        private Object lazyTarget;
050
051
052        /**
053         * Return whether the lazy target object of this TargetSource
054         * has already been fetched.
055         */
056        public synchronized boolean isInitialized() {
057                return (this.lazyTarget != null);
058        }
059
060        /**
061         * This default implementation returns {@code null} if the
062         * target is {@code null} (it is hasn't yet been initialized),
063         * or the target class if the target has already been initialized.
064         * <p>Subclasses may wish to override this method in order to provide
065         * a meaningful value when the target is still {@code null}.
066         * @see #isInitialized()
067         */
068        @Override
069        @Nullable
070        public synchronized Class<?> getTargetClass() {
071                return (this.lazyTarget != null ? this.lazyTarget.getClass() : null);
072        }
073
074        @Override
075        public boolean isStatic() {
076                return false;
077        }
078
079        /**
080         * Returns the lazy-initialized target object,
081         * creating it on-the-fly if it doesn't exist already.
082         * @see #createObject()
083         */
084        @Override
085        public synchronized Object getTarget() throws Exception {
086                if (this.lazyTarget == null) {
087                        logger.debug("Initializing lazy target object");
088                        this.lazyTarget = createObject();
089                }
090                return this.lazyTarget;
091        }
092
093        @Override
094        public void releaseTarget(Object target) throws Exception {
095                // nothing to do
096        }
097
098
099        /**
100         * Subclasses should implement this method to return the lazy initialized object.
101         * Called the first time the proxy is invoked.
102         * @return the created object
103         * @throws Exception if creation failed
104         */
105        protected abstract Object createObject() throws Exception;
106
107}