Spring源码-lookup-method和replaced-method

lookup-method和replaced-method平时用的很少,主要用来解决单例bean中使用原型bean的场景。

一、应用

lookup-method:

A.java

public class A {
public B getB() {
	return null;
}

public void printA(){
	System.out.println("AAA:"+this);
	this.getB().print();
}
}

B.java

public class B {

public void print() {
	System.out.println("BBBBB:"+this);
}
}

loopup.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">


	 <bean id="a" class="lookup.A">
			<lookup-method name="getB" bean="b"/>
	 </bean>

	 <bean id="b" class="lookup.B" scope="prototype"/>

<!--	<bean id="a" class="lookup.A">-->
<!--		<replaced-method name="getB" replacer="b"/>-->
<!--	</bean>-->

<!--	<bean id="b" class="lookup.B" scope="prototype"/>-->
</beans>

Main.java

public class Main {
public static void main(String[] args) {
	ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:lookup.xml");

	A bean = applicationContext.getBean(A.class);
	bean.printA();

	bean = applicationContext.getBean(A.class);
	bean.printA();

}
}

replaced-method:

将上面的B.java修改为:

public class B implements MethodReplacer, ApplicationContextAware {
private ApplicationContext applicationContext;

public void print() {
	System.out.println("BBBBB:"+this);
}

@Override
public Object reimplement(Object obj, Method method, Object[] args) throws Throwable {
	return this.applicationContext.getBean(B.class);
}

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
	this.applicationContext = applicationContext;
}
}

lookup.xml修改为:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">


<!--	 <bean id="a" class="lookup.A">-->
<!--			<lookup-method name="getB" bean="b"/>-->
<!--	 </bean>-->

<!--	 <bean id="b" class="lookup.B" scope="prototype"/>-->

	<bean id="a" class="lookup.A">
		<replaced-method name="getB" replacer="b"/>
	</bean>

	<bean id="b" class="lookup.B" scope="prototype"/>
</beans>

cglib例子:

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class Test {
	public void test() {
		System.out.println("调用 test");
	}
	public static void main(String[] args) {
		Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(Test.class);
		enhancer.setCallback(new MethodInterceptor() {
			@Override
			public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
				System.out.println("before method run...");
				Object result = proxy.invokeSuper(obj, args);
				System.out.println("after method run...");
				return result;
			}
		});

		Test o = (Test) enhancer.create();
		o.test();
	}
}

二、Spring源码解读lookup-method和replaced-method
前面Spring解析xml文件的bean标签时:

BeanDefinitionParserDelegate的parseBeanDefinitionElement方法:

public AbstractBeanDefinition parseBeanDefinitionElement(
		Element ele, String beanName, @Nullable BeanDefinition containingBean) {

	this.parseState.push(new BeanEntry(beanName));

	String className = null;
	if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
		className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
	}
	String parent = null;
	if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
		parent = ele.getAttribute(PARENT_ATTRIBUTE);
	}

	try {
		AbstractBeanDefinition bd = createBeanDefinition(className, parent);

		parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
		bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));

		parseMetaElements(ele, bd);
		parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
		parseReplacedMethodSubElements(ele, bd.getMethodOverrides());

		parseConstructorArgElements(ele, bd);
		parsePropertyElements(ele, bd);
		parseQualifierElements(ele, bd);

		bd.setResource(this.readerContext.getResource());
		bd.setSource(extractSource(ele));

		return bd;
	}
	catch (ClassNotFoundException ex) {
		error("Bean class [" + className + "] not found", ele, ex);
	}
	catch (NoClassDefFoundError err) {
		error("Class that bean class [" + className + "] depends on not found", ele, err);
	}
	catch (Throwable ex) {
		error("Unexpected failure during bean definition parsing", ele, ex);
	}
	finally {
		this.parseState.pop();
	}

	return null;
}

其中:

parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());

将lookup-method和replaced-method标签对应的方法名加到beanDefinition的methodOverrides中。

AbstractAutowireCapableBeanFactory的createBean:

@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
		throws BeanCreationException {

	if (logger.isTraceEnabled()) {
		logger.trace("Creating instance of bean '" + beanName + "'");
	}
	RootBeanDefinition mbdToUse = mbd;

	// Make sure bean class is actually resolved at this point, and
	// clone the bean definition in case of a dynamically resolved Class
	// which cannot be stored in the shared merged bean definition.
	Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
	if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
		mbdToUse = new RootBeanDefinition(mbd);
		mbdToUse.setBeanClass(resolvedClass);
	}

	// Prepare method overrides.
	try {
		mbdToUse.prepareMethodOverrides();
	}
	catch (BeanDefinitionValidationException ex) {
		throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
				beanName, "Validation of method overrides failed", ex);
	}

	try {
		// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
		Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
		if (bean != null) {
			return bean;
		}
	}
	catch (Throwable ex) {
		throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
				"BeanPostProcessor before instantiation of bean failed", ex);
	}

	try {
		Object beanInstance = doCreateBean(beanName, mbdToUse, args);
		if (logger.isTraceEnabled()) {
			logger.trace("Finished creating instance of bean '" + beanName + "'");
		}
		return beanInstance;
	}
	catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
		// A previously detected exception with proper bean creation context already,
		// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
		throw ex;
	}
	catch (Throwable ex) {
		throw new BeanCreationException(
				mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
	}
}

其中的mbdToUse.prepareMethodOverrides()处理beanDefinition的methodOverrides。

public void prepareMethodOverrides() throws BeanDefinitionValidationException {
	// Check that lookup methods exist and determine their overloaded status.
	if (hasMethodOverrides()) {
		getMethodOverrides().getOverrides().forEach(this::prepareMethodOverride);
	}
}

	public boolean hasMethodOverrides() {
	return !this.methodOverrides.isEmpty();
}

protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException {
	int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName());
	if (count == 0) {
		throw new BeanDefinitionValidationException(
				"Invalid method override: no method with name '" + mo.getMethodName() +
				"' on class [" + getBeanClassName() + "]");
	}
	else if (count == 1) {
		// Mark override as not overloaded, to avoid the overhead of arg type checking.
		mo.setOverloaded(false);
	}
}

如果beanDefinition的methodOverrides非空,则设置MethodOverride的overloaded为false。

doCreateBean->createBeanInstance->instantiateBean:

	protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) {
	try {
		Object beanInstance;
		if (System.getSecurityManager() != null) {
			beanInstance = AccessController.doPrivileged(
					(PrivilegedAction<Object>) () -> getInstantiationStrategy().instantiate(mbd, beanName, this),
					getAccessControlContext());
		}
		else {
			beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this);
		}
		BeanWrapper bw = new BeanWrapperImpl(beanInstance);
		initBeanWrapper(bw);
		return bw;
	}
	catch (Throwable ex) {
		throw new BeanCreationException(
				mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
	}
}

其中getInstantiationStrategy():

public AbstractAutowireCapableBeanFactory() {
	super();
	ignoreDependencyInterface(BeanNameAware.class);
	ignoreDependencyInterface(BeanFactoryAware.class);
	ignoreDependencyInterface(BeanClassLoaderAware.class);
	if (NativeDetector.inNativeImage()) {
		this.instantiationStrategy = new SimpleInstantiationStrategy();
	}
	else {
		this.instantiationStrategy = new CglibSubclassingInstantiationStrategy();
	}
}

由上可知instantiationStrategy是CglibSubclassingInstantiationStrategy。

CglibSubclassingInstantiationStrategy类中:

private static final int PASSTHROUGH = 0;
private static final int LOOKUP_OVERRIDE = 1;
private static final int METHOD_REPLACER = 2;

SimpleInstantiationStrategy的instantiate:

@Override
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
	// Don't override the class with CGLIB if no overrides.
	if (!bd.hasMethodOverrides()) {
		Constructor<?> constructorToUse;
		synchronized (bd.constructorArgumentLock) {
			constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
			if (constructorToUse == null) {
				final Class<?> clazz = bd.getBeanClass();
				if (clazz.isInterface()) {
					throw new BeanInstantiationException(clazz, "Specified class is an interface");
				}
				try {
					if (System.getSecurityManager() != null) {
						constructorToUse = AccessController.doPrivileged(
								(PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
					}
					else {
						constructorToUse = clazz.getDeclaredConstructor();
					}
					bd.resolvedConstructorOrFactoryMethod = constructorToUse;
				}
				catch (Throwable ex) {
					throw new BeanInstantiationException(clazz, "No default constructor found", ex);
				}
			}
		}
		return BeanUtils.instantiateClass(constructorToUse);
	}
	else {
		// Must generate CGLIB subclass.
		return instantiateWithMethodInjection(bd, beanName, owner);
	}
}

当有lookup-method或replaced-method标签时,beanDefinition的methodOverrides非空。此时走else分支创建instantiateWithMethodInjection。

CglibSubclassingInstantiationStrategy的instantiateWithMethodInjection:

@Override
protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
	return instantiateWithMethodInjection(bd, beanName, owner, null);
}

@Override
protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
		@Nullable Constructor<?> ctor, Object... args) {

	// Must generate CGLIB subclass...
	return new CglibSubclassCreator(bd, owner).instantiate(ctor, args);
}

CglibSubclassingInstantiationStrategy的内部类CglibSubclassCreator的instantiate:

public Object instantiate(@Nullable Constructor<?> ctor, Object... args) {
		Class<?> subclass = createEnhancedSubclass(this.beanDefinition);
		Object instance;
		if (ctor == null) {
			instance = BeanUtils.instantiateClass(subclass);
		}
		else {
			try {
				Constructor<?> enhancedSubclassConstructor = subclass.getConstructor(ctor.getParameterTypes());
				instance = enhancedSubclassConstructor.newInstance(args);
			}
			catch (Exception ex) {
				throw new BeanInstantiationException(this.beanDefinition.getBeanClass(),
						"Failed to invoke constructor for CGLIB enhanced subclass [" + subclass.getName() + "]", ex);
			}
		}
		// SPR-10785: set callbacks directly on the instance instead of in the
		// enhanced class (via the Enhancer) in order to avoid memory leaks.
		Factory factory = (Factory) instance;
		factory.setCallbacks(new Callback[] {NoOp.INSTANCE,
				new LookupOverrideMethodInterceptor(this.beanDefinition, this.owner),
				new ReplaceOverrideMethodInterceptor(this.beanDefinition, this.owner)});
		return instance;
	}

用cglib做了动态代理。cglib使用参考上面的例子。Callbacks的下标和CglibSubclassingInstantiationStrategy的三个属性相对应。因此上面的instantiateBean方法调用:

beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this);

返回了cglib代理后的对象。当执行bean的方法时,会先执行cglib的回调方法。

private Class<?> createEnhancedSubclass(RootBeanDefinition beanDefinition) {
		Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(beanDefinition.getBeanClass());
		enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
		if (this.owner instanceof ConfigurableBeanFactory) {
			ClassLoader cl = ((ConfigurableBeanFactory) this.owner).getBeanClassLoader();
			enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(cl));
		}
		enhancer.setCallbackFilter(new MethodOverrideCallbackFilter(beanDefinition));
		enhancer.setCallbackTypes(CALLBACK_TYPES);
		return enhancer.createClass();
	}

	private static final Class<?>[] CALLBACK_TYPES = new Class<?>[]
			{NoOp.class, LookupOverrideMethodInterceptor.class, ReplaceOverrideMethodInterceptor.class};


private static class MethodOverrideCallbackFilter extends CglibIdentitySupport implements CallbackFilter {

	private static final Log logger = LogFactory.getLog(MethodOverrideCallbackFilter.class);

	public MethodOverrideCallbackFilter(RootBeanDefinition beanDefinition) {
		super(beanDefinition);
	}

	@Override
	public int accept(Method method) {
		MethodOverride methodOverride = getBeanDefinition().getMethodOverrides().getOverride(method);
		if (logger.isTraceEnabled()) {
			logger.trace("MethodOverride for " + method + ": " + methodOverride);
		}
		if (methodOverride == null) {
			return PASSTHROUGH;
		}
		else if (methodOverride instanceof LookupOverride) {
			return LOOKUP_OVERRIDE;
		}
		else if (methodOverride instanceof ReplaceOverride) {
			return METHOD_REPLACER;
		}
		throw new UnsupportedOperationException("Unexpected MethodOverride subclass: " +
				methodOverride.getClass().getName());
	}
}

MethodOverrideCallbackFilter的accept通过MethodOverride和CglibSubclassingInstantiationStrategy的三个属性相映射。调用MethodOverrideCallbackFilter的accept过滤CallBack,得到Callbacks对应的下标,调用回调函数执行。

lookup-method标签的回调函数:

private static class LookupOverrideMethodInterceptor extends CglibIdentitySupport implements MethodInterceptor {

	private final BeanFactory owner;

	public LookupOverrideMethodInterceptor(RootBeanDefinition beanDefinition, BeanFactory owner) {
		super(beanDefinition);
		this.owner = owner;
	}

	@Override
	public Object intercept(Object obj, Method method, Object[] args, MethodProxy mp) throws Throwable {
		// Cast is safe, as CallbackFilter filters are used selectively.
		LookupOverride lo = (LookupOverride) getBeanDefinition().getMethodOverrides().getOverride(method);
		Assert.state(lo != null, "LookupOverride not found");
		Object[] argsToUse = (args.length > 0 ? args : null);  // if no-arg, don't insist on args at all
		if (StringUtils.hasText(lo.getBeanName())) {
			Object bean = (argsToUse != null ? this.owner.getBean(lo.getBeanName(), argsToUse) :
					this.owner.getBean(lo.getBeanName()));
			// Detect package-protected NullBean instance through equals(null) check
			return (bean.equals(null) ? null : bean);
		}
		else {
			return (argsToUse != null ? this.owner.getBean(method.getReturnType(), argsToUse) :
					this.owner.getBean(method.getReturnType()));
		}
	}
}

通过MethodOverride获得beanName,再通过getBean获取bean并返回。

replaced-method标签的回调函数:

private static class ReplaceOverrideMethodInterceptor extends CglibIdentitySupport implements MethodInterceptor {

	private final BeanFactory owner;

	public ReplaceOverrideMethodInterceptor(RootBeanDefinition beanDefinition, BeanFactory owner) {
		super(beanDefinition);
		this.owner = owner;
	}

	@Override
	public Object intercept(Object obj, Method method, Object[] args, MethodProxy mp) throws Throwable {
		ReplaceOverride ro = (ReplaceOverride) getBeanDefinition().getMethodOverrides().getOverride(method);
		Assert.state(ro != null, "ReplaceOverride not found");
		// TODO could cache if a singleton for minor performance optimization
		MethodReplacer mr = this.owner.getBean(ro.getMethodReplacerBeanName(), MethodReplacer.class);
		return mr.reimplement(obj, method, args);
	}
}

通过MethodOverride获得beanName,再通过getBean获取类型为MethodReplacer的bean并调用MethodReplacer的reimplement并返回。

posted @ 2022-09-28 22:19  shigp1  阅读(139)  评论(0编辑  收藏  举报