使用方式
lookup-method使用
public class User {
public void showMe() {
System.out.println("i am user");
}
}
public class Teacher extends User {
public void showMe(){
System.out.println("i am Teacher");
}
}
//调用方,可以是个抽象类
public abstract Class GetBeanTest {
public void show() {
this.getUser().showMe();
}
//注意,这是个方法
public abstract User getUser() ;
}
xml定义:
<bean id="getBeanTest" class="GetBeanTest">
<lookup-method name="getUser" bean="teacher"/>
</bean>
<bean id="teacher" class="Teacher"/>
spring 内部beanDefinition解析入口
在instantiate一个实例前,需要调用一个构造函数,决定调用构造函数是CglibSubclassingInstantiationStrategy的职能,其父类是SimpleInstantiationStrategy。
类:SimpleInstantiationStrategy.java
public Object instantiate(RootBeanDefinition beanDefinition, String beanName, BeanFactory owner) {
// Don't override the class with CGLIB if no overrides.
if (beanDefinition.getMethodOverrides().isEmpty()) {
Constructor<?> constructorToUse;
synchronized (beanDefinition.constructorArgumentLock) {
constructorToUse = (Constructor<?>) beanDefinition.resolvedConstructorOrFactoryMethod;
if (constructorToUse == null) {
final Class<?> clazz = beanDefinition.getBeanClass();
if (clazz.isInterface()) {
throw new BeanInstantiationException(clazz, "Specified class is an interface");
}
try {
if (System.getSecurityManager() != null) {
constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction<Constructor>() {
public Constructor<?> run() throws Exception {
return clazz.getDeclaredConstructor((Class[]) null);
}
});
}
else {
constructorToUse = clazz.getDeclaredConstructor((Class[]) null);
}
beanDefinition.resolvedConstructorOrFactoryMethod = constructorToUse;
}
catch (Exception ex) {
throw new BeanInstantiationException(clazz, "No default constructor found", ex);
}
}
}
return BeanUtils.instantiateClass(constructorToUse);
}
else {
// Must generate CGLIB subclass.
return instantiateWithMethodInjection(beanDefinition, beanName, owner);
}
}
beanDefinition.getMethodOverrides()在解析xml时候,会根据是否有lookup-method、replace-method生成对应的MethodOverride对象。
cglib生成类
最终的实例化是调用CglibSubclassingInstantiationStrategy.instantiateWithMethodInjection()方法,
public Object instantiate(Constructor<?> ctor, Object[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.beanDefinition.getBeanClass());
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setCallbackFilter(new CallbackFilterImpl());
enhancer.setCallbacks(new Callback[] {
NoOp.INSTANCE,
new LookupOverrideMethodInterceptor(),
new ReplaceOverrideMethodInterceptor()
});
return (ctor != null ? enhancer.create(ctor.getParameterTypes(), args) : enhancer.create());
}
最终bean的实现类是一个cglib enhancer生成的bean class指定类的子类。
其中,
private class LookupOverrideMethodInterceptor extends CglibIdentitySupport implements MethodInterceptor {
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) beanDefinition.getMethodOverrides().getOverride(method);
return owner.getBean(lo.getBeanName());
}
}
所以每次调用GetBeanTest.getUser()方法是,实际上是调用 BeanFactory.getBean(lo.getBeanName())的方法;
这样就可以解决GetBeanTest是sigleton bean,而 User是prototype bean。
replace-method的原理同样。