zoukankan      html  css  js  c++  java
  • 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 非常详细!

  • 相关阅读:
    java中的堆、栈、常量池
    java中int和Integer的区别
    python linecache模块读取文件的方法
    Python 字符串中 startswith()方法
    Python中的filter()函数的用法
    python sort、sorted高级排序技巧
    二级指针内存模型(一)
    Linux下多线程模拟停车场停车
    linux线程操作
    C语言实现多线程排序
  • 原文地址:https://www.cnblogs.com/FlyAway2013/p/7820585.html
Copyright © 2011-2022 走看看