📄 proxyfactorybean.java
字号:
logger.debug("Copy has config: " + copy);
}
return copy.createAopProxy().getProxy();
}
/**
* Create the advisor (interceptor) chain. Aadvisors that are sourced
* from a BeanFactory will be refreshed each time a new prototype instance
* is added. Interceptors added programmatically through the factory API
* are unaffected by such changes.
*/
private void createAdvisorChain() throws AopConfigException, BeansException {
if (this.interceptorNames == null || this.interceptorNames.length == 0) {
return;
}
// Globals can't be last unless we specified a targetSource using the property...
if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) &&
this.targetSource == EMPTY_TARGET_SOURCE) {
throw new AopConfigException("Target required after globals");
}
// materialize interceptor chain from bean names
for (int i = 0; i < this.interceptorNames.length; i++) {
String name = this.interceptorNames[i];
if (logger.isDebugEnabled()) {
logger.debug("Configuring advisor or advice '" + name + "'");
}
if (name.endsWith(GLOBAL_SUFFIX)) {
if (!(this.beanFactory instanceof ListableBeanFactory)) {
throw new AopConfigException(
"Can only use global advisors or interceptors with a ListableBeanFactory");
}
addGlobalAdvisor((ListableBeanFactory) this.beanFactory,
name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
continue;
}
else if (i == this.interceptorNames.length - 1 && this.targetSource == EMPTY_TARGET_SOURCE) {
// The last name in the chain may be an Advisor/Advice or a target/TargetSource.
// Unfortunately we don't know; we must look at type of the bean.
if (!isNamedBeanAnAdvisorOrAdvice(this.interceptorNames[i])) {
// Must be an interceptor.
this.targetName = this.interceptorNames[i];
if (logger.isInfoEnabled()) {
logger.info("Bean with name '" + this.interceptorNames[i] +
"' concluding interceptor chain is not an advisor class: " +
"treating it as a target or TargetSource");
}
continue;
}
// If it IS an advice, or we can't tell, fall through and treat it as an advice...
}
// If we get here, we need to add a named interceptor.
// We must check if it's a singleton or prototype.
Object advice = null;
if (isSingleton() || this.beanFactory.isSingleton(this.interceptorNames[i])) {
// Add the real Advisor/Advice to the chain.
advice = this.beanFactory.getBean(this.interceptorNames[i]);
}
else {
// It's a prototype Advice or Advisor: replace with a prototype.
// Avoid unnecessary creation of prototype bean just for advisor chain initialization.
advice = new PrototypePlaceholderAdvisor(interceptorNames[i]);
}
addAdvisorOnChainCreation(advice, this.interceptorNames[i]);
}
}
/**
* Look at bean factory metadata to work out whether this bean name,
* which concludes the interceptorNames list, is an Advisor or Advice,
* or may be a target.
* @param beanName bean name to check
* @return true if it's an Advisor or Advice
*/
private boolean isNamedBeanAnAdvisorOrAdvice(String beanName) {
Class namedBeanClass = this.beanFactory.getType(beanName);
if (namedBeanClass != null) {
return Advisor.class.isAssignableFrom(namedBeanClass) ||
Advice.class.isAssignableFrom(namedBeanClass);
}
// Treat it as an Advisor if we can't tell.
return true;
}
/**
* Return an independent advisor chain.
* We need to do this every time a new prototype instance is returned,
* to return distinct instances of prototype Advisors and Advices.
*/
private List freshAdvisorChain() {
Advisor[] advisors = getAdvisors();
List freshAdvisors = new ArrayList(advisors.length);
for (int i = 0; i < advisors.length; i++) {
if (advisors[i] instanceof PrototypePlaceholderAdvisor) {
PrototypePlaceholderAdvisor pa = (PrototypePlaceholderAdvisor) advisors[i];
if (logger.isDebugEnabled()) {
logger.debug("Refreshing bean named '" + pa.getBeanName() + "'");
}
// Replace the placeholder with a fresh protoype instance resulting
// from a getBean() lookup
Object bean = this.beanFactory.getBean(pa.getBeanName());
Advisor refreshedAdvisor = namedBeanToAdvisor(bean);
freshAdvisors.add(refreshedAdvisor);
}
else {
// Add the shared instance.
freshAdvisors.add(advisors[i]);
}
}
return freshAdvisors;
}
/**
* Add all global interceptors and pointcuts.
*/
private void addGlobalAdvisor(ListableBeanFactory beanFactory, String prefix) {
String[] globalAdvisorNames = BeanFactoryUtils.beanNamesIncludingAncestors(beanFactory, Advisor.class);
String[] globalInterceptorNames = BeanFactoryUtils.beanNamesIncludingAncestors(beanFactory, Interceptor.class);
List beans = new ArrayList(globalAdvisorNames.length + globalInterceptorNames.length);
Map names = new HashMap();
for (int i = 0; i < globalAdvisorNames.length; i++) {
String name = globalAdvisorNames[i];
Object bean = beanFactory.getBean(name);
beans.add(bean);
names.put(bean, name);
}
for (int i = 0; i < globalInterceptorNames.length; i++) {
String name = globalInterceptorNames[i];
Object bean = beanFactory.getBean(name);
beans.add(bean);
names.put(bean, name);
}
Collections.sort(beans, new OrderComparator());
for (Iterator it = beans.iterator(); it.hasNext();) {
Object bean = it.next();
String name = (String) names.get(bean);
if (name.startsWith(prefix)) {
addAdvisorOnChainCreation(bean, name);
}
}
}
/**
* Invoked when advice chain is created.
* <p>Add the given advice, advisor or object to the interceptor list.
* Because of these three possibilities, we can't type the signature
* more strongly.
* @param next advice, advisor or target object
* @param name bean name from which we obtained this object in our owning
* bean factory
*/
private void addAdvisorOnChainCreation(Object next, String name) {
if (logger.isDebugEnabled()) {
logger.debug("Adding advisor or TargetSource [" + next + "] with name [" + name + "]");
}
// We need to convert to an Advisor if necessary so that our source reference
// matches what we find from superclass interceptors.
Advisor advisor = namedBeanToAdvisor(next);
// If it wasn't just updating the TargetSource.
if (logger.isDebugEnabled()) {
logger.debug("Adding advisor with name [" + name + "]");
}
addAdvisor((Advisor) advisor);
}
/**
* Return a TargetSource to use when creating a proxy. If the target was not
* specified at the end of the interceptorNames list, the TargetSource will be
* this class' TargetSource member. Otherwise, we get the target bean and wrap
* it in a TargetSource if necessary.
*/
private TargetSource freshTargetSource() {
if (this.targetName == null) {
if (logger.isDebugEnabled()) {
logger.debug("Not refreshing target: bean name not specified in interceptorNames");
}
return this.targetSource;
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Refreshing target with name '" + this.targetName + "'");
}
Object target = this.beanFactory.getBean(this.targetName);
return (target instanceof TargetSource) ? (TargetSource) target : new SingletonTargetSource(target);
}
}
/**
* Convert the following object sourced from calling getBean() on a name in the
* interceptorNames array to an Advisor or TargetSource.
*/
private Advisor namedBeanToAdvisor(Object next) {
try {
return this.advisorAdapterRegistry.wrap(next);
}
catch (UnknownAdviceTypeException ex) {
// We expected this to be an Advisor or Advice,
// but it wasn't. This is a configuration error.
throw new AopConfigException("Unknown advisor type " + next.getClass() +
"; Can only include Advisor or Advice type beans in interceptorNames chain except for last entry," +
"which may also be target or TargetSource", ex);
}
}
/**
* @see org.springframework.aop.framework.AdvisedSupportListener#activated
*/
public void activated(AdvisedSupport advisedSupport) {
// Nothing to do.
}
/**
* Blow away and recache singleton on an advice change.
* @see org.springframework.aop.framework.AdvisedSupportListener#adviceChanged
*/
public void adviceChanged(AdvisedSupport advisedSupport) {
if (this.singleton) {
logger.info("Advice has changed; recaching singleton instance");
this.singletonInstance = null;
getSingletonInstance();
}
}
/**
* Used in the interceptor chain where we need to replace a bean with a prototype
* on creating a proxy.
*/
private static class PrototypePlaceholderAdvisor implements Advisor {
private final String beanName;
private final String message;
public PrototypePlaceholderAdvisor(String beanName) {
this.beanName = beanName;
this.message = "Placeholder for prototype Advisor/Advice with bean name ='" + beanName + "'";
}
public String getBeanName() {
return beanName;
}
public Advice getAdvice() {
throw new UnsupportedOperationException("Cannot invoke methods: " + this.message);
}
public boolean isPerInstance() {
throw new UnsupportedOperationException("Cannot invoke methods: " + this.message);
}
public String toString() {
return this.message;
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -