Spring AOP 详解及@Trasactional

Spring AOP 详解

AOP基础

AOP: Aspect Oriented Program, 面向切面编程。解耦(组织结构调整)、增强(扩展)。

AOP术语

术语

说明

Aspect(切面)

横切于系统的连接点实现特定功能的类

JoinPoint(连接点)

系统执行的某个动态阶段,如对象操作、方法调用等

Pointcut(切点)

定义了Aspect发生作用的切入特征

Advice(增强)

在连接点执行的增强操作

Target Object(目标对象)

Advice作用对象、被增强对象

Proxy(代理)

为了实施增强,动态创建的对象。

Weaving(织入)

构建可以针对目标对象实施增强行为的代理对象的基础过程。

AOP Aliance

AOP Aliance: AOP联盟,定义了AOP的基础规范。

AOP JavaAPIDoc 网址: Generated Documentation (Untitled)

AOP 官方白皮书地址:https://aopalliance.sourceforge.net/white_paper/white_paper.pdf

图1 Spring AOP中的AOP Aliance 基本接口

AspectJ

AsprctJ 是Java社区里最完整最流行的AOP框架。

官网: AspectJ Documentation | The Eclipse Foundation

AspectJ提供了完整的AOP解决方案,支持以下三种织入时机:

  • compile-time:编译期织入,编译出包含织入代码的 .class 文件
  • post-compile:编译后织入,增强已经编译出来的类,如我们要增强依赖的 jar 包中的某个类的某个方法
  • load-time:在 JVM 进行类加载的时候进行织入

Spring AOP 和 AspectJ

Spring AOP: 为Spring IoC上提供的AOP实现,应用于Spring Bean容器管理的,以及Spring 框架其他技术,如Spring Transactional

AspectJ: 提供完整的AOP解决方案。它比Spring AOP更强大,但也更复杂。还值得注意的是,AspectJ可以应用于所有域对象。

Spring AOP

AspectJ

用纯Java实现

使用Java编程语言的扩展实现

无需单独的编译过程

除非设置了LTW,否则需要AspectJ编译器(ajc)

仅需运行时编织

运行时编织不可用。支持编译时,后编译和加载时编织

不足–仅支持方法级编织

更强大–可以编织字段,方法,构造函数,静态初始值设定项,最终类/方法等…

只能在Spring容器管理的bean上实现

可以在所有领域对象上实施

仅支持方法执行切入点

支持所有切入点

代理是针对目标对象创建的,并且方面已应用于这些代理

在应用程序执行之前(运行时之前)将方面直接编织到代码中

比AspectJ慢得多

更好的性能

易于学习和应用

比Spring AOP复杂得多

Spring AOP代理的生成

Cglib代理和JDK动态代理。

JDK 动态代理是JDK内置的动态代理工具,底层原理是反射机制,为目标接口创建代理,动态代理类需要实现InvocationHandler接口。代理实现原理是通过实现被代理类的接口,被代理对象由InvocationHandler进行包装调用。

public interface InvocationHandler {

   /**

     * @param proxy 包装的代理对象

     * @param method 调用的方法

     * @param args 调用方法参数

    */

    public Object invoke(Object proxy, Method method, Object[] args)

        throws Throwable;

}

public static <T> T getProxyObject(T object,

                               InvocationHandler h) {

return (T) Proxy.newProxyInstance(object.getClass().getClassLoader(),

                        object.getClass().getInterfaces(), h);

}

try {

    super.h.invoke(this, m3, (Object[])null);

} catch (RuntimeException | Error var2) {

    throw var2;

} catch (Throwable var3) {

    throw new UndeclaredThrowableException(var3);

}

Cglib底层原理通过字节码处理框架ASM修改类的字节码生成继承方法的子类,通过修改字节码生成子类代理直接代替实体类,需要实现MethodInterceptor接口。 继承方式意味着不能对final修饰的类、final修饰的方法、私有方法进行代理。

public interface MethodInterceptor

extends Callback

{

    /**

     * 拦截方法逻辑

     *

     * @param o           被增强的对象

     * @param method      被增强的方法

     * @param args        方法的参数

     * @param methodProxy 方法的代理对象

     * @return 方法返回值

     */

    public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,

                               MethodProxy proxy) throws Throwable;

}

Enhancer.create(object.getClass(), methodInterceptor)

Spring AOP 创建代理过程

下面介绍了Spring Aop支持AspectJ注解的代理创建过程, 其他注解的AOP类似,只是通过不同的扩展点来创建代理对象,如ProxyFactoryBean或BeanPostProcessor。

@EnableAspectJAutoProxy

项目为启用AspectJ的Spring-AOP,通常会再配置文件中加上@EnableAspectJAutoProxy

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@Documented

@Import(AspectJAutoProxyRegistrar.class)

public @interface EnableAspectJAutoProxy {

         boolean proxyTargetClass() default false;

         boolean exposeProxy() default false;

}

@Import(AspectJAutoProxyRegistrar.class)

@Import 注解包含一个实现了ImportBeanDefinitionRegistrar的类, 注册重要的Bean用于后续Bean初始化。AspectJAutoProxyRegistrar

public void registerBeanDefinitions(

                          AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

                  AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

                  AnnotationAttributes enableAspectJAutoProxy =

                                   AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);

                  if (enableAspectJAutoProxy != null) {

                          if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {

                                   AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);

                          }

                          if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {

                                   AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);

                          }

                  }

         }

AnnotationAwareAspectJAutoProxyCreator

AnnotationAwareAspectJAutoProxyCreator负责创建AOP代理,实现了SmartInstantiationAwareBeanPostProcessor(InstantiationAwareBeanPostProcessor) 接口,核心创建逻辑在postProcessBeforeInstantiation实现中。

public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {

         //缓存Bean类和名称,避免重复处理

         Object cacheKey = getCacheKey(beanClass, beanName);

         if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {

                  if (this.advisedBeans.containsKey(cacheKey)) {

                          return null;

                  }

                  if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {

                          this.advisedBeans.put(cacheKey, Boolean.FALSE);

                          return null;

                  }

         }

         // Create proxy here if we have a custom TargetSource.

         // Suppresses unnecessary default instantiation of the target bean:

         // The TargetSource will handle target instances in a custom fashion.

         TargetSource targetSource = getCustomTargetSource(beanClass, beanName);

         if (targetSource != null) {

                  if (StringUtils.hasLength(beanName)) {

                          this.targetSourcedBeans.add(beanName);

                  }

                  //检查AOP相关配置是否作用在Bean上,如果不匹配这里返回空, 再下一步创建proxy将返回空

                  Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);

                  Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);

                  this.proxyTypes.put(cacheKey, proxy.getClass());

                  return proxy;

         }

         return null;

}

检查是否该创建Bean对象的逻辑在AopUtils.canApply方法。

public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {

         if (advisor instanceof IntroductionAdvisor) {

                  return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);

         }

         else if (advisor instanceof PointcutAdvisor) {

                  PointcutAdvisor pca = (PointcutAdvisor) advisor;

                  return canApply(pca.getPointcut(), targetClass, hasIntroductions);

         }

         else {

                  // It doesn't have a pointcut so we assume it applies.

                  return true;

         }

}

AopProxyFactory

继续跟进代码 最终由AopProxyFactory来创建。 AopProxyFactory 调用AopProxy接口的getProxy方法创建代理对象。 AopProxy有两个实现:JdkDynamicAopProxy和ObjenesisCglibAopProxy对应于JDK动态代理和Cglib代理实现。

选择AopProxy的代码如下:

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {

                  if (!NativeDetector.inNativeImage() &&

                                   (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))) {

                          Class<?> targetClass = config.getTargetClass();

                          if (targetClass == null) {

                                   throw new AopConfigException("TargetSource cannot determine target class: " +

                                                     "Either an interface or a target is required for proxy creation.");

                          }

                          if (targetClass.isInterface() || Proxy.isProxyClass(targetClass) || ClassUtils.isLambdaClass(targetClass)) {

                                   return new JdkDynamicAopProxy(config);

                          }

                          return new ObjenesisCglibAopProxy(config);

                  }

                  else {

                          return new JdkDynamicAopProxy(config);

                  }

         }

具体创建代理的代码为Cglib和JDK代理的使用方法。如JdkDynamicAopProxy的getProxy()代码如下:

public Object getProxy(@Nullable ClassLoader classLoader) {

                  if (logger.isTraceEnabled()) {

                          logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());

                  }

                  return Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this);

         }

Spring AOP切面相关抽象及解析过程

主要抽象
Advice

Org.aopalliance.aop.Advice: AOP联盟的Advice接口,代表增强入口,其实现包括Interceptors或其他任何类型的Advice。

Org.aopalliance.intercept.interceptor: : 指可以针对Joint事件进行拦截的拦截器。

MethodInterceptor:对接口调用的拦截

public interface MethodInterceptor extends Interceptor {

  @Nullable

  Object invoke(@Nonnull MethodInvocation invocation) throws Throwable;

}

ConstructorInterceptor: 对对象构造的拦截

DynamicIntroductionAdvice:支持在Advice上实现附加接口。

public interface DynamicIntroductionAdvice extends Advice {

  boolean implementsInterface(Class<?> intf);

}

IntroductionInterceptor extends MethodInterceptor, DynamicIntroductionAdvice : 通过Interceptor实现DynamicIntroductionAdvice。

       IntroductionInfo: 描述引入接口的信息

MethodBeforeAdvice: 在方法调用之前执行的Advice

AfterReturningAdvice: 在方法返回之后执行的Advice

ThrowsAdvice: 异常抛出后执行的Advice

       public void afterThrowing(Exception ex)

       public void afterThrowing(RemoteException)

       public void afterThrowing(Method method, Object[] args, Object target, Exception ex)

       public void afterThrowing(Method method, Object[] args, Object target, ServletException ex)

ClassFilter

ClassFilter: 负责检查一个pointcut 或则 introduction时候和目标类匹配

public interface ClassFilter {

  boolean matches(Class<?> clazz);

}

MethodMatcher

MethodMatcher:负责检查方法是否匹配Advice

public interface MethodMatcher {

         boolean matches(Method method, Class<?> targetClass);

         boolean isRuntime();

         boolean matches(Method method, Class<?> targetClass, Object... args);

}

Advisor

Advisor: 持有AOP Advice信息的接口,

public interface Advisor {

  //返回切面的Advice信息, Advice指interceptor、before advice 、throw advice等

  Advice getAdvice();

  //Advisor是否共享

  boolean isPerInstance();

}

AdvisorChainFactory

实现类DefaultAdvisorChainFactory,接口方法getInterceptorsAndDynamicInterceptionAdvice返回指定方法的Advice链(增强链),当执行代理对象时根据这里放回的Advice链进行增强。

for (Advisor advisor : advisors) {

         if (advisor instanceof PointcutAdvisor) {

                  // Add it conditionally.

                  PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;

                  if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {

                          MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();

                          boolean match;

                          if (mm instanceof IntroductionAwareMethodMatcher) {

                                   if (hasIntroductions == null) {

                                            hasIntroductions = hasMatchingIntroductions(advisors, actualClass);

                                   }

                                   match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions);

                          }

                          else {

                                   match = mm.matches(method, actualClass);

                          }

                          if (match) {

                                   MethodInterceptor[] interceptors = registry.getInterceptors(advisor);

                                   if (mm.isRuntime()) {

                                            // Creating a new object instance in the getInterceptors() method

                                            // isn't a problem as we normally cache created chains.

                                            for (MethodInterceptor interceptor : interceptors) {

                                                     interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));

                                            }

                                   }

                                   else {

                                            interceptorList.addAll(Arrays.asList(interceptors));

                                   }

                          }

                  }

         }

         else if (advisor instanceof IntroductionAdvisor) {

                  IntroductionAdvisor ia = (IntroductionAdvisor) advisor;

                  if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {

                          Interceptor[] interceptors = registry.getInterceptors(advisor);

                          interceptorList.addAll(Arrays.asList(interceptors));

                  }

         }

         else {

                  Interceptor[] interceptors = registry.getInterceptors(advisor);

                  interceptorList.addAll(Arrays.asList(interceptors));

         }

}

Advised

Advised是AOP的配置信息, AOP代理的创建时基于Advised提供的Advise及Advisor信息创建。

如:Advised接口提供了Advisor的管理方法(get/addAdvisors)。

AopContext

AopContext 提供AOP线程上线文的。

ThreadLocal<Object> currentProxy = new NamedThreadLocal<>("Current AOP proxy");

ProxyConfig

AOP 代理创建的配置类, 提取公共父类保证代理的一致性。

ProxyConfig作为AOP代理创建代理对象的一个基础类,其实现展示了几种代理的实现机制。

BeanFactoryAware+BeanPostProcessor方式

AbstractAdvisingBeanPostProcessor及其子类使用该模式进行框架初始化, 该模式针对特定切面,如Async。通过setBeanFactory方法初始Advisor信息, 并在postProcessAfterInitialization方法中创建代理对象。

AsyncAnnotationBeanPostProcessor

@Override

public void setBeanFactory(BeanFactory beanFactory) {

         super.setBeanFactory(beanFactory);

         AsyncAnnotationAdvisor advisor = new AsyncAnnotationAdvisor(this.executor, this.exceptionHandler);

         if (this.asyncAnnotationType != null) {

                  advisor.setAsyncAnnotationType(this.asyncAnnotationType);

         }

         advisor.setBeanFactory(beanFactory);

         this.advisor = advisor;

}

@Override

public Object postProcessAfterInitialization(Object bean, String beanName) {

         ......

         if (isEligible(bean, beanName)) {

                  ProxyFactory proxyFactory = prepareProxyFactory(bean, beanName);

                  if (!proxyFactory.isProxyTargetClass()) {

                          evaluateProxyInterfaces(bean.getClass(), proxyFactory);

                  }

                  proxyFactory.addAdvisor(this.advisor);

                  customizeProxyFactory(proxyFactory);

                  // Use original ClassLoader if bean class not locally loaded in overriding class loader

                  ClassLoader classLoader = getProxyClassLoader();

                  if (classLoader instanceof SmartClassLoader && classLoader != bean.getClass().getClassLoader()) {

                          classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader();

                  }

                  return proxyFactory.getProxy(classLoader);

         }

         // No proxy needed.

         return bean;

}

protected boolean isEligible(Class<?> targetClass) {

         Boolean eligible = this.eligibleBeans.get(targetClass);

         if (eligible != null) {

                  return eligible;

         }

         if (this.advisor == null) {

                  return false;

         }

         eligible = AopUtils.canApply(this.advisor, targetClass);

         this.eligibleBeans.put(targetClass, eligible);

         return eligible;

}

基于SmartInstantiationAwareBeanPostProcessor的AutoProxyCreator

AOP关于AspectJ注解的支持是基于该模式创建, 该模式的特点是: 1. 支持各种不同功能的切面增强。 2. 代理对象负责创建目标对象,支持目标对象的延迟创建。

基于postProcessBeforeInstantiation接口创建。

public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {

         Object cacheKey = getCacheKey(beanClass, beanName);

         // Create proxy here if we have a custom TargetSource.

         // Suppresses unnecessary default instantiation of the target bean:

         // The TargetSource will handle target instances in a custom fashion.

         TargetSource targetSource = getCustomTargetSource(beanClass, beanName);

         if (targetSource != null) {

                  if (StringUtils.hasLength(beanName)) {

                          this.targetSourcedBeans.add(beanName);

                  }

                  Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);

                  Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);

                  this.proxyTypes.put(cacheKey, proxy.getClass());

                  return proxy;

         }

         return null;

}

相关代码见AbstractAutoProxyCreator及其子类, 在Spring AOP创建章节中详细介绍。

初始化核心调用栈示例:

getTransactionAttribute:93, AbstractFallbackTransactionAttributeSource (org.springframework.transaction.interceptor)

matches:42, TransactionAttributeSourcePointcut (org.springframework.transaction.interceptor)

canApply:251, AopUtils (org.springframework.aop.support)

canApply:288, AopUtils (org.springframework.aop.support)

findAdvisorsThatCanApply:320, AopUtils (org.springframework.aop.support)

findAdvisorsThatCanApply:126, AbstractAdvisorAutoProxyCreator (org.springframework.aop.framework.autoproxy)

findEligibleAdvisors:95, AbstractAdvisorAutoProxyCreator (org.springframework.aop.framework.autoproxy)

getAdvicesAndAdvisorsForBean:76, AbstractAdvisorAutoProxyCreator (org.springframework.aop.framework.autoproxy)

wrapIfNecessary:352, AbstractAutoProxyCreator (org.springframework.aop.framework.autoproxy)

postProcessAfterInitialization:304, AbstractAutoProxyCreator (org.springframework.aop.framework.autoproxy)

基于FactoryBean模式创建代理

@Transaction及@Cache注解的创建模式

AbstractSingletonProxyFactoryBean

public void afterPropertiesSet() {

         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);

}

protected Object createMainInterceptor() {

         this.transactionInterceptor.afterPropertiesSet();

         if (this.pointcut != null) {

                  return new DefaultPointcutAdvisor(this.pointcut, this.transactionInterceptor);

         }

         else {

                  // Rely on default pointcut.

                  return new TransactionAttributeSourceAdvisor(this.transactionInterceptor);

         }

}

//TransactionProxyFactoryBean

AopProxy

AOP 代理接口实现类包括Cglib和Jdk动态代理

      

AopProxyFactory

AopProxy工厂接口,负责创建AopProxy对象。实现类是DefaultAopProxyFactory

                  Class<?> targetClass = config.getTargetClass();

                  if (targetClass == null) {

                          throw new AopConfigException("TargetSource cannot determine target class: " +

                                            "Either an interface or a target is required for proxy creation.");

                  }

                  if (targetClass.isInterface() || Proxy.isProxyClass(targetClass) || ClassUtils.isLambdaClass(targetClass)) {

                          return new JdkDynamicAopProxy(config);

                  }

                  return new ObjenesisCglibAopProxy(config);

注解信息的解析(Advised对象的创建)

Advised对象的解析过程同ProxyConfig章节介绍的代理对象过程类似,同样是三种模式的解析过程。

AbstractAdvisingBeanPostProcessor

AbstractAdvisingBeanPostProcessor 针对特定注解创建代理对象模式。扩展点BeanPostProcessor 的postProcessAfterInitialization方法中检查注解是否作用在Bean上,如是则创建代理。

if (isEligible(bean, beanName)) {

         ProxyFactory proxyFactory = prepareProxyFactory(bean, beanName);

         if (!proxyFactory.isProxyTargetClass()) {

                  evaluateProxyInterfaces(bean.getClass(), proxyFactory);

         }

         proxyFactory.addAdvisor(this.advisor);

         customizeProxyFactory(proxyFactory);

         // Use original ClassLoader if bean class not locally loaded in overriding class loader

         ClassLoader classLoader = getProxyClassLoader();

         if (classLoader instanceof SmartClassLoader && classLoader != bean.getClass().getClassLoader()) {

                  classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader();

         }

         return proxyFactory.getProxy(classLoader);

}

AbstractSingletonProxyFactoryBean

基于FactoryBean机制,对通过XML配置的FactoryBean,针对目标Bean解析所得Advicsed对象。

<bean id="target" class="org.springframework.beans.testfixture.beans.DerivedTestBean" lazy-init="true">

         <property name="name"><value>custom</value></property>

         <property name="age"><value>666</value></property>

         <property name="spouse"><ref bean="targetDependency"/></property>

</bean>

<bean id="baseProxyFactory" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"

           abstract="true">

         <property name="transactionManager"><ref bean="mockMan"/></property>

         <property name="transactionAttributes">

                  <props>

                          <prop key="s*">PROPAGATION_MANDATORY</prop>

                          <prop key="setAg*">  PROPAGATION_REQUIRED  ,  readOnly  </prop>

                          <prop key="set*">PROPAGATION_SUPPORTS</prop>

                  </props>

         </property>

</bean>

<bean id="proxyFactory2Cglib" parent="baseProxyFactory">

         <property name="proxyTargetClass"><value>true</value></property>

         <property name="target"><ref bean="target"/></property>

</bean>

public void afterPropertiesSet() {

         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);

}

ProxyFactoryBean

基于ProxyFactoryBean创建的代理的对象,在获取对象时会检查是否需要解析和创建AOP 的代理。

public Object getObject() throws BeansException {

         initializeAdvisorChain();

         if (isSingleton()) {

                  return getSingletonInstance();

         }

         else {

                  if (this.targetName == null) {

                          logger.info("Using non-singleton proxies with singleton targets is often undesirable. " +

                                            "Enable prototype proxies by setting the 'targetName' property.");

                  }

                  return newPrototypeInstance();

         }

}

Spring AOP的执行

JDK代理执行代码

JdkDynamicAopProxy 执行了JDK动态代理的InvocationHandler接口, 执行入口就是JdkDynamicAopProxy的invoke方法。

流程:

  1. 获取该方法匹配的Advice

// Get the interception chain for this method.

List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

查找匹配实现为接口AdvisorChainFactory接口的实现类:DefaultAdvisorChainFactory。

public interface AdvisorChainFactory {

         /**

          * Determine a list of {@link org.aopalliance.intercept.MethodInterceptor} objects

          * for the given advisor chain configuration.

          * @param config the AOP configuration in the form of an Advised object

          * @param method the proxied method

          * @param targetClass the target class (may be {@code null} to indicate a proxy without

          * target object, in which case the method's declaring class is the next best option)

          * @return a List of MethodInterceptors (may also include InterceptorAndDynamicMethodMatchers)

          */

         List<Object> getInterceptorsAndDynamicInterceptionAdvice(Advised config, Method method, @Nullable Class<?> targetClass);

}

解析相应的MethodInterceptor接口实现或适配AOP 联盟的语言成为MethodInterceptor接口。

如:MethodBeforeAdviceInterceptor代码如下:

public Object invoke(MethodInvocation mi) throws Throwable {

         this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());

         return mi.proceed();

}

  1. 执行

// 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();

  1. ReflectiveMethodInvocation 处理方法

public Object proceed() throws Throwable {

                  // We start with an index of -1 and increment early.

                  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);

                  }

         }

AopContext

AopContext类可以再代理类执行过程中获取到代理对象, 通过代理对象可以保证基于AOP增强的特性得到执行,从而解决直接this.xxx调用直接执行被代理对象的方法,造成增强实效。

Spring Aop 应用-@Transactional

       Spring Transaction就是基于Spring AOP机制实现的事务。

解析@Transactionnal

       事务的拦截逻辑实现主要在TransactionInterceptor类中, 如果通过XML文件配置的TransactionProxyFactoryBean创建代理对象,则在FactoryBean的afterProperties方法中创建Advisor生成proxyFactory对象(见上面章节)。

对于基于注解的Transaction注解解析在于TransactionAttributeSourcePointcut由AOP框架触发解析判断某个方法是否满足Transactional注解。

解析逻辑代码如下:

@Nullable

protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {

         // Don't allow non-public methods, as configured.

         if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {

                  return null;

         }

         // The method may be on an interface, but we need attributes from the target class.

         // If the target class is null, the method will be unchanged.

         Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);

         // First try is the method in the target class.

         TransactionAttribute txAttr = findTransactionAttribute(specificMethod);

         if (txAttr != null) {

                  return txAttr;

         }

         // Second try is the transaction attribute on the target class.

         txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());

         if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {

                  return txAttr;

         }

         if (specificMethod != method) {

                  // Fallback is to look at the original method.

                  txAttr = findTransactionAttribute(method);

                  if (txAttr != null) {

                          return txAttr;

                  }

                  // Last fallback is the class of the original method.

                  txAttr = findTransactionAttribute(method.getDeclaringClass());

                  if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {

                          return txAttr;

                  }

         }

         return null;

}

TransactionInterceptor

事务执行逻辑实现与TransactionInterceptor

public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {

// Standard transaction demarcation with getTransaction and commit/rollback calls.

TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);

Object retVal;

try {

         // This is an around advice: Invoke the next interceptor in the chain.

         // This will normally result in a target object being invoked.

         retVal = invocation.proceedWithInvocation();

}

catch (Throwable ex) {

         // target invocation exception

         completeTransactionAfterThrowing(txInfo, ex);

         throw ex;

}

finally {

         cleanupTransactionInfo(txInfo);

}

if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {

         // Set rollback-only in case of Vavr failure matching our rollback rules...

         TransactionStatus status = txInfo.getTransactionStatus();

         if (status != null && txAttr != null) {

                  retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);

         }

}

commitTransactionAfterReturning(txInfo);

return retVal;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/151417.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

编译工具链 之二 详解 ELF 格式及标准、UNIX 发展、ABI

在计算机及嵌入式系统中&#xff0c;二进制文件也有一定的标准格式&#xff0c;通常会包含在各平台的应用程序二进制接口 &#xff08;Application Binary Interface&#xff0c;ABI&#xff09;规范中。它是编译工具链必须要遵守的规范&#xff08;编译工具链产生符合 ABI 的二…

Qt单一应用实例判断

原本项目中使用QSharedMemory的方法来判断当前是否已存在运行的实例&#xff0c;但在MacOS上&#xff0c;当程序异常崩溃后&#xff0c;QSharedMemory没有被正常销毁&#xff0c;导致应用程序无法再次被打开。 对此&#xff0c;Qt assistant中有相关说明&#xff1a; 摘抄 qt-s…

tailscale自建headscale和derp中继

tailscale自建headscale和derp中继 Tailscale 官方的 DERP 中继服务器全部在境外&#xff0c;在国内的网络环境中不一定能稳定连接&#xff0c;所以有必要建立自己的 DERP 服务器的。 准备工作&#xff1a; 需要有自己的云服务器&#xff0c;本示例为阿里云轻量服务器需要有…

Spring的beanName生成器AnnotationBeanNameGenerator

博主介绍&#xff1a;✌全网粉丝4W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战&#xff0c;博主也曾写过优秀论文&#xff0c;查重率极低&#xff0c;在这方面有丰富的经验…

11.3 读图举例

一、低频功率放大电路 图11.3.1所示为实用低频功率放大电路&#xff0c;最大输出功率为 7 W 7\,\textrm W 7W。其中 A \textrm A A 的型号为 LF356N&#xff0c; T 1 T_1 T1​ 和 T 3 T_3 T3​ 的型号为 2SC1815&#xff0c; T 4 T_4 T4​ 的型号为 2SD525&#xff0c; T 2…

(高阶) Redis 7 第21讲 IO多路复用模型 完结篇

🌹 以下分享 Redis IO多路复用模型,如有问题请指教。🌹🌹 如你对技术也感兴趣,欢迎交流。🌹🌹🌹 如有对阁下帮助,请👍点赞💖收藏🐱‍🏍分享😀 IO多路复用模型是什么 I/O:网络IO 多路:多个客户端连接(连接即套接字描述符,即socket或channel),指…

leetcode 49. 字母异位词分组

2023.10.7 根据字母异位词的定义&#xff0c;可知&#xff1a;所有字母异位词经过排序之后得到的字符串相同&#xff0c;所以可以定义一个哈希表&#xff0c;将排序后的字符串当作哈希表的键&#xff0c;哈希表的值则用来存储该字母异位词对应的所有字符串&#xff0c;最后将哈…

HDLbits: Shift18

先补充一下算术移位寄存器和按位移位寄存器&#xff1a; SystemVerilog具有按位和算术移位运算符。 按位移位只是将向量的位向右或向左移动指定的次数&#xff0c;移出向量的位丢失。移入的新位是零填充的。例如&#xff0c;操作8’b11000101 << 2将产生值8’b00010100…

【数据结构-二叉树 八】【遍历求和】:求根到叶子节点数字之和

废话不多说&#xff0c;喊一句号子鼓励自己&#xff1a;程序员永不失业&#xff0c;程序员走向架构&#xff01;本篇Blog的主题是【遍历求和】&#xff0c;使用【二叉树】这个基本的数据结构来实现&#xff0c;这个高频题的站点是&#xff1a;CodeTop&#xff0c;筛选条件为&am…

练[SUCTF 2019]CheckIn

[SUCTF 2019]CheckIn 文章目录 [SUCTF 2019]CheckIn掌握知识解题思路关键paylaod 掌握知识 ​ .user.ini文件上传利用–需要上传目录有一个php文件(index.php)&#xff0c;文件头绕过&#xff0c;文件内容<&#xff1f;检测 解题思路 打开题目链接&#xff0c;发现又是一…

[SWPUCTF 2021 新生赛]easy_sql - 联合注入||报错注入||sqlmap

[SWPUCTF 2021 新生赛]easy_sql 一、思路分析二、解题方法解法一&#xff1a;手注解法二&#xff1a;报错注入解法三&#xff1a;sqlmap 一、思路分析 这题可以直接参考&#xff1a;[NISACTF 2022]join-us - 报错注入&无列名注入 网站标题提示&#xff0c;参数是wllm ?…

day25--JS进阶(递归函数,深浅拷贝,异常处理,改变this指向,防抖及节流)

目录 浅拷贝 1.拷贝对象①Object.assgin() ②展开运算符newObj {...obj}拷贝对象 2.拷贝数组 ①Array.prototype.concat() ② newArr [...arr] 深拷贝 1.通过递归实现深拷贝 2.lodash/cloneDeep实现 3.通过JSON.stringify()实现 异常处理 throw抛异常 try/catch捕获…

Linux TCP协议通信 (流程 三次握手 四次挥手 滑动窗口)

TCP通信流程 Socket函数 TCP通信实现&#xff08;服务器端&#xff09; #include <stdio.h> #include <arpa/inet.h> #include <unistd.h> #include <string.h> #include <stdlib.h> int main() {//1.创建socketint lfd socket(AF_INET, SOCK_…

kafka的请求处理机制

目录 前言&#xff1a; kafak是如何处理请求的&#xff1f; 控制请求与数据类请求 参考资料 前言&#xff1a; 无论是 Kafka 客户端还是 Broker 端&#xff0c;它们之间的交互都是通过“请求 / 响应”的方式完成的。比如&#xff0c;客户端会通过网络发送消息生产请求给 B…

四位十进制频率计VHDL,DE1开发板验证,仿真和源码

名称&#xff1a;四位十进制频率计VHDL&#xff0c;DE1开发板验证 软件&#xff1a;Quartus 语言&#xff1a;VHDL 要求&#xff1a; 数字频率计设计要求 1、四位十进制数字显示的数学式频率计,其频率测量范围为10~9999khz,测量单位为kHz。 2、要求量程能够转换。即测几十…

蓝桥杯每日一题2023.10.8

题目描述 七段码 - 蓝桥云课 (lanqiao.cn) 题目分析 所有的情况我们可以分析出来一共有2的7次方-1种&#xff0c;因为每一个二极管都有选择和不选择两种情况&#xff0c;有7个二极管&#xff0c;但是还有一种都不选的情况需要排除&#xff0c;故-1 枚举每个方案看是否符合要…

【图像处理】【应用程序设计】加载,编辑和保存图像数据、图像分割、色度键控研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

MongoDB数据库网站网页实例-编程语言Python+Django

程序示例精选 PythonDjangoMongoDB数据库网站网页实例 如需安装运行环境或远程调试&#xff0c;见文章底部个人QQ名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对《PythonDjangoMongoDB数据库网站网页实例》编写代码&#xff0c;代码整洁&#xff0c;…

【ONE·Linux || 多线程(二)】

总言 多线程&#xff1a;生产者消费者模型与两种实现方式&#xff08;条件变量、信号量&#xff09;、线程池。 文章目录 总言4、生产者消费者模型4.1、基本概念4.2、基于BlockingQueue的生产者消费者模型&#xff08;理解条件变量&#xff09;4.2.1、单生产者单消费者模式&am…

golang gin——中间件编程以及jwt认证和跨域配置中间件案例

中间件编程jwt认证 在不改变原有方法的基础上&#xff0c;添加自己的业务逻辑。相当于grpc中的拦截器一样&#xff0c;在不改变grpc请求的同时&#xff0c;插入自己的业务。 简单例子 func Sum(a, b int) int {return a b }func LoggerMiddleware(in func(a, b int) int) f…