概述
本文想要说明的是代理框架的如何实现,同时扩展了下谈谈自己对于设计的一些想法,其中代理框架部分主要是基于Spring的AOP源码。
首先我们需要明确实现一个代理框架需要有哪些核心哪些功能,以及哪些地方需要抽象出来。
本文在最后还分析了Spring TX的代码,TX的代码是AOP的另一个应用场景,我们可以通过这部分代码,来加深对AOP的理解。
Spring 中的代理框架(AOP)的实现原理
先说下使用代理模式的意义
代理模式的一种应用就是持有目标对象的引用,并在此之上可以增加增强内容。注意,这里说的代理模式和装饰模式有本质上的区别,这种区别体现在应用上,两者实现相似度很高但是实际使用场景区别很大需要区分开。
我认为一个代理框架应该具有如下的基本功能:
代理框架(AOP)的主要的功能就是:告诉我需要执行什么,以及在哪执行。然后我来帮你把对应的类进行代理,将需要增强的方法进行增强。
AOP框架做的事就是将上面的内容封装起来对用户透明。只要你告诉我对应的切面和需要代理的对象,然后代理框架负责将对应的代理对象生成,用户调用的代理对象的对应的方法。
现在来思考下,通常实现一个代理类应该有哪些步骤:
- 1、定义增强,增强定义了增强的内容,一些业务逻辑。是什么类型的切面,比如,前置增强还是,后置增强等等,增强通常情况下是用户定义的一个方法。
- 2、定义切点,切点定义了有没有资格增强和在哪里进行增强。
- 3、定义切面,作为增强和切点的组合体配置信息。
- 4、在此之上我们可以定义多个可以应用该位置的切面列表,切面A、切面B、切面C等等等。
- 5、最后通过动态代理Proxy的方式将增强引用到目标对象上。
通常我们通过以上几步来生成一个动态代理对象。
所以我们可以看到,上述流程如果想要封装成一个框架的话,首先需要一个配置类,另外就是需要一个生成代理的ProxyFactory工厂类。然后对外提供的API可以是集成了配置类和工厂类功能。工厂类用来生成代理,而配置类是用来保存切面信息。
Spring的设计就是抽象出了三个基本概念。
这里我们需要理解AOP的三个非常重要的概念:
- 1、增强(Advice):定义了具体的执行内容。解决的是执行什么?
- 2、切点(Pointcut):用于检索,判断是否支持分为类和方法层面。解决的是在哪执行?
- 3、切面(Advisor):同时持有切面和切点的配置信息
上面三个组件就组成了构建AOP的基本配置能力信息。我们构建的Proxy在InvocationHandler的invoke方法中调用的就是上面的三个组件。
大体的流程就是:
1、通过Pointcut中的类过滤和方法过滤判断是否可以应用这个切面。
2、根据切面来完成增强的调用。
我们需要注意的是这个切面(Advice)是不可以直接使用的因为它还没有设置好执行的循序,它需要经过加工成MethodInterceptor来实现具体的执行步骤。所以AOP框架中定义了一个AdvisorAdapterRegistry类来实现对固定的类型的从Advice到MethodInterceptor的转换。Proxy中会使用MethodInterceptor来编排执行过程。
实际上Proxy在运行的时候是通过MethodInterceptor来调用执行的,我们可以声明Advice,实现这个接口,可以自己随便定义方法,然后通过AdviceAdapter转换成MethodInterceptor即可。但是这个在框架内部已经写死了,没法扩展。所以,如果我们实现一个增强(Advice)直接实现MethodInterceptor即可。
关键字:
- 1、配置
- 2、检索规则,这个在AOP中是个非常重要的概念,很多的组件建立都是为了实现这个功能的。主要的目的是提供一个对于一个切点的对应的切面的检索能力。
- 3、调用编排,编排检索到符合条件的切面之后的执行顺序。
在AOP框架中,抽象出了一个Proxy的概念,这个Proxy的主要功能就是通过不同的动态代理的方式来生成代理对象。然后有抽象出了ProxyFactory,这个主要使用来生成Proxy,以及保存一些配置信息等。属于服务域,AOP的对外使用的门面类。
下面来看下具体的源码:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
// 忽略一些代码
...
Object retVal;
// 判断是否需要将代理暴露给线程上下文
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// 重要,主要的功能就是根据方法和对象类型来获取符合条件的执行链。
// Get the interception chain for this method.
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// Check whether we have any advice. If we don't, we can fallback on direct
// reflective invocation of the target, and avoid creating a MethodInvocation.
// 这里判断如果没有匹配到增强,那么直接使用反射调用方法即可
// 注意这里是在已经生成动态代理了,但是在调用的时候因为没有增强所以只是使用了反射。
if (chain.isEmpty()) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// 关键,这里是根据获取到的执行链,执行。
// We need to create a method invocation...
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
retVal = invocation.proceed();
}
// 处理返回值
// Massage return value if necessary.
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// Special case: it returned "this" and the return type of the method
// is type-compatible. Note that we can't help if the target sets
// a reference to itself in another returned object.
retVal = proxy;
}
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
// 这里判断下是否是执行链最后一个节点,如果是的话,那么此时执行proceed方法就是执行原始的我们需要增强方法
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
// 获取到下一个执行节点
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
else {
// 执行增强的内容
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed.
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
这里只是分析了JDK的动态代理方法,CGLIB实现一样的。代理框架的代码到此就结束了,很简单,但是需要我们理解代理框架都干了什么。
使用
现在我们来说一下该如何使用ProxyFactory。
1、我们需要定义一个Pointcut类,里面需要持有一个ClassFilter(过滤类:切面对于哪些类有效)和MethodMatcher(过滤方法,切面对于哪些方法有效)对象。
2、定义一个增强(Advice)这个Advice可以是MethodInterceptor
3、组合一个Advisor。
4、将组装后的Advisor传入到ProxyFactory的构造函数中。
5、将对象传入到ProxyFactory中。
这里用到了工厂,我就想对工厂模式这种设计模式多说一下。
扩展一下:Dubbo中的ProxyFactory和Spring的ProxyFactory实现有所不同,Spring中的ProxyFactory倾向于根据不同的条件来使用来生产对用的AopProxy。但是Dubbo中是有不同的ProxyFactory,但是这些ProxyFactory都是有一个共同的抽象类来实现共同的逻辑,为什么Dubbo中不采用Spring中的这种通过参数来区分的方式呢?这要考虑到Dubbo中的SPI方式,我们可以通过SPI的方式来动态的根据参数使用不同的ProxyFactory。
Spring中采用的是简单工厂模式,而Dubbo中使用的是工厂模式,两者的主要区别是工厂模式的应用范围要比简单工厂模式广,工厂模式倾向于由于具体的对象太多了,开始有业务逻辑分类比如A类使用哪个工厂,B类使用哪个工厂。而简单工厂模式只是简单意义上的区分,比如某个参数。
同时我们思考下,什么时候用工厂模式,其实不是所有需要创建对象的地方都需要用工厂模式,我考虑了一下,如果对象类似于产品一样的属性一直需要被生成,那就需要工厂模式。什么是产品属性的对象呢?比如:一个被代理的对象或者一个会话对象,这个对象需要生成很多。那么什么不是产品一样的对象呢?例如:一个组件,代表了一个框架,模块,这种实体域的对象,一般不需要工厂模式或者说不至于使用工厂模式,因为通常对象只会被构建一次。其实这就是Spring中一般使用单例Bean来构建框架,使用原型Bean来创建对象的意义是一样的。
通常情况下,设计模式是辅助我们设计出可扩展性高、且合理的代码,但是一个程序、框架最核心需要的是对业务或者需求的认知程度和代码严谨程度,性能。我觉得设计模式更深层次解决的是我们对于事物的一种认识的方法论,我们看待问题时需要看到事物的结构和关系,首先回答的是what,而不是how。过程式就是过分强调了how,一开始就思考怎么去做,过程式思维是以自己为中心,导演了整个功能流程,自己承担了太多自己不应该承担的职责,整个设计就显得不灵活。面向对象是从对象的角度去看问题,解决问题是由各个对象协作完成,设计模式的基石就是面向对象,脱离了面向对象去谈设计模式是不对的。
AOP在Spring中的应用
到现在为止,代理框架有了。具体使用,就是需要我们自己手动或者自动识别出切面,然后调用代理框架的ProxyFactory来生成对应的对象就行了。
在Spring中的对象自动代理是通过BeanPostProcessor或者SmartInstantiationAwareBeanPostProcessor这个类来实现的,因为需要解决循环依赖的问题,这两者的调用时机有所区别,在Spring的生命周期中,会回调postProcessAfterInitialization这个方法。我们知道postProcessAfterInitialization这个方法执行的时机是对象已经被创建完成并且已经初始化完成了之后(属性都已经设置完成)。所以在这个时候,我们需要判断下这个对象是否需要代理,如果需要就调用ProxyFactory生成代理对象然后返回即可。
Spring中主要实现了四种自动创建代理的类:
- 1、InfrastructureAdvisorAutoProxyCreator
- 2、AspectJAwareAdvisorAutoProxyCreator
- 3、AnnotationAwareAspectJAutoProxyCreator
- 4、DefaultAdvisorAutoProxyCreator
AdvisorAutoProxyCreator通常的作用只有两个:
- 1、加载、初始化容器中的切面,子类同时可以根据条件过滤掉一部分切面。
- 2、根据条件筛选出符合条件的切面集合。
特别需要注意,这几个自动创建代理的实现类的都是针对不同场景加载不同的切面,比如InfrastructureAdvisor就是基础设施类、AnnotationAwareAspectJ就是Aspect注解的切面进行加载,然后再自动创建代理类。再次强调下,这四种不同的自动创建代理类的不同点都是体现在加载不同类型的切面。
父类AbstractAutoProxyCreator的实现如下:
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// 如果是框架内部的类Advice Pointcut Advisor AopInfrastructureBean就不增强了,并且标记下,
// 这个方法子类可以根据特定的情况重写,达到不需要增强的要求。
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// 关键的方法,主要做的事情就是获取容器内部所有的Advice类然后针对当前的类进行判断使用可以应用到这个类上,不同的子类可以对其进行不同的实现。
// 注意这里的判断的粒度只是说明当前的类可以应用这个切面,具体哪个方法需要执行的时候才可以决定。
// Create proxy if we have advice.
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
// 如果查到了切面,那么就标记下,后续不会在解析了
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 第二个关键的方法,调用ProxyFactory代理框架创建代理类对象
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
// 使用ProxyFactory来创建代理对象
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
// 构建切面信息,主要是将一部分Advice转换成Advisor
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
// 添加切面信息到配置类
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
// 创建代理类
return proxyFactory.getProxy(getProxyClassLoader());
}
可以看到父类的这个方法定义了一个创建代理对象的模板。
getAdvicesAndAdvisorsForBean
具体获取切面的逻辑,以及筛选的逻辑,子类可以根据不同的使用场景实现。
注意,每个不同场景的自动代理创建器的获取切面以及筛选逻辑可能都不尽相同,那么这个方法需要抽取出来,由不同的子类来进行实现。
这里我们就看下AnnotationAwareAspectJAutoProxyCreator的实现。
// AnnotationAwareAspectJAutoProxyCreator获取切面的实现
@Override
protected List<Advisor> findCandidateAdvisors() {
// Add all the Spring advisors found according to superclass rules.
List<Advisor> advisors = super.findCandidateAdvisors();
// Build Advisors for all AspectJ aspects in the bean factory.
if (this.aspectJAdvisorsBuilder != null) {
// 主要的作用就是根据获取带有Aspect注解的切面类,并解析出对应的切面。
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
// 解析切面类的主要方法
public List<Advisor> buildAspectJAdvisors() {
List<String> aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
List<Advisor> advisors = new ArrayList<>();
aspectNames = new ArrayList<>();
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
for (String beanName : beanNames) {
// 默认实现都是true
if (!isEligibleBean(beanName)) {
continue;
}
// We must be careful not to instantiate beans eagerly as in this case they
// would be cached by the Spring container but would not have been weaved.
Class<?> beanType = this.beanFactory.getType(beanName);
if (beanType == null) {
continue;
}
// 判断类型是否为带有Aspect注解的类
if (this.advisorFactory.isAspect(beanType)) {
aspectNames.add(beanName);
AspectMetadata amd = new AspectMetadata(beanType, beanName);
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
if (this.beanFactory.isSingleton(beanName)) {
this.advisorsCache.put(beanName, classAdvisors);
}
else {
this.aspectFactoryCache.put(beanName, factory);
}
advisors.addAll(classAdvisors);
}
else {
// Per target or per this.
if (this.beanFactory.isSingleton(beanName)) {
throw new IllegalArgumentException("Bean with name '" + beanName +
"' is a singleton, but aspect instantiation model is not singleton");
}
MetadataAwareAspectInstanceFactory factory =
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
this.aspectFactoryCache.put(beanName, factory);
// 在这里解析的
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
}
this.aspectBeanNames = aspectNames;
return advisors;
}
}
}
if (aspectNames.isEmpty()) {
return Collections.emptyList();
}
List<Advisor> advisors = new ArrayList<>();
for (String aspectName : aspectNames) {
List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
if (cachedAdvisors != null) {
advisors.addAll(cachedAdvisors);
}
else {
MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
return advisors;
}
// 解析类里面的切面
@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
validate(aspectClass);
// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
// so that it will only instantiate once.
MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
List<Advisor> advisors = new ArrayList<>();
for (Method method : getAdvisorMethods(aspectClass)) {
// 生成切面
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}
// If it's a per target aspect, emit the dummy instantiating aspect.
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
advisors.add(0, instantiationAdvisor);
}
// Find introduction fields.
for (Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}
return advisors;
}
@Override
@Nullable
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) {
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
// 根据注解里面的内容,生成切点
AspectJExpressionPointcut expressionPointcut = getPointcut(
candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {
return null;
}
// 根据方法和切点生成一个增强类。这个类主要的功能是封装一下切面的获取逻辑
return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}
// 最终需要调用AspectJAdvisorFactory来生成对应的切面。
private Advice instantiateAdvice(AspectJExpressionPointcut pointcut) {
Advice advice = this.aspectJAdvisorFactory.getAdvice(this.aspectJAdviceMethod, pointcut,
this.aspectInstanceFactory, this.declarationOrder, this.aspectName);
return (advice != null ? advice : EMPTY_ADVICE);
}
// 生成具体切面的方法
public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
validate(candidateAspectClass);
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
}
// If we get here, we know we have an AspectJ method.
// Check that it's an AspectJ-annotated class
if (!isAspect(candidateAspectClass)) {
throw new AopConfigException("Advice must be declared inside an aspect type: " +
"Offending method '" + candidateAdviceMethod + "' in class [" +
candidateAspectClass.getName() + "]");
}
if (logger.isDebugEnabled()) {
logger.debug("Found AspectJ method: " + candidateAdviceMethod);
}
AbstractAspectJAdvice springAdvice;
// 根据不同的注解类型,来生成不同的切面。
switch (aspectJAnnotation.getAnnotationType()) {
case AtPointcut:
if (logger.isDebugEnabled()) {
logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
}
return null;
case AtAround:
springAdvice = new AspectJAroundAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtBefore:
springAdvice = new AspectJMethodBeforeAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfter:
springAdvice = new AspectJAfterAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfterReturning:
springAdvice = new AspectJAfterReturningAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterReturningAnnotation.returning())) {
springAdvice.setReturningName(afterReturningAnnotation.returning());
}
break;
case AtAfterThrowing:
springAdvice = new AspectJAfterThrowingAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
}
break;
default:
throw new UnsupportedOperationException(
"Unsupported advice type on method: " + candidateAdviceMethod);
}
// Now to configure the advice...
springAdvice.setAspectName(aspectName);
springAdvice.setDeclarationOrder(declarationOrder);
String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
if (argNames != null) {
springAdvice.setArgumentNamesFromStringArray(argNames);
}
springAdvice.calculateArgumentBindings();
return springAdvice;
}
这里获取到了对应的切面之后,就可以通过调用代理框架,来实现自动创建代理对象的功能了。
其他的实现类大同小异。
代理模式在事务中的实现
SpringTX的代码,主要分为两部分,一部分是使用代理框架(AOP),另一部分是实现事务的逻辑。我们分开分析。这样清晰一些。
首先,我们先不考虑事务是如何实现的,我们先来看下代理模式是如何在事务这种场景中应用起来的,注意是如何使用代理框架。
事务如何使用代理框架
首先,我们看这个类AbstractSingletonProxyFactoryBean,通过类名我们就知道,这是个Spring容器提供的可以根据定义的配置来自动生成ProxyFactory并产生Proxy的类。该类在Spring容器初始化过程中会回调getObject来获取实例,同时该类还实现了InitializingBean,那么这个类在实例初始化完成之后会回调afterPropertiesSet方法。再次提醒下,我们需要对于这个类的职责有一个非常清晰的认识。
最后,我们注意到该类还继承了ProxyConfig,那么这个类就具有持有一些AOP的配置的能力,比如切面等。
我们先来看afterPropertiesSet,这个方法中主要初始化了ProxyFactory对象。
@Override
public void afterPropertiesSet() {
if (this.target == null) {
throw new IllegalArgumentException("Property 'target' is required");
}
if (this.target instanceof String) {
throw new IllegalArgumentException("'target' needs to be a bean reference, not a bean name as value");
}
if (this.proxyClassLoader == null) {
this.proxyClassLoader = ClassUtils.getDefaultClassLoader();
}
// 应用ProxyFactory的老规矩,首先创建一个实例
ProxyFactory proxyFactory = new ProxyFactory();
if (this.preInterceptors != null) {
// 这里预置一些前置的拦截器,可以手动设置
for (Object interceptor : this.preInterceptors) {
proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(interceptor));
}
}
// 增加拦截器
// Add the main interceptor (typically an Advisor).
// 增加一个创建拦截器的逻辑,这部分逻辑子类可以覆盖
proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(createMainInterceptor()));
if (this.postInterceptors != null) {
// 增加后置拦截器,可以手动设置
for (Object interceptor : this.postInterceptors) {
proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(interceptor));
}
}
proxyFactory.copyFrom(this);
TargetSource targetSource = createTargetSource(this.target);
proxyFactory.setTargetSource(targetSource);
if (this.proxyInterfaces != null) {
proxyFactory.setInterfaces(this.proxyInterfaces);
}
else if (!isProxyTargetClass()) {
// Rely on AOP infrastructure to tell us what interfaces to proxy.
Class<?> targetClass = targetSource.getTargetClass();
if (targetClass != null) {
proxyFactory.setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
}
}
// 增加一个回调接口
postProcessProxyFactory(proxyFactory);
this.proxy = proxyFactory.getProxy(this.proxyClassLoader);
}
首先,我们注意到在预置拦截器,回调接口的时候,这里提供了前置、后置的拦截器以及回调的设置,使得用户能够有目的的增加对应拦截器的能力,这种预先留置方式值得借鉴。流程的关键节点,我们通常需要留出可扩展点,供使用者使用。这里只是引申了一下。
接下来我们看下createMainInterceptor方法,这个方法在父类是抽象的,子类需要根据不同的场景来创建不同的MethodInterceptor。
@Override
protected Object createMainInterceptor() {
// 这部分是事务初始化相关逻辑,暂时先不管
this.transactionInterceptor.afterPropertiesSet();
// 判断了切点是否为空,如果不为空就使用传入的切点
if (this.pointcut != null) {
// 交给外部去实现切面的过滤逻辑
return new DefaultPointcutAdvisor(this.pointcut, this.transactionInterceptor);
}
else {
// 通常的默认实现transactionInterceptor是一个增强,主要实现了事务的主要功能。
// Rely on default pointcut.
return new TransactionAttributeSourceAdvisor(this.transactionInterceptor);
}
}
TransactionAttributeSourceAdvisor中持有TransactionInterceptor增强,TransactionAttributeSourcePointcut切点。
这个切点,我们再多说几句。
TransactionAttributeSourcePointcut切点继承了StaticMethodMatcherPointcut
@Override
public final MethodMatcher getMethodMatcher() {
// 也就是说TransactionAttributeSourcePointcut的MethodMatcher就是自己。
return this;
}
TransactionAttributeSourcePointcut的MethodMatcher就是自己。
TransactionAttributeSourcePointcut的ClassFilter是TransactionAttributeSourceClassFilter。
那么接下来,我们看下TX的AOP分别过滤类和过滤方法是如何实现的。
1、过滤类
TransactionAttributeSourceClassFilter
@Override
public boolean matches(Class<?> clazz) {
// 如果是TX的组件类,那么直接返回false
if (TransactionalProxy.class.isAssignableFrom(clazz) ||
PlatformTransactionManager.class.isAssignableFrom(clazz) ||
PersistenceExceptionTranslator.class.isAssignableFrom(clazz)) {
return false;
}
TransactionAttributeSource tas = getTransactionAttributeSource();
// 通过TransactionAttributeSource来判断是否是候选类。
return (tas == null || tas.isCandidateClass(clazz));
}
TransactionAttributeSource在Spring容器中通常使用的是AnnotationTransactionAttributeSource,通过注解的方式解析TransactionAttribute。
@Override
public boolean isCandidateClass(Class<?> targetClass) {
// 通过注解解析器来实现的。
for (TransactionAnnotationParser parser : this.annotationParsers) {
if (parser.isCandidateClass(targetClass)) {
return true;
}
}
return false;
}
1、Ejb3TransactionAnnotationParser
2、JtaTransactionAnnotationParser
3、SpringTransactionAnnotationParser
这里由三种解析器,默认我们使用SpringTransactionAnnotationParser。
@Override
public boolean isCandidateClass(Class<?> targetClass) {
return AnnotationUtils.isCandidateClass(targetClass, Transactional.class);
}
public static boolean isCandidateClass(Class<?> clazz, String annotationName) {
if (annotationName.startsWith("java.")) {
return true;
}
if (AnnotationsScanner.hasPlainJavaAnnotationsOnly(clazz)) {
return false;
}
return true;
}
规则如下:
java.开头的注解,所有的类都能承载
给定类不能以java.开头,也就是说JDK中的类都不行
给定类也不能是Ordered类
2、过滤方法
@Override
public boolean matches(Method method, Class<?> targetClass) {
TransactionAttributeSource tas = getTransactionAttributeSource();
return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}
这里我们需要知道,判断一个方法是否符合TX是依赖发现并初始化TransactionAttribute来实现的。
public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
if (method.getDeclaringClass() == Object.class) {
return null;
}
// First, see if we have a cached value.
Object cacheKey = getCacheKey(method, targetClass);
TransactionAttribute cached = this.attributeCache.get(cacheKey);
if (cached != null) {
// Value will either be canonical value indicating there is no transaction attribute,
// or an actual transaction attribute.
if (cached == NULL_TRANSACTION_ATTRIBUTE) {
return null;
}
else {
return cached;
}
}
else {
// 获取并组装TransactionAttribute信息,这里有一点需要注意的是
// 获取TransactionAttribute信息的时候优先获取的是方法的,方法没有才会获取类的。
// 并且值得注意的是,Transaction注解是可以被子类继承的。也就是在接口我们可以定义Transaction注解,实现的子类能看到
// We need to work it out.
TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
// Put it in the cache.
// 缓存起来
if (txAttr == null) {
this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
}
else {
String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
if (txAttr instanceof DefaultTransactionAttribute) {
((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification);
}
if (logger.isTraceEnabled()) {
logger.trace("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
}
this.attributeCache.put(cacheKey, txAttr);
}
return txAttr;
}
}
@Override
@Nullable
protected TransactionAttribute findTransactionAttribute(Method method) {
return determineTransactionAttribute(method);
}
protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {
for (TransactionAnnotationParser parser : this.annotationParsers) {
// 解析方法的Transaction注解
TransactionAttribute attr = parser.parseTransactionAnnotation(element);
if (attr != null) {
return attr;
}
}
return null;
}
总结下过滤方法的规则就是:
判断当前类或者父类是否存在Transaction注解。
最后我们来总结下事务如何使用代理框架:
1、首先使用了AbstractSingletonProxyFactoryBean类来保证对象的初始化的时候是自动经过代理的。
2、TransactionAttributeSourceAdvisor中持有TransactionInterceptor增强,TransactionAttributeSourcePointcut切点。
2.1、TransactionInterceptor增强即事务的核心逻辑
2.2、TransactionAttributeSourcePointcut切点中TransactionAttributeSourcePointcut的MethodMatcher就是自己。
TransactionAttributeSourcePointcut的ClassFilter是TransactionAttributeSourceClassFilter。
2.2.1、过滤类的规则如下:java.开头的注解,所有的类都能承载,给定类不能以java.开头,也就是说JDK中的类都不行,给定类也不能是Ordered类
2.2.2、过滤方法的规则如下:判断当前类或者父类是否存在Transaction注解。
以上就是TX的Spring中如何被使用的。
注意,这里仅仅分析了手动创建事务的类型。同时Spring还支持注解的方式自动加载切面和生成代理。这里就不再详细说明了,应用代理框架的方式大同小异。