spring lookup-method和replace-method本质

来源:互联网 发布:视频直播源码 编辑:程序博客网 时间:2024/06/08 02:49

使用方式

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.javapublic 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的原理同样。

0 0