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