10年 Java程序员,硬核人生!勇往直前,永不退缩!

欢迎围观我的git:https://github.com/R1310328554/spring_security_learn 寻找志同道合的有志于研究技术的朋友,关注本人微信公众号: 觉醒的码农,或Q群 165874185

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

初始化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 非常详细!

 

posted on 2017-11-12 01:48  CanntBelieve  阅读(818)  评论(0编辑  收藏  举报