五Spring-AOP--2AOP重要组件类

五Spring-AOP--2AOP重要组件类

5.4 AOP重要组件类

image-20230310115013442

5.4.1 Advisor(切面)

把pointcut和advice连接起来(可由Spring去完成,我们都交给容器管理就行,当然,你也可以手动完成)Spring的Advisor是Pointcut和Advice的配置器,它是将Advice注入程序中Pointcut位置的代码。

public interface Advisor {
     Advice EMPTY_ADVICE = new Advice() {};
     Advice getAdvice();
}

作为AOP中最重要的数据结构,它是aop所有的基础数据的归宿,负责Advice和Pointcut的封装

其仅仅可以获取Advice对象。

image-20220429220539869

5.4.1.1 PointcutAdvisor

public interface PointcutAdvisor extends Advisor {

     /**
	 * Get the Pointcut that drives this advisor.
	 */
     Pointcut getPointcut();

}

继承advisor类,因此PointcutAdvisor类可以获取Advice和Pointcut。

Advisor的扩展组件,它封装Advisor具有的Pointcut能力;

PointcutAdvisor用来获取advice和pointcut。也是完成对两者的封装和访问的能力。

5.4.1.2 DefaultPointcutAdvisor

常用的PointcutAdvisor对象。

public class DefaultPointcutAdvisor extends AbstractGenericPointcutAdvisor implements Serializable {
     
}

5.4.1.3 springAOP切面实例化模型

Spring AOP支持AspectJ的singleton、perthis、pertarget、pertypewithin实例化模型(目前不支持percflow、percflowbelow) 参见枚举类PerClauseKind

  1. singleton:即切面只会有一个实例;
  2. perthis:每个切入点表达式匹配的连接点对应的AOP对象(代理对象)都会创建一个新切面实例
  3. pertarget:每个切入点表达式匹配的连接点对应的目标对象都会创建一个新的切面实例
  4. pertypewithin

默认是singleton实例化模型,Schema风格只支持singleton实例化模型,而@AspectJ风格支持这三种实例化模型

singleton:使用@Aspect()指定,即默认就是单例实例化模式,在此就不演示示例了

perthis:每个切入点表达式匹配的连接点对应的AOP代理对象都会创建一个新的切面实例,使用@Aspect("perthis(切入点表达式)")指定切入点表达式;

// 他将为每个被切入点表达式匹配上的代理对象,都创建一个新的切面实例(此处允许HelloService是接口)
@Aspect("perthis(this(com.fsx.HelloService))") 

pertarget:每个切入点表达式匹配的连接点对应的目标对象都会创建一个新的切面实例,使用@Aspect("pertarget(切入点表达式)")指定切入点表达式; 此处要求HelloService不能是接口

另外需要注意一点:若在Spring内要使用perthis和pertarget,请把切面的Scope定义为:prototype

5.4.1.4 AspectInstanceFactory切面工厂

专门为切面创建实例的工厂(因为切面也不一定是单例的,也支持各种多例形式。上面已有说明)

// 它实现了Order接口哦~~~~支持排序的
public interface AspectInstanceFactory extends Ordered {
	//Create an instance of this factory's aspect.
	Object getAspectInstance();
	//Expose the aspect class loader that this factory uses.
	@Nullable
	ClassLoader getAspectClassLoader();
}

它的实现类如下:

img

SimpleAspectInstanceFactory:根据切面的aspectClass,调用空构造函数反射.newInstance()创建一个实例(备注:构造函数private的也没有关系) SingletonAspectInstanceFactory:这个就更简单了,因为已经持有aspectInstance得引用了,直接return即可

MetadataAwareAspectInstanceFactory

AspectInstanceFactory的子接口。提供了获取AspectMetadata的方法

public interface MetadataAwareAspectInstanceFactory extends AspectInstanceFactory {
	AspectMetadata getAspectMetadata();
	// Spring4.3提供  和beanFactory.getSingletonMutex()  否则一般都是this
	Object getAspectCreationMutex();
}

SimpleMetadataAwareAspectInstanceFactorySingletonMetadataAwareAspectInstanceFactory已经直接关联到AspectMetadata,所以直接return即可。 LazySingletonAspectInstanceFactoryDecorator也只是个简单的装饰而已。

BeanFactoryAspectInstanceFactory

这个就和Bean工厂有关了。比较重要

public class BeanFactoryAspectInstanceFactory implements MetadataAwareAspectInstanceFactory, Serializable {
	
	// 持有对Bean工厂的引用
	private final BeanFactory beanFactory;
	// 需要处理的名称
	private final String name;
	private final AspectMetadata aspectMetadata;

	// 传了Name,type可以不传,内部判断出来
	public BeanFactoryAspectInstanceFactory(BeanFactory beanFactory, String name) {
		this(beanFactory, name, null);
	}
	public BeanFactoryAspectInstanceFactory(BeanFactory beanFactory, String name, @Nullable Class<?> type) {
		this.beanFactory = beanFactory;
		this.name = name;
		Class<?> resolvedType = type;
		// 若没传type,就去Bean工厂里看看它的Type是啥  type不能为null~~~~
		if (type == null) {
			resolvedType = beanFactory.getType(name);
			Assert.notNull(resolvedType, "Unresolvable bean type - explicitly specify the aspect class");
		}
		// 包装成切面元数据类
		this.aspectMetadata = new AspectMetadata(resolvedType, name);
	}

	// 此处:切面实例 是从Bean工厂里获取的  需要注意
	// 若是多例的,请注意Scope的值
	@Override
	public Object getAspectInstance() {
		return this.beanFactory.getBean(this.name);
	}

	@Override
	@Nullable
	public ClassLoader getAspectClassLoader() {
		return (this.beanFactory instanceof ConfigurableBeanFactory ?
				((ConfigurableBeanFactory) this.beanFactory).getBeanClassLoader() :
				ClassUtils.getDefaultClassLoader());
	}

	@Override
	public AspectMetadata getAspectMetadata() {
		return this.aspectMetadata;
	}

	@Override
	@Nullable
	public Object getAspectCreationMutex() {
		if (this.beanFactory.isSingleton(this.name)) {
			// Rely on singleton semantics provided by the factory -> no local lock.
			return null;
		}
		else if (this.beanFactory instanceof ConfigurableBeanFactory) {
			// No singleton guarantees from the factory -> let's lock locally but
			// reuse the factory's singleton lock, just in case a lazy dependency
			// of our advice bean happens to trigger the singleton lock implicitly...
			return ((ConfigurableBeanFactory) this.beanFactory).getSingletonMutex();
		}
		else {
			return this;
		}
	}

	@Override
	public int getOrder() {
		Class<?> type = this.beanFactory.getType(this.name);
		if (type != null) {
			if (Ordered.class.isAssignableFrom(type) && this.beanFactory.isSingleton(this.name)) {
				return ((Ordered) this.beanFactory.getBean(this.name)).getOrder();
			}
			// 若没实现接口,就拿注解的值
			return OrderUtils.getOrder(type, Ordered.LOWEST_PRECEDENCE);
		}
		return Ordered.LOWEST_PRECEDENCE;
	}
}

PrototypeAspectInstanceFactory:多例专用的工厂 若是多例的,推荐使用

public class PrototypeAspectInstanceFactory extends BeanFactoryAspectInstanceFactory implements Serializable {
	public PrototypeAspectInstanceFactory(BeanFactory beanFactory, String name) {
		super(beanFactory, name);
		// 若是单例,直接报错了
		if (!beanFactory.isPrototype(name)) {
			throw new IllegalArgumentException(
					"Cannot use PrototypeAspectInstanceFactory with bean named '" + name + "': not a prototype");
		}
	}
}

5.4.2 Advice(增强方法)

Advice:通知,定义在连接点做什么,比如我们在方法前后进行日志打印(前置通知、后置通知、环绕通知等等)

public interface Advice {

}

Advice的标签接口,实现类可以是任何advice,例如拦截器Interceptors。

image-20210811162929543

image-20230310115059427

负责Advisor切面的具体增强业务,它包含AspectJAroundAdvice、AspectJAfterAdvice、AspectJAfterThrowingAdvice、AspectJMethodBeforeAdvice、AspectJAfterReturningAdvice等具体的增强部件。它们分别一一对应不同增强类型Around、After、AfterThrowing、Before、AfterReturning 等;

image-20230310115112547

5.4.2.1 MethodInterceptor(AOP)

(不同于cglib的MI)

interceptor继承自advice。(advice和pointcut都是通过PointcutAdvisor来获取)

image-20220422013619813

MethodInterceptor,

image-20220505110955302

非methodInterceptor通过[AdvisorAdapter](#5.5.5.3 AdvisorAdapter)转换为methodInterceptor

@FunctionalInterface
public interface MethodInterceptor extends Interceptor {

Object invoke(MethodInvocation invocation) throws Throwable;

实现invoke方法,以在拦截对应的MethodInvocation内包装的method对象,并在调用前后执行额外的处理。在aop执行中,会执行jointpoint.proceed(methodInvocation是jointpoint的子类)的执行链。用户需要实现invoke来修改行为方法。

属于methodInterceptor的advice

public class AspectJAfterAdvice extends AbstractAspectJAdvice
		implements MethodInterceptor, AfterAdvice, Serializable {

	public AspectJAfterAdvice(
			Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {

		super(aspectJBeforeAdviceMethod, pointcut, aif);
	}


	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		try {
      //链式调用
			return mi.proceed();
		}
		finally {
      //链式调用的操作,这里after的增强操作(调用增强方法adviceMethod),位于链式调用之后执行
			invokeAdviceMethod(getJoinPointMatch(), null, null);
		}
	}

实现逻辑:

调用methodInterceptor实现的advice增强,invoke方法是链式调用的实现。根据after增强,先链式调用,然后调用增强方法invokeAdviceMethod。

5.4.2.2 非MethodInterceptor的Advice增强

由非methodInterceptor的advice转换而来的methodInterceptor

// 都转为AOP的MethodInterceptor 从而实现拦截统一的拦截工作
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {

  //MethodBeforeAdviceInterceptor持有非methodInterceptor的advice对象实例,在调用invoke的时候调用其方法
	private MethodBeforeAdvice advice;

	public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
		Assert.notNull(advice, "Advice must not be null");
		this.advice = advice;
	}

	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
    //调用AOP标准的MethodInteceptor.invoke时候,调用advice响应的方法
		this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
		// 最终调用,实现了链式调用的效果
		return mi.proceed();
	}

}

实现逻辑:

对于非methodInterceptor的Advice实现类,如MethodBeforeAdvice、AfterReturningAdvice,其转换为带invoke方法的MethodInterceptor类,其内持有advice实例对象,在拦截连接点并执行invoke时,调用advice的方法,实现AOP标准的MethodInteceptor实现的增强的调用。

5.4.2.3 自定义Advice增强

自定义interceptor开发示例如下:

 class TracingInterceptor implements MethodInterceptor {
 *   Object invoke(MethodInvocation i) throws Throwable {
 *     System.out.println("method "+i.getMethod()+" is called on "+
 *                        i.getThis()+" with args "+i.getArguments());
 *     Object ret=i.proceed();
 *     System.out.println("method "+i.getMethod()+" returns "+ret);
 *     return ret;
 *   }
 * }

通常需要在invoke中执行methodInvocation.proceed,来执行拦截器链chain。

该MethodInterceptor有三个重要实现,AspectJAroundAdvice、AspectJAfterAdvice、AspectJAfterThrowingAdvice。

MethodInterceptor:三种增强类型的基接口,它扩展的invoke方法让Advisor具有了基础的拦截处理能力。

5.4.2.4 InterceptorAndDynamicMethodMatcher

class InterceptorAndDynamicMethodMatcher {

  
	final MethodInterceptor interceptor;

	final MethodMatcher methodMatcher;

	public InterceptorAndDynamicMethodMatcher(MethodInterceptor interceptor, MethodMatcher methodMatcher) {
		this.interceptor = interceptor;
		this.methodMatcher = methodMatcher;
	}

}

这是一个具有动态匹配能力的MethodInterceptor。其内有MethodMatcher属性,用来判断当前MethodInterceptor拦截器,是否可以作用在target的目标方法上。如果匹配上,通过dm.interceptor.invoke(this)执行方法调用。

如ReflectiveMethodInvocation.proceed方法内:

/**………………………………………………InterceptorAndDynamicMethodMatcher的动态匹配逻辑……………………………………………………………… */
              //当前代理方法动态匹配成功时,执行interceptor.invoke,调用拦截器方法
			if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
				return dm.interceptor.invoke(this);
			}
      //如果当前拦截器,没有匹配上当前jointpoint内的method方法,执行proceed,进行chain链表中下一个调用
			else {
                    //递归调用
				return proceed();
			}

详见[5.4.4.2 ReflectiveMethodInvocation](# 5.4.4.2 ReflectiveMethodInvocation)

public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable {
     	
     	/**缓存了MethodInterceptor and InterceptorAndDynamicMethodMatcher对象的list
     	调用的时候,需要进行动态确认,其类型前者还是后者 */
	protected final List<?> interceptorsAndDynamicMethodMatchers;
     
     @Nullable
     //反射来调用joinpoint
	protected Object invokeJoinpoint() throws Throwable {
		return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
	}
     
     	/**该类实现proceed方法,来递归地执行chain链*/
     @Override
	@Nullable
	public Object proceed() throws Throwable {
		// We start with an index of -1 and increment early.
		if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
               //当执行到chain链中最后一个时,反射调用joinpoint点处的方法代码
			return invokeJoinpoint();
		}

          //从缓存中逐个获取chain中的对象
		Object interceptorOrInterceptionAdvice =
				this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
          
/**……………………………………处理获取的chain中对象是InterceptorAndDynamicMethodMatcher的情况……………………………………………………*/
		if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
			// Evaluate dynamic method matcher here: static part will already have
			// been evaluated and found to match.
			InterceptorAndDynamicMethodMatcher dm =
					(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
      //获取当前target的Class对象
			Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
      
/**………………………………………………InterceptorAndDynamicMethodMatcher的动态匹配逻辑……………………………………………………………… */
              //当前代理方法动态匹配成功时,执行interceptor.invoke,调用拦截器方法
			if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
				return dm.interceptor.invoke(this);
			}
      //如果当前拦截器,没有匹配上当前jointpoint内的method方法,执行proceed,进行chain链表中下一个调用
			else {
                    //递归调用
				return proceed();
			}
		}
    
 /** ……………………………………………………………………判断获取的chain中对象是MethodInterceptor………………………………………………………………*/
		else {
			// It's an interceptor, so we just invoke it: The pointcut will have
			// been evaluated statically before this object was constructed.
      //直接invoke调用
			return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
		}
	}

5.4.3 Pointcut(切点--拦截规则)

切点,决定advice应该作用于那个连接点joinpoint,比如根据正则等规则匹配哪些方法需要增强(Pointcut 目前有getClassFilter(类匹配),getMethodMatcher(方法匹配),Pointcut TRUE (全匹配))

public interface Pointcut {

     ClassFilter getClassFilter();
     MethodMatcher getMethodMatcher();
     /**
    * Canonical Pointcut instance that always matches.
    始终匹配的规范pointcut实例
    */
     Pointcut TRUE = TruePointcut.INSTANCE;
}

配置Advisor的拦截增强目标,Spring内部最终通过模糊匹配算法,最终定位到具体的拦截目标;

类过滤和方法过滤的用法,详见5.5.5.1 [AdvisorChainFactory](#5.5.5.1 AdvisorChainFactory)中构建拦截器链的方法:

首先通过pointcutAdvisor.getPointcut().getClassFilter.match(targetClass),判断当前对象targetClass是否需要切面增强,如果需要,通过AdvisorAdapterRegistry.getInterceptors(advisor),转换为interceptors对象;然后获取MethodMatcher,如果匹配到当前方法,且mm为动态匹配,那么将构建InterceptorAndDynamicMethodMatcher(interceptor, mm),加入list;如果为静态匹配,构建 interceptors直接加入list。

5.4.3.1 ClassFilter

public interface ClassFilter {

	//切入点pointcut是否应该应用于给定的接口或者目标类
	boolean matches(Class<?> clazz);
     //全匹配
	ClassFilter TRUE = TrueClassFilter.INSTANCE;

}

用来判断当前pointcut是否匹配到当前给定的接口或者目标类。

5.4.3.2 MathodMatcher

public interface MethodMatcher {

  //静态匹配,使用该方法
	boolean matches(Method method, Class<?> targetClass);

  //当前是否是runtime动态匹配的
	boolean isRuntime();

  //如果isRuntime为true,则最后会调用这个三个参数的方法,匹配
	boolean matches(Method method, Class<?> targetClass, Object... args);
     	/**
	 * Canonical instance that matches all methods.
	 匹配一切方法的MethodMatcher
	 */
	MethodMatcher TRUE = TrueMethodMatcher.INSTANCE;

判断当前pointcut是否匹配到目标类target上的具体方法method。

如果mm.isRuntime为true动态匹配,chain链传入的是InterceptorAndDynamicMethodMatcher对象,在ReflectiveMethodInvocation的proceed的调用环节,匹配方法用的是三个参数的matches。

5.4.4 Joinpoint(连接点--拦截点的方法)

连接点,就是spring允许你是通知(Advice)或者说需要增强的地方,就是需要执行advice增强的方法。基本每个方法的前、后(两者都有也行),或抛出异常是时都可以是连接点,spring只支持方法连接点。和方法有关的前前后后都是连接点(通知方法MethodInvocation里都可以获取到这个连接点,顺便获取到相关信息

image-20220422024644699

5.4.4.1 MethodInvocation

//该对象是被调用方法的描述,当被调用时,提供给拦截器interceptor
public interface MethodInvocation extends Invocation {
	//获取被调用的方法对象
	Method getMethod();
}
image-20220422025629881

methodInvocation继承的方法,如上。

//作为一个通用的运行时连接点。joinpoint是发生在程序位置上的一个事件。
public interface Joinpoint {

	//**proceed**:用来执行chain上的下一个interceptor对象。
	Object proceed() throws Throwable;

MethodInvocation是一个连接点jointpoint,并且可以被方法拦截器methodinterceptor拦截,并调用proceed方法,执行chain的拦截器链调用。

5.4.4.2 ReflectiveMethodInvocation

image-20220422053420920

反射方法调用类,用反射method.invoke来调用target对象的目标方法,以及拦截器链chain,完成AOP的增强。子类通过重写invokeJoinpoint方法,来改变行为。

public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable {
     	
     	/**缓存了MethodInterceptor and InterceptorAndDynamicMethodMatcher对象的list
     	调用的时候,需要进行动态确认,其类型前者还是后者 */
	protected final List<?> interceptorsAndDynamicMethodMatchers;
     
     @Nullable
     //反射来调用joinpoint
	protected Object invokeJoinpoint() throws Throwable {
		return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
	}
     
     	/**该类实现proceed方法,来递归地执行chain链*/
     @Override
	@Nullable
	public Object proceed() throws Throwable {
		// We start with an index of -1 and increment early.
		if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
               //当执行到chain链中最后一个时,反射调用joinpoint点处的方法代码
			return invokeJoinpoint();
		}

          //从缓存中逐个获取chain中的对象
		Object interceptorOrInterceptionAdvice =
				this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
          
/**……………………………………处理获取的chain中对象是InterceptorAndDynamicMethodMatcher的情况……………………………………………………*/
		if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
			// Evaluate dynamic method matcher here: static part will already have
			// been evaluated and found to match.
			InterceptorAndDynamicMethodMatcher dm =
					(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
      //获取当前target的Class对象
			Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
              //当前代理方法动态匹配成功时,执行interceptor.invoke,调用拦截器方法
			if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
				return dm.interceptor.invoke(this);
			}
      //如果当前拦截器,没有匹配上当前jointpoint内的method方法,执行proceed,进行chain链表中下一个调用
			else {
                    //递归调用--------------完成链式调用的关键
				return proceed();
			}
		}
    
 /** ……………………………………………………………………判断获取的chain中对象是MethodInterceptor………………………………………………………………*/
		else {
			// It's an interceptor, so we just invoke it: The pointcut will have
			// been evaluated statically before this object was constructed.
      //直接invoke调用
			return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
		}
	}

ReflectiveMethodInvocation的方法调用中,proceed执行拦截器链的逻辑如下:

1 通过执行proceed方法,执行拦截器链执行;

2 List<?> interceptorsAndDynamicMethodMatchers缓存当前joinpoint的拦截器链(joinpoint是一个待增强的method点),逐个获取chain中的属性;

3 判断对象是MethodInterceptor 还是 InterceptorAndDynamicMethodMatcher,执行不同的逻辑:

3.1 如果是InterceptorAndDynamicMethodMatcher,即动态匹配拦截器,要调用InterceptorAndDynamicMethodMatcher.methodMatcher.match方法判断当前拦截器是否需要拦截,

3.1.1 如果是,执行dm.interceptor.invoke(this);

3.1.2 如果不是,直接proceed(),递归调用,执行chain中下一个;

3.2 如果是MethodInterceptor,直接反射调用mi.invoke。

4 完成链式调用的关键,在3.1.2的proceed方法上。

5.4.5 TargetSource(目标类)

image-20220501232443120

image-20230310115208108

TargetSource(目标源)是被代理的target(目标对象)实例的来源。TargetSource被用于获取当前MethodInvocation(方法调用)所需要的target(目标对象),这个target通过反射的方式被调用(如:method.invoke(target,args))。换句话说,proxy(代理对象)代理的不是target,而是TargetSource,这点非常重要!!!

​ 那么问题来了:为什么SpringAOP代理不直接代理target,而需要通过代理TargetSource(target的来源,其内部持有target),间接代理target呢?

​ 通常情况下,一个proxy(代理对象)只能代理一个target,每次方法调用的目标也是唯一固定的target。但是,如果让proxy代理TargetSource,可以使得每次方法调用的target实例都不同(当然也可以相同,这取决于TargetSource实现)。这种机制使得方法调用变得灵活,可以扩展出很多高级功能,如:target pool(目标对象池)、hot swap(运行时目标对象热替换),等等。

TargetSource组件本身与SpringIoC容器无关,换句话说,target的生命周期不一定是受spring容器管理的,我们以往的XML中的AOP配置,只是对受容器管理的bean而言的,我们当然可以手动创建一个target,同时使用Spring的AOP框架(而不使用IoC容器)

public interface TargetSource extends TargetClassAware {

     @Override
     Class<?> getTargetClass();

     // 如果为true,则getTarget返回的对象是不可变
     //此种情况下,不需要再次调用getTarget,spring的aop框架会缓存该实例
     boolean isStatic();

     Object getTarget() throws Exception;

     void releaseTarget(Object target) throws Exception;
}

5.4.7.1 spring内置的TargetSource

该接口代表一个目标对象,在aop调用目标对象的时候,使用该接口返回真实的对象。 比如它有两个实现SingletonTargetSourcePrototypeTargetSource代表着每次调用返回同一个实例,和每次调用返回一个新的实例。

(1)SingletonTargetSource

    public class SingletonTargetSource implements TargetSource, Serializable {
    
    	/** Target cached and invoked using reflection. */
    	private final Object target;
    	//省略无关代码......
    	@Override
    	public Object getTarget() {
    		return this.target;
    	}
    	//省略无关代码......
    

从这个目标源取得的目标对象是单例的,成员变量target缓存了目标对象,每次getTarget()都是返回这个对象。

(2)PrototypeTargetSource

  public class PrototypeTargetSource extends AbstractPrototypeBasedTargetSource {
    
       /**
        */
       @Override
       public Object getTarget() throws BeansException {
          return newPrototypeInstance();
       }
    
       /**
        * Destroy the given independent instance.
        * @see #destroyPrototypeInstance
        */
       @Override
       public void releaseTarget(Object target) {
          destroyPrototypeInstance(target);
       }
      //省略无关代码......
    }

每次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() + "'");
          }
       		//获取beanFactory,然后getbean方法获取代理目标对象target实例
          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类型的原因。(调用BeanFactory.getBean(getTargetBeanName()),因此就需要该目标bean应该声明为prototype类型,然后调用beanFactory的创建prototype的方法来创建bean)。

(3)ThreadLocalTargetSource

public class ThreadLocalTargetSource extends AbstractPrototypeBasedTargetSource
     implements ThreadLocalTargetSourceStats, DisposableBean {

     /**
        * ThreadLocal holding the target associated with the current
        * thread. Unlike most ThreadLocals, which are static, this variable
        * is meant to be per thread per instance of the ThreadLocalTargetSource class.
        */
     private final ThreadLocal<Object> targetInThread =
          new NamedThreadLocal<>("Thread-local instance of bean '" + getTargetBeanName() + "'");

     /**
        * Set of managed targets, enabling us to keep track of the targets we've created.
       存储创建的target到set中,方便后续管理、跟踪所创建的target对象们
       */
     private final Set<Object> targetSet = new HashSet<>();

     //省略无关代码......
     /*** Implementation of abstract getTarget() method.
        getTarget逻辑:
        首先从threadlocal中获取线程持有的target对象;如果没有获取,newPrototypeInstance方法,创建一个prototype的bean对象,并绑定到ThreadLocal上,同时将新创建的bean设置入targetset内。*/
     @Override
     public Object getTarget() throws BeansException {
          ++this.invocationCount;
          Object target = this.targetInThread.get();
          if (target == null) {
               if (logger.isDebugEnabled()) {
                    logger.debug("No target for prototype '" + getTargetBeanName() + "' bound to thread: " +
                                 "creating one and binding it to thread '" + Thread.currentThread().getName() + "'");
               }
               // Associate target with ThreadLocal.
            //创建bean,并设置入targetInThread中
               target = newPrototypeInstance();
               this.targetInThread.set(target);
               synchronized (this.targetSet) {
                    this.targetSet.add(target);
               }
          }
          else {
               ++this.hitCount;
          }
          return target;
     }

     /**
        * Dispose of targets if necessary; clear ThreadLocal.
        * @see #destroyPrototypeInstance
        */
     @Override
     public void destroy() {
          logger.debug("Destroying ThreadLocalTargetSource bindings");
          synchronized (this.targetSet) {
               for (Object target : this.targetSet) {
                    destroyPrototypeInstance(target);
               }
               this.targetSet.clear();
          }
          // Clear ThreadLocal, just in case.
          this.targetInThread.remove();
     }
     //省略无关代码......

ThreadLocalTargetSource也就是和线程绑定的TargetSource,可以理解,其底层实现必然使用的是ThreadLocal。既然使用了ThreadLocal,也就是说我们需要注意两个问题:

  • 目标对象必须声明为prototype类型,因为每个线程都会持有一个不一样的对象;
  • 目标对象必须是无状态的,因为目标对象是和当前线程绑定的,而Spring是使用的线程池处理的请求,因而每个线程可能处理不同的请求,因而为了避免造成问题,目标对象必须是无状态的

5.4.7.2 自定义的TargetSource

public class DqqzjTargetSource implements TargetSource {
     private final AtomicInteger idx = new AtomicInteger();
     private final Object[] target;
     public DqqzjTargetSource(Object[]  target) {
          Assert.notNull(target, "Target object must not be null");
          this.target = target;
     }
     @Override
     public Class<?> getTargetClass() {
          return target.getClass();
     }

     @Override
     public boolean isStatic() {
          return false;
     }

     @Override
     public Object getTarget() throws Exception {
          return this.target[this.idx.getAndIncrement() & this.target.length - 1];
     }

     @Override
     public void releaseTarget(Object target) throws Exception {

     }
}

实现自定义TargetSource主要有两个点要注意,一个是getTarget()方法,该方法中需要实现获取目标对象的逻辑,另一个是isStatic()方法,这个方法告知Spring是否需要缓存目标对象,在非单例的情况下一般是返回false

posted @ 2023-03-10 17:15  LeasonXue  阅读(121)  评论(0编辑  收藏  举报