lookup-method和replace-method注入

Spring的方法注入可分为两种

  • 查找方法注入:用于注入方法返回结果,也就是说能通过配置方式替换方法返回结果。即我们通常所说的lookup-method注入。
  • 替换方法注入:可以实现方法主体或返回结果的替换,即我们通常所说的replaced-method注入。

1.lookup-method注入

解决单例bean引用原型bean的问题。

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

	<bean id="apple" class="com.self.bean.initialization.method.overrides.lookup.Apple"/>
	<bean id="banana" class="com.self.bean.initialization.method.overrides.lookup.Banana"/>

	<bean id="fruitPlate1" class="com.self.bean.initialization.method.overrides.lookup.FruitPlate">
		<lookup-method bean="apple" name="getFruit"></lookup-method>
	</bean>
	<bean id="fruitPlate2" class="com.self.bean.initialization.method.overrides.lookup.FruitPlate">
		<lookup-method bean="banana" name="getFruit"></lookup-method>
	</bean>
</beans>
public class Fruit {
	public Fruit() {
		System.out.println("I got a Fruit");
	}
}
public class Apple extends Fruit {
	public Apple() {
		System.out.println("I got a Apple");
	}

	public void doSomething() {
		System.out.println("Apple doSomething");
	}
}
public class Banana extends Fruit {
	public Banana() {
		System.out.println("I got a Banana");
	}
}
public abstract class FruitPlate {
	public abstract Fruit getFruit();
}
public class LookUpTest {
	public static void main(String[] args) {
		ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("method.overrides.lookup.xml");
		FruitPlate fruitPlate1 = (FruitPlate) classPathXmlApplicationContext.getBean("fruitPlate1");
		Apple apple = (Apple) fruitPlate1.getFruit();
		apple.doSomething();
	}
}

输出:

> Task :spring-debug:LookUpTest.main()
I got a Fruit
I got a Apple
I got a Fruit
I got a Banana
Apple doSomething

源码分析

createBean() 时将mbd属性methodOverrides的overloaded设置为false.

// Prepare method overrides.
		try {
			mbdToUse.prepareMethodOverrides();
		}

在这里插入图片描述
调用CGLIB设置代理

	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 {

			//由于上文已经把overloaded设置为false. 所以走此逻辑
			// Must generate CGLIB subclass.
			//必须生成CGLIB字类
			return instantiateWithMethodInjection(bd, beanName, owner);
		}
	}
		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;
		}

LookUpTest
//获取配置的实例
Apple apple = (Apple) fruitPlate1.getFruit();

		public Object intercept(Object obj, Method method, Object[] args, MethodProxy mp) throws Throwable {
			// Cast is safe, as CallbackFilter filters are used selectively.
			// 获取mbd中的LookupOverride
			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())) {
				//返回bean
				return (argsToUse != null ? this.owner.getBean(lo.getBeanName(), argsToUse) :
						this.owner.getBean(lo.getBeanName()));
			}
			else {
				return (argsToUse != null ? this.owner.getBean(method.getReturnType(), argsToUse) :
						this.owner.getBean(method.getReturnType()));
			}
		}
	}

2. replaced-method注入

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context.xsd">

	<bean id="replaceDog" class="com.self.bean.initialization.method.overrides.replace.ReplaceDog"/>
	<bean id="originalDog" class="com.self.bean.initialization.method.overrides.replace.OriginalDog">
		<replaced-method name="sayHello" replacer="replaceDog">
			<arg-type match="java.lang.String"></arg-type>
		</replaced-method>
	</bean>
</beans>
public class OriginalDog {
	public void sayHello() {
		System.out.println("Hello,I am a black dog...");
	}

	public void sayHello(String name) {
		System.out.println("Hello,I am a black dog, my name is " + name);
	}
}
public class ReplaceDog implements MethodReplacer {
	@Override
	public Object reimplement(Object obj, Method method, Object[] args) throws Throwable {
		System.out.println("Hello, I am a white dog...");

		Arrays.stream(args).forEach(str -> System.out.println("params:" + str));
		return obj;
	}
}
public class ReplaceTest {
	public static void main(String[] args) {
		ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("method.overrides.replace.xml");
		OriginalDog originalDog = (OriginalDog) classPathXmlApplicationContext.getBean("originalDog");
		originalDog.sayHello("dddddddddddd");
	}
}

源码分析
注入方式同lookup-method
通过代理获取获取配置的实例

       @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);
		}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值