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.framework;
018
019import org.springframework.aop.TargetSource;
020import org.springframework.aop.framework.adapter.AdvisorAdapterRegistry;
021import org.springframework.aop.framework.adapter.GlobalAdvisorAdapterRegistry;
022import org.springframework.aop.target.SingletonTargetSource;
023import org.springframework.beans.factory.BeanClassLoaderAware;
024import org.springframework.beans.factory.FactoryBean;
025import org.springframework.beans.factory.FactoryBeanNotInitializedException;
026import org.springframework.beans.factory.InitializingBean;
027import org.springframework.lang.Nullable;
028import org.springframework.util.ClassUtils;
029
030/**
031 * Convenient superclass for {@link FactoryBean} types that produce singleton-scoped
032 * proxy objects.
033 *
034 * <p>Manages pre- and post-interceptors (references, rather than
035 * interceptor names, as in {@link ProxyFactoryBean}) and provides
036 * consistent interface management.
037 *
038 * @author Juergen Hoeller
039 * @since 2.0
040 */
041@SuppressWarnings("serial")
042public abstract class AbstractSingletonProxyFactoryBean extends ProxyConfig
043                implements FactoryBean<Object>, BeanClassLoaderAware, InitializingBean {
044
045        @Nullable
046        private Object target;
047
048        @Nullable
049        private Class<?>[] proxyInterfaces;
050
051        @Nullable
052        private Object[] preInterceptors;
053
054        @Nullable
055        private Object[] postInterceptors;
056
057        /** Default is global AdvisorAdapterRegistry. */
058        private AdvisorAdapterRegistry advisorAdapterRegistry = GlobalAdvisorAdapterRegistry.getInstance();
059
060        @Nullable
061        private transient ClassLoader proxyClassLoader;
062
063        @Nullable
064        private Object proxy;
065
066
067        /**
068         * Set the target object, that is, the bean to be wrapped with a transactional proxy.
069         * <p>The target may be any object, in which case a SingletonTargetSource will
070         * be created. If it is a TargetSource, no wrapper TargetSource is created:
071         * This enables the use of a pooling or prototype TargetSource etc.
072         * @see org.springframework.aop.TargetSource
073         * @see org.springframework.aop.target.SingletonTargetSource
074         * @see org.springframework.aop.target.LazyInitTargetSource
075         * @see org.springframework.aop.target.PrototypeTargetSource
076         * @see org.springframework.aop.target.CommonsPool2TargetSource
077         */
078        public void setTarget(Object target) {
079                this.target = target;
080        }
081
082        /**
083         * Specify the set of interfaces being proxied.
084         * <p>If not specified (the default), the AOP infrastructure works
085         * out which interfaces need proxying by analyzing the target,
086         * proxying all the interfaces that the target object implements.
087         */
088        public void setProxyInterfaces(Class<?>[] proxyInterfaces) {
089                this.proxyInterfaces = proxyInterfaces;
090        }
091
092        /**
093         * Set additional interceptors (or advisors) to be applied before the
094         * implicit transaction interceptor, e.g. a PerformanceMonitorInterceptor.
095         * <p>You may specify any AOP Alliance MethodInterceptors or other
096         * Spring AOP Advices, as well as Spring AOP Advisors.
097         * @see org.springframework.aop.interceptor.PerformanceMonitorInterceptor
098         */
099        public void setPreInterceptors(Object[] preInterceptors) {
100                this.preInterceptors = preInterceptors;
101        }
102
103        /**
104         * Set additional interceptors (or advisors) to be applied after the
105         * implicit transaction interceptor.
106         * <p>You may specify any AOP Alliance MethodInterceptors or other
107         * Spring AOP Advices, as well as Spring AOP Advisors.
108         */
109        public void setPostInterceptors(Object[] postInterceptors) {
110                this.postInterceptors = postInterceptors;
111        }
112
113        /**
114         * Specify the AdvisorAdapterRegistry to use.
115         * Default is the global AdvisorAdapterRegistry.
116         * @see org.springframework.aop.framework.adapter.GlobalAdvisorAdapterRegistry
117         */
118        public void setAdvisorAdapterRegistry(AdvisorAdapterRegistry advisorAdapterRegistry) {
119                this.advisorAdapterRegistry = advisorAdapterRegistry;
120        }
121
122        /**
123         * Set the ClassLoader to generate the proxy class in.
124         * <p>Default is the bean ClassLoader, i.e. the ClassLoader used by the
125         * containing BeanFactory for loading all bean classes. This can be
126         * overridden here for specific proxies.
127         */
128        public void setProxyClassLoader(ClassLoader classLoader) {
129                this.proxyClassLoader = classLoader;
130        }
131
132        @Override
133        public void setBeanClassLoader(ClassLoader classLoader) {
134                if (this.proxyClassLoader == null) {
135                        this.proxyClassLoader = classLoader;
136                }
137        }
138
139
140        @Override
141        public void afterPropertiesSet() {
142                if (this.target == null) {
143                        throw new IllegalArgumentException("Property 'target' is required");
144                }
145                if (this.target instanceof String) {
146                        throw new IllegalArgumentException("'target' needs to be a bean reference, not a bean name as value");
147                }
148                if (this.proxyClassLoader == null) {
149                        this.proxyClassLoader = ClassUtils.getDefaultClassLoader();
150                }
151
152                ProxyFactory proxyFactory = new ProxyFactory();
153
154                if (this.preInterceptors != null) {
155                        for (Object interceptor : this.preInterceptors) {
156                                proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(interceptor));
157                        }
158                }
159
160                // Add the main interceptor (typically an Advisor).
161                proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(createMainInterceptor()));
162
163                if (this.postInterceptors != null) {
164                        for (Object interceptor : this.postInterceptors) {
165                                proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(interceptor));
166                        }
167                }
168
169                proxyFactory.copyFrom(this);
170
171                TargetSource targetSource = createTargetSource(this.target);
172                proxyFactory.setTargetSource(targetSource);
173
174                if (this.proxyInterfaces != null) {
175                        proxyFactory.setInterfaces(this.proxyInterfaces);
176                }
177                else if (!isProxyTargetClass()) {
178                        // Rely on AOP infrastructure to tell us what interfaces to proxy.
179                        Class<?> targetClass = targetSource.getTargetClass();
180                        if (targetClass != null) {
181                                proxyFactory.setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
182                        }
183                }
184
185                postProcessProxyFactory(proxyFactory);
186
187                this.proxy = proxyFactory.getProxy(this.proxyClassLoader);
188        }
189
190        /**
191         * Determine a TargetSource for the given target (or TargetSource).
192         * @param target the target. If this is an implementation of TargetSource it is
193         * used as our TargetSource; otherwise it is wrapped in a SingletonTargetSource.
194         * @return a TargetSource for this object
195         */
196        protected TargetSource createTargetSource(Object target) {
197                if (target instanceof TargetSource) {
198                        return (TargetSource) target;
199                }
200                else {
201                        return new SingletonTargetSource(target);
202                }
203        }
204
205        /**
206         * A hook for subclasses to post-process the {@link ProxyFactory}
207         * before creating the proxy instance with it.
208         * @param proxyFactory the AOP ProxyFactory about to be used
209         * @since 4.2
210         */
211        protected void postProcessProxyFactory(ProxyFactory proxyFactory) {
212        }
213
214
215        @Override
216        public Object getObject() {
217                if (this.proxy == null) {
218                        throw new FactoryBeanNotInitializedException();
219                }
220                return this.proxy;
221        }
222
223        @Override
224        @Nullable
225        public Class<?> getObjectType() {
226                if (this.proxy != null) {
227                        return this.proxy.getClass();
228                }
229                if (this.proxyInterfaces != null && this.proxyInterfaces.length == 1) {
230                        return this.proxyInterfaces[0];
231                }
232                if (this.target instanceof TargetSource) {
233                        return ((TargetSource) this.target).getTargetClass();
234                }
235                if (this.target != null) {
236                        return this.target.getClass();
237                }
238                return null;
239        }
240
241        @Override
242        public final boolean isSingleton() {
243                return true;
244        }
245
246
247        /**
248         * Create the "main" interceptor for this proxy factory bean.
249         * Typically an Advisor, but can also be any type of Advice.
250         * <p>Pre-interceptors will be applied before, post-interceptors
251         * will be applied after this interceptor.
252         */
253        protected abstract Object createMainInterceptor();
254
255}