## TargetSource - [TargetSource](#TargetSource) - [一、基本信息](#一基本信息) - [二、知识储备](#二知识储备) - [三、基本描述](#三基本描述) - [四、主要功能](#四主要功能) - [五、接口源码](#五接口源码) - [六、主要实现](#六主要实现) - [七、最佳实践](#七最佳实践) - [八、与其他组件的关系](#八与其他组件的关系) - [九、常见问题](#九常见问题) ### 一、基本信息 ✒️ **作者** - Lex 📝 **博客** - [掘金](https://juejin.cn/user/4251135018533068/posts) 📚 **源码地址** - [github](https://github.com/xuchengsheng/spring-reading) ### 二、基本描述 `TargetSource` 接口是 Spring AOP 框架中的一个关键组件,用于定义获取目标对象的策略,允许我们灵活地管理目标对象的创建和管理。通过实现该接口,可以实现各种目标对象的获取方式,如单例、原型、池化等,从而为 AOP 切面提供了更高度的可定制性和灵活性。 ### 三、主要功能 1. **目标对象获取方法** + `getTarget()`,该方法根据具体的策略获取目标对象,如单例、原型、池化等。 2. **目标对象释放方法** + `releaseTarget(Object target)`,一些实现可能需要释放目标对象,如将对象返回到对象池中。 3. **灵活的目标对象管理** + 可以根据应用程序的需求实现自定义的目标对象获取策略,从而实现对目标对象的灵活管理。 4. **内置的目标源实现** + Spring AOP 提供了几种内置的 `TargetSource` 实现,如 `SingletonTargetSource`、`PrototypeTargetSource`、`ThreadLocalTargetSource` 等,可以根据具体情况选择合适的目标源实现。 5. **扩展性和定制性** + 我们可以通过实现 `TargetSource` 接口来实现自定义的目标源,从而满足特定场景下的需求,如基于线程的对象管理、对象池管理等。 ### 四、接口源码 `TargetSource` 接口用于获取当前 AOP 调用的目标对象,通过 `getTarget()` 方法获取目标对象,并通过 `releaseTarget(Object target)` 方法释放目标对象。接口定义了 `getTargetClass()` 方法用于返回目标对象的类型,`isStatic()` 方法用于检查是否所有调用 `getTarget()` 方法的返回值都是相同的对象。此接口支持静态和动态目标源,静态目标源始终返回相同的目标对象,而动态目标源支持池化、热交换等功能。 ```java /** * TargetSource 接口用于获取 AOP 调用的当前目标对象,如果没有环绕通知选择结束拦截器链,则将通过反射调用目标对象。 * *
如果 TargetSource 是 "static",它将始终返回相同的目标对象,从而允许 AOP 框架进行优化。动态目标源可以支持池化、热交换等。 * *
应用程序开发人员通常不需要直接使用 TargetSources:这是一个 AOP 框架接口。 * * @author Rod Johnson * @author Juergen Hoeller */ public interface TargetSource extends TargetClassAware { /** * 返回此 TargetSource 返回的目标类型。 *
可以返回 {@code null},尽管某些 TargetSource 的用法可能只使用预定的目标类。 * * @return 此 TargetSource 返回的目标类型 */ @Override @Nullable Class> getTargetClass(); /** * 所有对 getTarget() 的调用是否将返回相同的对象? *
在这种情况下,不需要调用 releaseTarget(Object),并且 AOP 框架可以缓存 getTarget() 的返回值。
*
* @return 如果目标是不可变的,则为 true
* @see #getTarget
*/
boolean isStatic();
/**
* 返回一个目标实例。在 AOP 框架调用 AOP 方法调用的目标之前立即调用此方法。
*
* @return 包含连接点的目标对象,如果没有实际目标实例,则为 {@code null}
* @throws Exception 如果无法解析目标对象
*/
@Nullable
Object getTarget() throws Exception;
/**
* 释放从 getTarget() 方法获取的给定目标对象(如果有)。
*
* @param target 从调用 getTarget() 获取的对象
* @throws Exception 如果无法释放对象
*/
void releaseTarget(Object target) throws Exception;
}
```
### 五、主要实现
1. **SingletonTargetSource**
+ 用于管理单例对象的目标源。该实现每次调用 `getTarget()` 方法都返回同一个单例对象,适用于目标对象是单例的情况。
2. **PrototypeTargetSource**
+ 用于每次调用时创建新对象的目标源。该实现每次调用 `getTarget()` 方法都返回一个新的目标对象实例,适用于目标对象需要频繁更新或重置的情况。
3. **ThreadLocalTargetSource**
+ 用于在每个线程中保持一个目标对象的引用。该实现在每个线程中都维护一个目标对象的副本,适用于需要在多线程环境中使用不同的目标对象实例的情况。
4. **CommonsPool2TargetSource**
+ 用于使用 Apache Commons Pool 来管理目标对象的池化目标源。该实现通过对象池管理目标对象的创建和销毁,以提高对象的重用性和性能。
### 六、最佳实践
使用 Spring 的代理工厂(`ProxyFactory`)和目标源(`TargetSource`)来创建代理对象。在这个示例中,我们创建了一个连接池目标源(`ConnectionPoolTargetSource`),设置连接池的大小为 3。然后,我们将这个连接池目标源设置为代理工厂的目标源,并通过代理工厂获取代理对象。最后,我们通过代理对象调用了10次方法。
```java
public class TargetSourceDemo {
public static void main(String[] args) {
// 创建代理工厂
ProxyFactory proxyFactory = new ProxyFactory();
// 设置目标源为连接池目标源,连接池大小为3
proxyFactory.setTargetSource(new ConnectionPoolTargetSource(3));
// 获取代理对象
MyConnection proxy = (MyConnection) proxyFactory.getProxy();
// 调用10次方法
for (int i = 0; i < 10; i++) {
System.out.println("MyConnection Name = " + proxy.getName());
}
}
}
```
`ConnectionPoolTargetSource` 类实现了 Spring 的 `TargetSource` 接口,用于管理自定义连接对象的连接池。在构造函数中,它会初始化一个固定大小的阻塞队列作为连接池,并填充连接对象。通过实现 `getTarget()` 方法,它能够从连接池中获取连接对象,并在 `releaseTarget()` 方法中释放连接对象。
```java
/**
* 连接池目标源,用于管理自定义连接对象的连接池。
*
* @author xcs
* @date 2024年4月9日15:26:28
*/
public class ConnectionPoolTargetSource implements TargetSource {
/**
* 连接池
*/
private final BlockingQueue