时间:2021-05-20
摘要:
其实我第一次看见这个东西的时候也是不解,代理目标源不就是一个class嘛还需要封装干嘛。。。
其实proxy代理的不是target,而是TargetSource,这点非常重要,一定要分清楚!!!
通常情况下,一个代理对象只能代理一个target,每次方法调用的目标也是唯一固定的target。但是,如果让proxy代理TargetSource,可以使得每次方法调用的target实例都不同(当然也可以相同,这取决于TargetSource实现)。这种机制使得方法调用变得灵活,可以扩展出很多高级功能,如:单利,原型,本地线程,目标对象池、运行时目标对象热替换目标源等等。
Spring内置的TargetSource
SingletonTargetSource
从这个目标源取得的目标对象是单例的,成员变量target缓存了目标对象,每次getTarget()都是返回这个对象。
PrototypeTargetSource
每次getTarget()将生成prototype类型的bean,即其生成的bean并不是单例的,因而使用这个类型的TargetSource时需要注意,封装的目标bean必须是prototype类型的。
PrototypeTargetSource继承了AbstractBeanFactoryBasedTargetSource拥有了创建bean的能力。
public abstract class AbstractPrototypeBasedTargetSource extends AbstractBeanFactoryBasedTargetSource { //省略无关代码...... /** * Subclasses should call this method to create a new prototype instance. * @throws BeansException if bean creation failed */ protected Object newPrototypeInstance() throws BeansException { if (logger.isDebugEnabled()) { logger.debug("Creating new instance of bean '" + getTargetBeanName() + "'"); } return getBeanFactory().getBean(getTargetBeanName()); } /** * Subclasses should call this method to destroy an obsolete prototype instance. * @param target the bean instance to destroy */ protected void destroyPrototypeInstance(Object target) { if (logger.isDebugEnabled()) { logger.debug("Destroying instance of bean '" + getTargetBeanName() + "'"); } if (getBeanFactory() instanceof ConfigurableBeanFactory) { ((ConfigurableBeanFactory) getBeanFactory()).destroyBean(getTargetBeanName(), target); } else if (target instanceof DisposableBean) { try { ((DisposableBean) target).destroy(); } catch (Throwable ex) { logger.warn("Destroy method on bean with name '" + getTargetBeanName() + "' threw an exception", ex); } } } //省略无关代码...... }可以看到,PrototypeTargetSource的生成prototype类型bean的方式主要是委托给BeanFactory进行的,因为BeanFactory自有一套生成prototype类型的bean的逻辑,因而PrototypeTargetSource也就具有生成prototype类型bean的能力,这也就是我们要生成的目标bean必须声明为prototype类型的原因。
ThreadLocalTargetSource
ThreadLocalTargetSource也就是和线程绑定的TargetSource,可以理解,其底层实现必然使用的是ThreadLocal。既然使用了ThreadLocal,也就是说我们需要注意两个问题:
目标对象必须声明为prototype类型,因为每个线程都会持有一个不一样的对象;
目标对象必须是无状态的,因为目标对象是和当前线程绑定的,而Spring是使用的线程池处理的请求,因而每个线程可能处理不同的请求,因而为了避免造成问题,目标对象必须是无状态的。
实现自定义的TargetSource
实现自定义TargetSource主要有两个点要注意,一个是getTarget()方法,该方法中需要实现获取目标对象的逻辑,另一个是isStatic()方法,这个方法告知Spring是否需要缓存目标对象,在非单例的情况下一般是返回false。
小结
本文主要首先讲解了Spring是如果在源码层面支持TargetSource的,然后讲解了TargetSource的使用原理,接着对Spring提供的常见`TargetSource`进行了讲解,最后使用一个自定义的TargetSource讲解了其使用方式。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
一、源码分析自定义异常数据之前我们先看看一下源码上述代码意思是如果你没有提供就使用springboot提供的类这是springboot提供的异常属性类,我们想要
springBoot源码编译1.git上下拉最新版的springBoot下载:gitclonegit@github.com:spring-projects/sp
详解springboot-修改内置tomcat版本1、解析SpringBoot父级依赖org.springframework.bootspring-boot-s
SpringBoot整合Gson整合Fastjson一、SpringBoot整合Gson1、pom依赖#在SpringBoot中给我们自带了json解析器,我们
源码地址:https://github.com/laolunsi/spring-boot-examples目前SpringBoot常被用于开发JavaWeb应用