spring lookup-method和replace-method本质

使用方式

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

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值