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