|
Spring Framework example source code file (ProxyFactoryBean.java)
The Spring Framework ProxyFactoryBean.java source code
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.aop.framework;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.Interceptor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.Advisor;
import org.springframework.aop.TargetSource;
import org.springframework.aop.framework.adapter.AdvisorAdapterRegistry;
import org.springframework.aop.framework.adapter.GlobalAdvisorAdapterRegistry;
import org.springframework.aop.framework.adapter.UnknownAdviceTypeException;
import org.springframework.aop.target.SingletonTargetSource;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.FactoryBeanNotInitializedException;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.core.OrderComparator;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
/**
* {@link org.springframework.beans.factory.FactoryBean} implementation that builds an
* AOP proxy based on beans in Spring {@link org.springframework.beans.factory.BeanFactory}.
*
* <p>{@link org.aopalliance.intercept.MethodInterceptor MethodInterceptors} and
* {@link org.springframework.aop.Advisor Advisors} are identified by a list of bean
* names in the current bean factory, specified through the "interceptorNames" property.
* The last entry in the list can be the name of a target bean or a
* {@link org.springframework.aop.TargetSource}; however, it is normally preferable
* to use the "targetName"/"target"/"targetSource" properties instead.
*
* <p>Global interceptors and advisors can be added at the factory level. The specified
* ones are expanded in an interceptor list where an "xxx*" entry is included in the
* list, matching the given prefix with the bean names (e.g. "global*" would match
* both "globalBean1" and "globalBean2", "*" all defined interceptors). The matching
* interceptors get applied according to their returned order value, if they implement
* the {@link org.springframework.core.Ordered} interface.
*
* <p>Creates a JDK proxy when proxy interfaces are given, and a CGLIB proxy for the
* actual target class if not. Note that the latter will only work if the target class
* does not have final methods, as a dynamic subclass will be created at runtime.
*
* <p>It's possible to cast a proxy obtained from this factory to {@link Advised},
* or to obtain the ProxyFactoryBean reference and programmatically manipulate it.
* This won't work for existing prototype references, which are independent. However,
* it will work for prototypes subsequently obtained from the factory. Changes to
* interception will work immediately on singletons (including existing references).
* However, to change interfaces or target it's necessary to obtain a new instance
* from the factory. This means that singleton instances obtained from the factory
* do not have the same object identity. However, they do have the same interceptors
* and target, and changing any reference will change all objects.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @see #setInterceptorNames
* @see #setProxyInterfaces
* @see org.aopalliance.intercept.MethodInterceptor
* @see org.springframework.aop.Advisor
* @see Advised
*/
public class ProxyFactoryBean extends ProxyCreatorSupport
implements FactoryBean, BeanClassLoaderAware, BeanFactoryAware {
/**
* This suffix in a value in an interceptor list indicates to expand globals.
*/
public static final String GLOBAL_SUFFIX = "*";
protected final Log logger = LogFactory.getLog(getClass());
private String[] interceptorNames;
private String targetName;
private boolean autodetectInterfaces = true;
private boolean singleton = true;
private AdvisorAdapterRegistry advisorAdapterRegistry = GlobalAdvisorAdapterRegistry.getInstance();
/**
* Indicates whether the proxy should be frozen before creation.
*/
private boolean freezeProxy = false;
private transient ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
/**
* Owning bean factory, which cannot be changed after this
* object is initialized.
*/
private transient BeanFactory beanFactory;
/** Whether the advisor chain has already been initialized */
private boolean advisorChainInitialized = false;
/** If this is a singleton, the cached singleton proxy instance */
private Object singletonInstance;
/**
* Set the names of the interfaces we're proxying. If no interface
* is given, a CGLIB for the actual class will be created.
* <p>This is essentially equivalent to the "setInterfaces" method,
* but mirrors TransactionProxyFactoryBean's "setProxyInterfaces".
* @see #setInterfaces
* @see AbstractSingletonProxyFactoryBean#setProxyInterfaces
*/
public void setProxyInterfaces(Class[] proxyInterfaces) throws ClassNotFoundException {
setInterfaces(proxyInterfaces);
}
/**
* Set the list of Advice/Advisor bean names. This must always be set
* to use this factory bean in a bean factory.
* <p>The referenced beans should be of type Interceptor, Advisor or Advice
* The last entry in the list can be the name of any bean in the factory.
* If it's neither an Advice nor an Advisor, a new SingletonTargetSource
* is added to wrap it. Such a target bean cannot be used if the "target"
* or "targetSource" or "targetName" property is set, in which case the
* "interceptorNames" array must contain only Advice/Advisor bean names.
* <p>NOTE: Specifying a target bean as final name in the "interceptorNames"
* list is deprecated and will be removed in a future Spring version.</b>
* Use the {@link #setTargetName "targetName"} property instead.
* @see org.aopalliance.intercept.MethodInterceptor
* @see org.springframework.aop.Advisor
* @see org.aopalliance.aop.Advice
* @see org.springframework.aop.target.SingletonTargetSource
*/
public void setInterceptorNames(String[] interceptorNames) {
this.interceptorNames = interceptorNames;
}
/**
* Set the name of the target bean. This is an alternative to specifying
* the target name at the end of the "interceptorNames" array.
* <p>You can also specify a target object or a TargetSource object
* directly, via the "target"/"targetSource" property, respectively.
* @see #setInterceptorNames(String[])
* @see #setTarget(Object)
* @see #setTargetSource(org.springframework.aop.TargetSource)
*/
public void setTargetName(String targetName) {
this.targetName = targetName;
}
/**
* Set whether to autodetect proxy interfaces if none specified.
* <p>Default is "true". Turn this flag off to create a CGLIB
* proxy for the full target class if no interfaces specified.
* @see #setProxyTargetClass
*/
public void setAutodetectInterfaces(boolean autodetectInterfaces) {
this.autodetectInterfaces = autodetectInterfaces;
}
/**
* Set the value of the singleton property. Governs whether this factory
* should always return the same proxy instance (which implies the same target)
* or whether it should return a new prototype instance, which implies that
* the target and interceptors may be new instances also, if they are obtained
* from prototype bean definitions. This allows for fine control of
* independence/uniqueness in the object graph.
*/
public void setSingleton(boolean singleton) {
this.singleton = singleton;
}
/**
* Specify the AdvisorAdapterRegistry to use.
* Default is the global AdvisorAdapterRegistry.
* @see org.springframework.aop.framework.adapter.GlobalAdvisorAdapterRegistry
*/
public void setAdvisorAdapterRegistry(AdvisorAdapterRegistry advisorAdapterRegistry) {
this.advisorAdapterRegistry = advisorAdapterRegistry;
}
public void setFrozen(boolean frozen) {
this.freezeProxy = frozen;
}
public void setBeanClassLoader(ClassLoader classLoader) {
this.beanClassLoader = classLoader;
}
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
checkInterceptorNames();
}
/**
* Return a proxy. Invoked when clients obtain beans from this factory bean.
* Create an instance of the AOP proxy to be returned by this factory.
* The instance will be cached for a singleton, and create on each call to
* <code>getObject() for a proxy.
* @return a fresh AOP proxy reflecting the current state of this factory
*/
public Object getObject() throws BeansException {
initializeAdvisorChain();
if (isSingleton()) {
return getSingletonInstance();
}
else {
if (this.targetName == null) {
logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +
"Enable prototype proxies by setting the 'targetName' property.");
}
return newPrototypeInstance();
}
}
/**
* Return the type of the proxy. Will check the singleton instance if
* already created, else fall back to the proxy interface (in case of just
* a single one), the target bean type, or the TargetSource's target class.
* @see org.springframework.aop.TargetSource#getTargetClass
*/
public Class getObjectType() {
synchronized (this) {
if (this.singletonInstance != null) {
return this.singletonInstance.getClass();
}
}
Class[] ifcs = getProxiedInterfaces();
if (ifcs.length == 1) {
return ifcs[0];
}
else if (ifcs.length > 1) {
return createCompositeInterface(ifcs);
}
else if (this.targetName != null && this.beanFactory != null) {
return this.beanFactory.getType(this.targetName);
}
else {
return getTargetClass();
}
}
public boolean isSingleton() {
return this.singleton;
}
/**
* Create a composite interface Class for the given interfaces,
* implementing the given interfaces in one single Class.
* <p>The default implementation builds a JDK proxy class for the
* given interfaces.
* @param interfaces the interfaces to merge
* @return the merged interface as Class
* @see java.lang.reflect.Proxy#getProxyClass
*/
protected Class createCompositeInterface(Class[] interfaces) {
return ClassUtils.createCompositeInterface(interfaces, this.beanClassLoader);
}
/**
* Return the singleton instance of this class's proxy object,
* lazily creating it if it hasn't been created already.
* @return the shared singleton proxy
*/
private synchronized Object getSingletonInstance() {
if (this.singletonInstance == null) {
this.targetSource = freshTargetSource();
if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
// Rely on AOP infrastructure to tell us what interfaces to proxy.
Class targetClass = getTargetClass();
if (targetClass == null) {
throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");
}
setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.beanClassLoader));
}
// Initialize the shared singleton instance.
super.setFrozen(this.freezeProxy);
this.singletonInstance = getProxy(createAopProxy());
}
return this.singletonInstance;
}
/**
* Create a new prototype instance of this class's created proxy object,
* backed by an independent AdvisedSupport configuration.
* @return a totally independent proxy, whose advice we may manipulate in isolation
*/
private synchronized Object newPrototypeInstance() {
// In the case of a prototype, we need to give the proxy
// an independent instance of the configuration.
// In this case, no proxy will have an instance of this object's configuration,
// but will have an independent copy.
if (logger.isTraceEnabled()) {
logger.trace("Creating copy of prototype ProxyFactoryBean config: " + this);
}
ProxyCreatorSupport copy = new ProxyCreatorSupport(getAopProxyFactory());
// The copy needs a fresh advisor chain, and a fresh TargetSource.
TargetSource targetSource = freshTargetSource();
copy.copyConfigurationFrom(this, targetSource, freshAdvisorChain());
if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
// Rely on AOP infrastructure to tell us what interfaces to proxy.
copy.setInterfaces(
ClassUtils.getAllInterfacesForClass(targetSource.getTargetClass(), this.beanClassLoader));
}
copy.setFrozen(this.freezeProxy);
if (logger.isTraceEnabled()) {
logger.trace("Using ProxyCreatorSupport copy: " + copy);
}
return getProxy(copy.createAopProxy());
}
/**
* Return the proxy object to expose.
* <p>The default implementation uses a
Other Spring Framework examples (source code examples)Here is a short list of links related to this Spring Framework ProxyFactoryBean.java source code file: |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.