📄 proxyfactorybean.java
字号:
/*
* Copyright 2002-2004 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.util.ArrayList;
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.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.support.AopUtils;
import org.springframework.aop.target.SingletonTargetSource;
import org.springframework.beans.BeansException;
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.ListableBeanFactory;
import org.springframework.core.OrderComparator;
/**
* FactoryBean implementation for use to source AOP proxies from a Spring BeanFactory.
*
* <p>Interceptors and Advisors are identified by a list of bean names in the current
* bean factory. These beans should be of type Interceptor or Advisor. The last entry
* in the list can be the name of any bean in the factory. If it's neither an
* Interceptor nor an Advisor, a new SingletonTargetSource is added to wrap it. If it;s
* a TargetSource, it is used as this proxy factory's TargetSource. It's normally preferred
* to use the "targetSource" property to set the TargetSource. It is not possible to use
* both the targetSource property and an interceptor name: this is treated as a
* configuration error.
*
* <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 Ordered interface. An interceptor name list may not conclude
* with a global "xxx*" pattern, as global interceptors cannot invoke targets.
*
* <p>Creates a J2SE proxy when proxy interfaces are given, 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 <code>Advised</code>, 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.framework.Advised
* @see org.springframework.aop.target.SingletonTargetSource
*/
public class ProxyFactoryBean extends AdvisedSupport
implements FactoryBean, BeanFactoryAware, AdvisedSupportListener {
/*
* Implementation notes. There are two cases of usage of this class:
* usage as a singleton, when only one object will be created, and usage
* as a prototype, when the FactoryBean.getObject() method must return an
* independent proxy on each invocation. In the latter case, a distinct instance of
* any non-singleton Advisors or Advices must be used, as well as a distinct
* target/TargetSource instance if the target is a prototype and is specified in the
* interceptorNames list, rather than using the target or targetSource property.
*
* If this factory is used as a singleton, the advice chain in this class is used
* and all Advisors/Advices are materialized when the singleton instance is created.
* If it's a prototype, new AdvisedSupport instances are created with
* a copy of the advice chain to create each proxy and support independent
* manipulation of advice. Any advisor/advice bean names that that are prototypes
* are replaced by placeholders in the advisor chain held in this class and
* an independent advisor chain is materialized when each prototype instance
* is created.
*
* Revision as of September 20, 2004 partly based on patch provided by Chris Eldredge.
*/
/**
* This suffix in a value in an interceptor list indicates to expand globals.
*/
public static final String GLOBAL_SUFFIX = "*";
/**
* Names of Advisor and Advice beans in the factory.
* Default is for globals expansion only.
*/
private String[] interceptorNames;
private boolean singleton = true;
private AdvisorAdapterRegistry advisorAdapterRegistry = GlobalAdvisorAdapterRegistry.getInstance();
/**
* Indicates whether the proxy should be frozen before creation.
*/
private boolean freezeProxy = false;
/**
* Owning bean factory, which cannot be changed after this
* object is initialized.
*/
private BeanFactory beanFactory;
/**
* Name of the target or TargetSource bean. Null if the TargetSource is not specified in
* the interceptorNames list.
*/
private String targetName;
/** 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>Alternatively, use the "interfaces" property of type Class array
* (the bean factory will automatically convert from String to Class there).
* @see #setInterfaces
*/
public void setProxyInterfaces(String[] interfaceNames) throws ClassNotFoundException {
Class[] interfaces = AopUtils.toInterfaceArray(interfaceNames);
setInterfaces(interfaces);
}
/**
* 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
* property is set, in which case the interceptorNames array must contain
* only Advice/Advisor bean names.
* @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 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 setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
createAdvisorChain();
if (this.singleton) {
this.targetSource = freshTargetSource();
// Eagerly initialize the shared singleton instance.
getSingletonInstance();
// We must listen to superclass advice change events to recache the singleton
// instance if necessary.
addListener(this);
}
}
/**
* 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
* getObject() for a proxy.
* @return a fresh AOP proxy reflecting the current state of this factory
*/
public Object getObject() throws BeansException {
return this.singleton ? getSingletonInstance() : newPrototypeInstance();
}
/**
* Return the type of the proxy. Will check the singleton instance if
* already created, falling back to the TargetSource's target class.
* @see org.springframework.aop.TargetSource#getTargetClass
*/
public Class getObjectType() {
return (this.singletonInstance != null ?
this.singletonInstance.getClass() : getTargetSource().getTargetClass());
}
public boolean isSingleton() {
return this.singleton;
}
private Object getSingletonInstance() {
if (this.singletonInstance == null) {
super.setFrozen(this.freezeProxy);
this.singletonInstance = createAopProxy().getProxy();
}
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 poxy will have an instance of this object's configuration,
// but will have an independent copy.
if (logger.isDebugEnabled()) {
logger.debug("Creating copy of prototype ProxyFactoryBean config: " + this);
}
AdvisedSupport copy = new AdvisedSupport();
// The copy needs a fresh advisor chain, and a fresh TargetSource.
copy.copyConfigurationFrom(this, freshTargetSource(), freshAdvisorChain());
copy.setFrozen(this.freezeProxy);
if (logger.isDebugEnabled()) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -