spring 之 lookup-method & replace-method
初始化bean的堆栈:
at org.springframework.beans.factory.support.CglibSubclassingInstantiationStrategy$CglibSubclassCreator.instantiate(CglibSubclassingInstantiationStrategy.java:)
at org.springframework.beans.factory.support.CglibSubclassingInstantiationStrategy.instantiateWithMethodInjection(CglibSubclassingInstantiationStrategy.java:)
at org.springframework.beans.factory.support.CglibSubclassingInstantiationStrategy.instantiateWithMethodInjection(CglibSubclassingInstantiationStrategy.java:)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:)
at org.springframework.beans.factory.support.AbstractBeanFactory$.getObject(AbstractBeanFactory.java:)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:)
- locked <0x667> (a java.util.concurrent.ConcurrentHashMap)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:)
- locked <0x668> (a java.lang.Object)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:)
at AnnoIoCTest.main(AnnoIoCTest.java:)
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[]);
} 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 > ?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 非常详细!
spring 之 lookup-method & replace-method的更多相关文章
- .replace(R.id.container, new User()).commit();/The method replace(int, Fragment) in the type FragmentTransaction is not app
提示错误:The method replace(int, Fragment) in the type FragmentTransaction is not applicable for the arg ...
- 错误:The method replace(int, Fragment) in the type FragmentTransaction is not applicable for the arguments (int, MyFragment)
Fragment newfragment =new MyFragment();fragmentTransaction.replace(R.layout.activity_main,newfragmen ...
- Spring 通过工厂方法(Factory Method)来配置bean
Spring 通过工厂方法(Factory Method)来配置bean 在Spring的世界中, 我们通常会利用bean config file 或者 annotation注解方式来配置bean. ...
- 『重构--改善既有代码的设计』读书笔记----Replace Method with Method Object
有时候,当你遇到一个大型函数,里面的临时变量和参数多的让你觉得根本无法进行Extract Method.重构中也大力的推荐短小函数的好处,它所带来的解释性,复用性让你收益无穷.但如果你遇到上种情况,你 ...
- The method replace(int, Fragment, String) in the type FragmentTransaction is not applicable for the arguments (int, SettingFragment, String)
The method replace(int, Fragment, String) in the type FragmentTransaction is not applicable for the ...
- 重构 改善既有代码的设计 Replace Method with Method Object(以函数对象取代函数)
你有一个大型函数,其中对局部变量的使用使你无法采用Extract Method. 将这个函数放进一个单独对象中,如此一来局部变量就成了对象内的字段.然后你可以在同一个对象中将这个大型函数分解为多个小型 ...
- 关于.ToList(): LINQ to Entities does not recognize the method ‘xxx’ method, and this method cannot be translated into a store expression.
LINQ to Entities works by translating LINQ queries to SQL queries, then executing the resulting quer ...
- org.springframework.expression.spel.SpelEvaluationException: EL1004E: Method call: Method service() cannot be found on com.my.blog.springboot.thymeleaf.util.MethodTest type
前言 本文中提到的解决方案,源码地址在:springboot-thymeleaf,希望可以帮你解决问题. 至于为什么已经写了一篇文章thymeleaf模板引擎调用java类中的方法,又多此一举的单独整 ...
- Python OOP(2)-static method,class method and instance method
静态方法(Static Method): 一种简单函数,符合以下要求: 1.嵌套在类中. 2.没有self参数. 特点: 1.类调用.实例调用,静态方法都不会接受自动的self参数. 2.会记录所有实 ...
- 1.spring.net Look-up Method 查找方法的注入(方法是抽象的需要spring.net注入)
.为什么需要查找方法的注入 当Object依赖另一个生命周期不同的Object,尤其是当singleton依赖一个non-singleton时,常会遇到不少问题,Lookup Method Injec ...
随机推荐
- 解决“chrome adobe flash player不是最新版本”的方法
chrome地址栏输入chrome://components 更新flash后,重启chrome即可,可能需要搭梯子才能更新.
- GoJS拖动设计
http://192.168.0.149:8035/gojs/intro/groups.html http://192.168.0.149:8035/gojs/intro/ports.html htt ...
- 【mysql】mysql表分区、索引的性能测试
概述 mysql分区表概述:google搜索一下: RANGE COLUMNS partitioning 主要测试mysql分区表的性能: load 500w 条记录:大约在10min左右: batc ...
- C++标准模板库(STL)介绍:string的基本用法
1.带空格的字符串的输入 getline(cin, str)
- bzoj5019: [Snoi2017]遗失的答案
Description 小皮球在计算出答案之后,买了一堆皮肤,他心里很开心,但是一不小心,就忘记自己买了哪些皮肤了.==|||万 幸的是,他还记得他把所有皮肤按照1-N来编号,他买来的那些皮肤的编号( ...
- SQL Server的分页优化及Row_Number()分页存在的问题
最近有项目反应,在服务器CPU使用较高的时候,我们的事件查询页面非常的慢,查询几条记录竟然要4分钟甚至更长,而且在翻第二页的时候也是要这么多的时间,这肯定是不能接受的,也是让现场用SQLServerP ...
- MyBatis 手动映射结果集
MyBatis可以自动将查询结果封装到bean中,前提条件是bean的属性名和查询的结果列名相同,就会一次对应存储. 如果查询结果的列名和bean的属性名不一致,则需要手动映射结果集 <!-- ...
- webview自总结
2,webview ---- 运行时不调用系统自带浏览器: 1,安卓webview post传值问题: 11,WebView基本功能(html5.文件下载和远程URL) 10,webview--网络超 ...
- [UE4]UI动画复用
一.创建一个专门播放动画的Widget,添加一个“Name Slot”,创建动画绑定到这个“Name Slot”. 二.要使用这个动画的widget就添加第一步创建的widget,并把需要执行动画的对 ...
- 工作T-SQL备忘
作为一个"浸淫" Oracle 数据库很久的人来说, 突然转入 T-SQL, 也就是 MSSQL , 工作中经常用的查询和 MSMS 使用备忘如下 : --1. 切换对应的库连接 ...