SpringAOP详解(下)

proxyFactory代理对象创建方式和代理对象调用方法过程:

springaop创建动态代理对象和代理对象调用方法过程:

一、TargetSource的使用

@Lazy注解,当加在属性上时,会产生一个代理对象赋值给这个属性,产生代理对象的代码为:

java 复制代码
protected Object buildLazyResolutionProxy(final DependencyDescriptor descriptor, final @Nullable String beanName) {
  BeanFactory beanFactory = getBeanFactory();
  Assert.state(beanFactory instanceof DefaultListableBeanFactory,
    "BeanFactory needs to be a DefaultListableBeanFactory");
  final DefaultListableBeanFactory dlbf = (DefaultListableBeanFactory) beanFactory;

  TargetSource ts = new TargetSource() {
   @Override
   public Class<?> getTargetClass() {
    return descriptor.getDependencyType();
   }
   @Override
   public boolean isStatic() {
    return false;
   }
   @Override
   public Object getTarget() {
    Set<String> autowiredBeanNames = (beanName != null ? new LinkedHashSet<>(1) : null);
    Object target = dlbf.doResolveDependency(descriptor, beanName, autowiredBeanNames, null);
    if (target == null) {
     Class<?> type = getTargetClass();
     if (Map.class == type) {
      return Collections.emptyMap();
     }
     else if (List.class == type) {
      return Collections.emptyList();
     }
     else if (Set.class == type || Collection.class == type) {
      return Collections.emptySet();
     }
     throw new NoSuchBeanDefinitionException(descriptor.getResolvableType(),
       "Optional dependency not present for lazy injection point");
    }
    if (autowiredBeanNames != null) {
     for (String autowiredBeanName : autowiredBeanNames) {
      if (dlbf.containsBean(autowiredBeanName)) {
       dlbf.registerDependentBean(autowiredBeanName, beanName);
      }
     }
    }
    return target;
   }
   @Override
   public void releaseTarget(Object target) {
   }
  };

  ProxyFactory pf = new ProxyFactory();
  pf.setTargetSource(ts);
  Class<?> dependencyType = descriptor.getDependencyType();
  if (dependencyType.isInterface()) {
   pf.addInterface(dependencyType);
  }
  return pf.getProxy(dlbf.getBeanClassLoader());
 }

这段代码就利用了ProxyFactory来生成代理对象,以及使用了TargetSource,以达到代理对象在执行某个方法时,调用TargetSource的getTarget()方法实时得到一个被代理对象

二、Introduction

需要使用@EnableAspectJAutoProxy注解

java 复制代码
@Component
public class UserService {

	public void test() {
		System.out.println("test");
	}

}

public interface UserInterface {

	void test();
}

public class UserInterfaceImpl implements UserInterface {

	@Override
	public void test() {
		System.out.println("UserInterfaceImpl");
	}
}

@Aspect
@Component
public class TestAspect {

	@DeclareParents(value="com.spring.service.UserService", defaultImpl=com.spring.service.UserInterfaceImpl.class)
	public UserInterface userInterface;
}



AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
		UserInterface userService = (UserInterface) applicationContext.getBean("userService");
		userService.test();

spring创建bean初始化后会扫描@DeclareParents注解

三、ProxyFactory选择cglib或jdk动态代理原理

ProxyFactory在生成代理对象之前需要决定到底是使用JDK动态代理还是CGLIB技术:

java 复制代码
// config就是ProxyFactory对象

// optimize为true,或proxyTargetClass为true,或用户没有给ProxyFactory对象添加interface
if (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.");
 }
    // targetClass是接口,直接使用Jdk动态代理
 if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
  return new JdkDynamicAopProxy(config);
 }
    // 使用Cglib
 return new ObjenesisCglibAopProxy(config);
}
else {
    // 使用Jdk动态代理
 return new JdkDynamicAopProxy(config);
}

四、代理对象创建过程

1、JdkDynamicAopProxy

  1. 在构造JdkDynamicAopProxy对象时,会先拿到被代理对象自己所实现的接口,并且额外的增加SpringProxy、Advised、DecoratingProxy三个接口,组合成一个Class\[\],并赋值给proxiedInterfaces属性
  2. 并且检查这些接口中是否定义了equals()、hashcode()方法
  3. 执行Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this),得到代理对象,JdkDynamicAopProxy作为InvocationHandler,代理对象在执行某个方法时,会进入到JdkDynamicAopProxy的**invoke()**方法中

2、ObjenesisCglibAopProxy

  1. 创建Enhancer对象
  2. 设置Enhancer的superClass为通过ProxyFactory.setTarget()所设置的对象的类
  3. 设置Enhancer的interfaces为通过ProxyFactory.addInterface()所添加的接口,以及SpringProxy、Advised、DecoratingProxy接口
  4. 设置Enhancer的Callbacks为DynamicAdvisedInterceptor
  5. 最后创建一个代理对象,代理对象在执行某个方法时,会进入到DynamicAdvisedInterceptor的intercept()方法中

五、代理对象执行过程

  1. 在使用ProxyFactory创建代理对象之前,需要往ProxyFactory先添加Advisor
  2. 代理对象在执行某个方法时,会把ProxyFactory中的Advisor拿出来和当前正在执行的方法进行匹配筛选
  3. 把和方法所匹配的Advisor适配成MethodInterceptor
  4. 把和当前方法匹配的MethodInterceptor链,以及被代理对象、代理对象、代理类、当前Method对象、方法参数封装为MethodInvocation对象
  5. 调用MethodInvocation的proceed()方法,开始执行各个MethodInterceptor以及被代理对象的对应方法
  6. 按顺序调用每个MethodInterceptor的invoke()方法,并且会把MethodInvocation对象传入invoke()方法
  7. 直到执行完最后一个MethodInterceptor了,就会调用invokeJoinpoint()方法,从而执行被代理对象的当前方法

各注解对应的MethodInterceptor

  • @Before 对应的是AspectJMethodBeforeAdvice,在进行动态代理时会把AspectJMethodBeforeAdvice转成MethodBeforeAdviceInterceptor
    • 先执行advice对应的方法
    • 再执行MethodInvocation的proceed(),会执行下一个Interceptor,如果没有下一个Interceptor了,会执行target对应的方法
  • @After 对应的是AspectJAfterAdvice,直接实现了MethodInterceptor
    • 先执行MethodInvocation的proceed(),会执行下一个Interceptor,如果没有下一个Interceptor了,会执行target对应的方法
    • 再执行advice对应的方法
  • @Around 对应的是AspectJAroundAdvice,直接实现了MethodInterceptor
    • 直接执行advice对应的方法,由@Around自己决定要不要继续往后面调用
  • @AfterThrowing 对应的是AspectJAfterThrowingAdvice,直接实现了MethodInterceptor
    • 先执行MethodInvocation的proceed(),会执行下一个Interceptor,如果没有下一个Interceptor了,会执行target对应的方法
    • 如果上面抛了Throwable,那么则会执行advice对应的方法
  • @AfterReturning 对应的是AspectJAfterReturningAdvice,在进行动态代理时会把AspectJAfterReturningAdvice转成AfterReturningAdviceInterceptor
    • 先执行MethodInvocation的proceed(),会执行下一个Interceptor,如果没有下一个Interceptor了,会执行target对应的方法
    • 执行上面的方法后得到最终的方法的返回值
    • 再执行Advice对应的方法

六、AbstractAdvisorAutoProxyCreator

DefaultAdvisorAutoProxyCreator的父类是AbstractAdvisorAutoProxyCreator。

AbstractAdvisorAutoProxyCreator 非常强大以及重要,只要Spring容器中存在这个类型的Bean,就相当于开启了AOP,AbstractAdvisorAutoProxyCreator实际上就是一个BeanPostProcessor,所以在创建某个Bean时,就会进入到它对应的生命周期方法中,比如:在某个Bean初始化之后,会调用wrapIfNecessary()方法进行AOP,底层逻辑是,AbstractAdvisorAutoProxyCreator会找到所有的Advisor,然后判断当前这个Bean是否存在某个Advisor与之匹配(根据Pointcut),如果匹配就表示当前这个Bean有对应的切面逻辑,需要进行AOP,需要产生一个代理对象。

七、@EnableAspectJAutoProxy

这个注解主要就是往Spring容器中添加了一个AnnotationAwareAspectJAutoProxyCreator类型的Bean。

AspectJAwareAdvisorAutoProxyCreator 继承了AbstractAdvisorAutoProxyCreator ,重写了findCandidateAdvisors()方法,AbstractAdvisorAutoProxyCreator 只能找到所有Advisor类型的Bean对象,但是AspectJAwareAdvisorAutoProxyCreator 除开可以找到所有Advisor类型的Bean对象,还能把@Aspect注解所标注的Bean中的@Before等注解及方法进行解析,并生成对应的Advisor对象。

所以,我们可以理解@EnableAspectJAutoProxy,其实就是像Spring容器中添加了一个AbstractAdvisorAutoProxyCreator类型的Bean,从而开启了AOP,并且还会解析@Before等注解生成Advisor。

相关推荐
isyangli_blog4 小时前
OpenDayLight (Carbon 版本) 启动与组件安装
开发语言·php
vb2008114 小时前
FastAPI APIRouter
开发语言·python
Benszen4 小时前
KVM虚拟化解决方案
开发语言·perl
会编程的土豆4 小时前
Go 语言反射(Reflection)详解
开发语言·后端·golang
東雪木4 小时前
多线程与并发编程 专属复习笔记
java·开发语言·笔记·java面试
杨充4 小时前
1.3 浮点型数据设计灵魂
开发语言·python·算法
噜噜噜阿鲁~4 小时前
python学习笔记 | 11.3、面向对象高级编程-多重继承
java·开发语言
basketball6165 小时前
Go 语言从入门到进阶:4. 数组和MAP使用方法总结
开发语言·后端·golang
春生野草5 小时前
反射、Tomcat执行
java·开发语言
雪的季节6 小时前
企业级 Qt 全功能项目
开发语言·数据库·qt