## TargetSourceCreator - [TargetSourceCreator](#TargetSourceCreator) - [一、基本信息](#一基本信息) - [二、基本描述](#二基本描述) - [三、主要功能](#三主要功能) - [四、接口源码](#四接口源码) - [五、主要实现](#五主要实现) - [六、最佳实践](#六最佳实践) - [七、源码分析](#七源码分析) - [八、常见问题](#八常见问题) ### 一、基本信息 ✒️ **作者** - Lex 📝 **博客** - [掘金](https://juejin.cn/user/4251135018533068/posts) 📚 **源码地址** - [github](https://github.com/xuchengsheng/spring-reading) ### 二、基本描述 `TargetSourceCreator`接口,主要用于创建目标对象的代理。通过实现该接口,你可以自定义代理对象的创建逻辑,例如根据不同的条件返回不同的代理对象。这在AOP(面向切面编程)和代理模式中非常有用,可以灵活地控制代理对象的生成过程。 ### 三、主要功能 1. **创建代理对象的目标源(TargetSource)** + 该接口允许我们定义创建代理对象的逻辑,包括决定何时创建代理对象以及如何创建代理对象的目标源。 2. **定制代理对象的创建过程** + 通过实现该接口,你可以根据需要定制代理对象的创建过程。这包括根据不同的条件返回不同的目标源,或者在创建代理对象之前或之后执行特定的逻辑。 3. **支持AOP的灵活配置** + 在Spring框架中,AOP(面向切面编程)经常使用代理对象来实现横切关注点。`TargetSourceCreator`接口允许我们灵活地控制代理对象的生成过程,从而为AOP提供了更高的定制性和灵活性。 ### 四、接口源码 `TargetSourceCreator`接口,它允许实现类创建特殊的目标源(TargetSource),例如池化目标源,用于特定的bean。实现类可以基于目标类的属性,如池化属性,来决定选择哪种类型的目标源。`AbstractAutoProxyCreator`可以支持多个`TargetSourceCreators`,它们将按顺序应用,为Spring框架中的代理对象创建提供了灵活性和定制性。 ```java /** * 实现类可以为特定的bean创建特殊的目标源,例如池化目标源。例如,它们可以根据目标类上的属性(例如池化属性)来选择目标源。 * *
AbstractAutoProxyCreator 可以支持多个 TargetSourceCreators,它们将按顺序应用。
*
* @author Rod Johnson
* @author Juergen Hoeller
*/
@FunctionalInterface
public interface TargetSourceCreator {
/**
* 为给定的bean创建一个特殊的目标源(如果有的话)。
* @param beanClass bean的类
* @param beanName bean的名称
* @return 特殊的目标源,如果此 TargetSourceCreator 不感兴趣于特定的bean,则返回 {@code null}
*/
@Nullable
TargetSource getTargetSource(Class> beanClass, String beanName);
}
```
### 五、主要实现
1. **QuickTargetSourceCreator**
+ 用于快速创建目标源。它适用于那些不需要延迟加载的情况,通过特定的条件或策略,可以快速地生成目标源,以提高性能或满足其他需求。
2. **LazyInitTargetSourceCreator**
+ 用于延迟创建目标源。它适用于需要延迟加载的场景,以减少启动时间或资源占用。根据特定的条件或策略,它会延迟地创建目标源,直到被请求时才进行加载。
### 六、最佳实践
使用Spring框架中的注解配置来创建应用程序上下文,并从上下文中获取`MyConnection` bean。然后,它打印了`MyConnection`实例的类名,并循环调用了`MyConnection`实例的`getName()`方法来获取实例的名称并打印输出。
```java
public class TargetSourceCreatorDemo {
public static void main(String[] args) {
// 创建一个基于注解的应用程序上下文
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
// 从上下文中获取 MyConnection bean
MyConnection myConnection = context.getBean(MyConnection.class);
// 打印 MyConnection 实例的类名
System.out.println("MyConnection Class = " + myConnection.getClass());
// 循环调用 MyConnection 实例的 getName() 方法
for (int i = 0; i < 10; i++) {
// 打印 MyConnection 实例的名称
System.out.println("MyConnection Name = " + myConnection.getName());
}
}
}
```
通过`@EnableAspectJAutoProxy`注解启用了AspectJ自动代理功能,允许Spring框架创建和管理切面(Aspects)。同时,通过`@Configuration`注解标识这是一个配置类,并使用`@ComponentScan("com.xcs.spring")`注解来指定需要扫描的包,以便Spring能够自动装配Bean和发现组件。
```java
@EnableAspectJAutoProxy
@Configuration
@ComponentScan("com.xcs.spring")
public class AppConfig {
}
```
`SetMyTargetSourceCreator`类实现了Spring框架的`BeanPostProcessor`接口和`PriorityOrdered`接口。在`postProcessAfterInitialization`方法中,通过判断bean是否为`AbstractAutoProxyCreator`的实例,然后为其设置了自定义的目标源创建器`MyTargetSourceCreator`。通过实现`PriorityOrdered`接口并重写`getOrder`方法,确保了该后置处理器具有最高的优先级,以确保在其他后置处理器之前执行。
```java
@Component
public class SetMyTargetSourceCreator implements BeanPostProcessor , PriorityOrdered {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof AbstractAutoProxyCreator) {
((AbstractAutoProxyCreator) bean).setCustomTargetSourceCreators(new MyTargetSourceCreator());
}
return bean;
}
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
}
```
`MyTargetSourceCreator`类实现了`TargetSourceCreator`接口。在`getTargetSource`方法中,它根据传入的bean类和bean名称来判断是否需要为特定的bean创建目标源。如果传入的bean类是`MyConnection`类或其子类,它将返回一个具有连接池功能的目标源`ConnectionPoolTargetSource`,并设置连接池的大小为3。
```java
public class MyTargetSourceCreator implements TargetSourceCreator {
@Override
public TargetSource getTargetSource(Class> beanClass, String beanName) {
if (MyConnection.class.isAssignableFrom(beanClass)) {
return new ConnectionPoolTargetSource(3);
}
return null;
}
}
```
`ConnectionPoolTargetSource` 类实现了 Spring 的 `TargetSource` 接口,用于管理自定义连接对象的连接池。在构造函数中,它会初始化一个固定大小的阻塞队列作为连接池,并填充连接对象。通过实现 `getTarget()` 方法,它能够从连接池中获取连接对象,并在 `releaseTarget()` 方法中释放连接对象。
```java
/**
* 连接池目标源,用于管理自定义连接对象的连接池。
*
* @author xcs
* @date 2024年4月9日15:26:28
*/
public class ConnectionPoolTargetSource implements TargetSource {
/**
* 连接池
*/
private final BlockingQueue 此实现使用"customTargetSourceCreators"属性。
* 子类可以重写此方法以使用不同的机制。
* @param beanClass bean的类
* @param beanName bean的名称
* @return 用于此bean的目标源
* @see #setCustomTargetSourceCreators
*/
@Nullable
protected TargetSource getCustomTargetSource(Class> beanClass, String beanName) {
// 对于直接注册的单例bean,我们无法创建复杂的目标源。
if (this.customTargetSourceCreators != null &&
this.beanFactory != null && this.beanFactory.containsBean(beanName)) {
// 遍历所有的TargetSourceCreators
for (TargetSourceCreator tsc : this.customTargetSourceCreators) {
// 通过TargetSourceCreator获取目标源
TargetSource ts = tsc.getTargetSource(beanClass, beanName);
// 如果找到匹配的目标源,则返回
if (ts != null) {
// 找到了匹配的目标源。
if (logger.isTraceEnabled()) {
logger.trace("TargetSourceCreator [" + tsc +
"] found custom TargetSource for bean with name '" + beanName + "'");
}
return ts;
}
}
}
// 没有找到自定义的目标源。
return null;
}
```
### 八、常见问题
1. **如何在Spring应用程序中配置和使用TargetSourceCreator?**
- 配置`TargetSourceCreator`,创建一个实现`BeanPostProcessor`和`PriorityOrdered`接口的自定义类`SetMyTargetSourceCreator`,在其`postProcessAfterInitialization`方法中设置自定义的目标源创建器。