spring 之 lookup-method & replace-method

初始化bean的堆栈:

      at org.springframework.beans.factory.support.CglibSubclassingInstantiationStrategy$CglibSubclassCreator.instantiate(CglibSubclassingInstantiationStrategy.java:115)
      at org.springframework.beans.factory.support.CglibSubclassingInstantiationStrategy.instantiateWithMethodInjection(CglibSubclassingInstantiationStrategy.java:83)
      at org.springframework.beans.factory.support.CglibSubclassingInstantiationStrategy.instantiateWithMethodInjection(CglibSubclassingInstantiationStrategy.java:75)
      at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:93)
      at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1108)
      at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1060)
      at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:513)
      at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
      at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
      at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
      - locked <0x667> (a java.util.concurrent.ConcurrentHashMap)
      at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
      at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
      at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:759)
      at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:866)
      at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:542)
      - locked <0x668> (a java.lang.Object)
      at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
      at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:93)
      at AnnoIoCTest.main(AnnoIoCTest.java:7)

 

spring 初始化bean 的时候会使用一个 initializationStrategy, 默认就是 SimpleInstantiationStrategy, 关键就在于 它的 instantiate方法:

    public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) {
        if(bd.getMethodOverrides().isEmpty()) {
            Object var5 = bd.constructorArgumentLock;
            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 = (Constructor)AccessController.doPrivileged(new PrivilegedExceptionAction() {
                                public Constructor<?> run() throws Exception {
                                    return clazz.getDeclaredConstructor((Class[])null);
                                }
                            });
                        } else {
                            constructorToUse = clazz.getDeclaredConstructor((Class[])null);
                        }

                        bd.resolvedConstructorOrFactoryMethod = constructorToUse;
                    } catch (Throwable var9) {
                        throw new BeanInstantiationException(clazz, "No default constructor found", var9);
                    }
                }
            }

            return BeanUtils.instantiateClass(constructorToUse, new Object[0]);
        } else {
            return this.instantiateWithMethodInjection(bd, beanName, owner); 如果存在bean 覆盖,那么就 将那个方法注入过来吧!
        }
    }

这里instantiateWithMethodInjection 具体是由 CglibSubclassingInstantiationStrategy。 它是一个很重要的类。 顾名思义,它主要使用了 cglib 技术。 其中的 instantiate , 正是创建了 一个cglib 代理类, 

        public Object instantiate(Constructor<?> ctor, Object... args) {
            Class subclass = this.createEnhancedSubclass(this.beanDefinition); // 正是这里, 创建了一个 cglib 子类
            Object instance;
            if(ctor == null) {
                instance = BeanUtils.instantiateClass(subclass);// 实例化它
            } else {
                try {
                    Constructor factory = subclass.getConstructor(ctor.getParameterTypes());
                    instance = factory.newInstance(args);
                } catch (Exception var6) {
                    throw new BeanInstantiationException(this.beanDefinition.getBeanClass(), "Failed to invoke constructor for CGLIB enhanced subclass [" + subclass.getName() + "]", var6);
                }
            }

            Factory factory1 = (Factory)instance;
            factory1.setCallbacks(new Callback[]{NoOp.INSTANCE, new CglibSubclassingInstantiationStrategy.LookupOverrideMethodInterceptor(this.beanDefinition, this.owner), new CglibSubclassingInstantiationStrategy.ReplaceOverrideMethodInterceptor(this.beanDefinition, this.owner)});
            return instance;// setCallBack 是给它设置一些拦截器, 以便做些实际的操作。 因为默认的cglib代理类并不会做任何事情。
        }

 

不出所料,  LookupOverrideMethodInterceptor 处理 lookup-method, 而ReplaceOverrideMethodInterceptor 处理replace-method 。

public Object intercept(Object obj, Method method, Object[] args, MethodProxy mp) throws Throwable {
            LookupOverride lo = (LookupOverride)this.getBeanDefinition().getMethodOverrides().getOverride(method);
            Object[] argsToUse = args.length > 0?args:null;
            return StringUtils.hasText(lo.getBeanName())?this.owner.getBean(lo.getBeanName(), argsToUse):this.owner.getBean(method.getReturnType(), argsToUse);
        }

上面的intercept 方法返回的其实,正是  lookup-method 的bean 属性对应的对象。 而 原bean 的实例, 其实已经变成了 cglib 实现的 原class 的子类了。

 

获取lookup 方法的堆栈:

at org.springframework.beans.factory.support.CglibSubclassingInstantiationStrategy$LookupOverrideMethodInterceptor.intercept(CglibSubclassingInstantiationStrategy.java:283)
at com.baobaotao.Player$$EnhancerBySpringCGLIB$$1caa0626.getDelegete(<generated>:-1)
at com.baobaotao.Player.sayName(Player.java:15)
at AnnoIoCTest.main(AnnoIoCTest.java:15)

 

replace-method 和   lookup-method 的工作原理是类似的。 

    <bean id="player" class="com.baobaotao.Player">
        <replaced-method name="getDelegete" replacer="playerLk">
            <arg-type match="look">
            </arg-type>
        </replaced-method>
    </bean>

    <bean id="playerLk" class="com.baobaotao.LkMethodReplacer">
        <constructor-arg value="vvv"></constructor-arg>
    </bean>

replacer 需要实现 MethodReplacer:

public class LkMethodReplacer implements MethodReplacer {
    public String str;

    public LkMethodReplacer(String str) {
        this.str = str;
    }

    public PlayerLk reimplement(Object o, Method method, Object[] objects) throws Throwable {
        System.out.println("LkMethodReplacer.reimplement");
        return new PlayerLk(str);
    }
}

 

那么  lookup-method & replace-method  用于哪些地方呢?

用于:

单例类调用原型类,默认情况被调用的原形类仍是单例模式(即单例模式覆盖了原型模式),而通过lookup-method属性给单例类注入原型模式类的不同的实例。

他们之间有 什么区别呢?

其实很多时候 使用Autowired 即可, 但是, 使用场景还是有所不同的。  Autowired用于  给一个单例对象注入另一个单例对象。 但是如果想注入另外一个 原型对象。 那么久行不通了! 这个时候就使用  lookup-method 吧!! 

 

参考:

http://blog.csdn.net/huyangyamin/article/details/52126227

http://blog.csdn.net/u012881904/article/details/51116383 非常详细!

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
当然,除了使用注解方式,我们还可以使用XML配置来实现Spring Lookup Method。下面是一个使用XML配置的示例: 首先,定义一个抽象类: ``` public abstract class AbstractBean { public void doSomething() { getDependency().execute(); } public abstract Dependency getDependency(); } ``` 接下来,定义一个具体的子类: ``` public class ConcreteBean extends AbstractBean { private Dependency dependency; @Override public Dependency getDependency() { if (dependency == null) { dependency = createDependency(); } return dependency; } protected Dependency createDependency() { // 返回一个新的Dependency对象 } } ``` 注意到这里的`createDependency()`方法没有被`@Lookup`注解标记,这是因为我们将会在XML中配置这个方法。 接下来,我们需要在XML中配置这个类: ``` <bean id="concreteBean" class="com.example.ConcreteBean"> <lookup-method name="createDependency" bean="dependency"/> </bean> <bean id="dependency" class="com.example.Dependency"/> ``` 注意到这里的`lookup-method`元素,它告诉Spring在运行时为`createDependency()`方法生成一个代理,并将其返回值注入到`ConcreteBean`对象中。 现在,我们可以在其他类中注入`concreteBean`对象,并调用它的`doSomething()`方法,它将会使用`ConcreteBean`中的`createDependency()`方法来获取一个新的`Dependency`对象,并执行它的`execute()`方法。 这就是使用XML配置的Spring Lookup Method的一个简单示例。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值