lookup-method
lookup-method 是 Spring Framework 中用于实现依赖查找方法注入的一种方式。
它主要用于解决以下问题:在单例 bean 中,如果需要某个方法返回一个原型(prototype)类型的 bean,而该方法被多次调用,希望每次调用都能得到一个新的实例,而不是同一个实例。lookup-method 就可以帮助实现这样的需求。
in short 解决在单例Bean 中需要引用原型Bean的问题
public class PrototypeBean {
private String name;
public PrototypeBean() {
this.name = "PrototypeBean-" + System.nanoTime();
}
public String getName() {
return name;
}
}
public abstract class SingletonBean {
// 抽象方法,用于获取原型实例 (Spring 会基于cglib生成SingletonBean的子类, 实现这个方法)
public abstract PrototypeBean getPrototypeInstance();
public void displayPrototypeName() {
// 调用被覆盖的方法来获取原型实例
PrototypeBean prototypeBean = getPrototypeInstance();
System.out.println("Prototype name: " + prototypeBean.getName());
}
}
<!-- 配置 PrototypeBean -->
<bean id="prototypeBean" class="com.example.PrototypeBean" scope="prototype"/>
<!-- 配置 SingletonBean,使用 lookup-method 指定需要被子类覆盖的方法 (基于Cglib 生成一个代理对象) -->
<bean id="singletonBean" class="com.example.SingletonBean">
<!-- 将 getPrototypeInstance 方法 实现为返回容器的prototypeBean -->
<lookup-method name="getPrototypeInstance" bean="prototypeBean"/>
</bean>在这个例子中,每次调用 displayPrototypeName 方法都会得到一个新的 PrototypeBean 实例,因为 getPrototypeInstance 方法被代理类覆盖;
代理类是由 Spring 在运行时生成, 基于Cglib 生成一个代理对象 {@link org.springframework.beans.factory.support.CglibSubclassingInstantiationStrategy}
相关源码
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])
@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;
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
// Prepare method overrides.
try {
/**
* 准备和验证 lookup-method 和 replace-method;
* 注意: 这里只是标记, 真正处理是在实例化时, 选择策略生成一个CgLib的代理对象 {@link org.springframework.beans.factory.support.CglibSubclassingInstantiationStrategy}
* 关于它们的作用见笔记 [[Spring lookup-method 和 replace-method.md]]
*/
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
....看这个策略 org.springframework.beans.factory.support.CglibSubclassingInstantiationStrategy 的这个静态类
org.springframework.beans.factory.support.CglibSubclassingInstantiationStrategy.LookupOverrideMethodInterceptor
replace-method
replace-method 是Spring 动态借助CGLIB改变bean中的方法,通过改变方法逻辑注入对象,该方法的使用需要依赖Spring提供的MethodReplacer 接口实现。
in short 可以动态的 替换 任意bean的 任意方法, 类似jdk的方法拦截
public class Calculator {
//被拦截的方法
public String computeValue(String input) {
// some real code...
}
}替换的bean需要实现MethodReplacer
//实现 MethodReplacer 方法拦截器
public class ReplacementComputeValue implements MethodReplacer {
public Object reimplement(Object o, Method m, Object[] args) throws Throwable {
// get the input value, work with it, and return a computed result
String input = (String) args[0];
...
return ...;
}
}配置
<bean id="calculator" class="x.y.z.Calculator">
<!-- 替换 computeValue 方法, 指向 replacementComputeValue 方法拦截器 -->
<replaced-method name="computeValue" replacer="replacementComputeValue">
<arg-type>String</arg-type>
</replaced-method>
</bean>
<!-- 方法拦截器 -->
<bean id="replacementComputeValue" class="a.b.c.ReplacementComputeValue"/>相关源码
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])
@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;
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
// Prepare method overrides.
try {
/**
* 准备和验证 lookup-method 和 replace-method;
* 注意: 这里只是标记, 真正处理是在实例化时, 选择策略生成一个CgLib的代理对象 {@link org.springframework.beans.factory.support.CglibSubclassingInstantiationStrategy}
* 关于它们的作用见笔记 [[Spring lookup-method 和 replace-method.md]]
*/
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
....看这个策略 org.springframework.beans.factory.support.CglibSubclassingInstantiationStrategy 的这个静态类
org.springframework.beans.factory.support.CglibSubclassingInstantiationStrategy.ReplaceOverrideMethodInterceptor