Spring框架系列(10) - Spring AOP实现原理详解之AOP代理的创建

引入

同时我们也总结了Spring AOP初始化的过程,具体如下:

  1. IOC Bean加载方法栈中找到parseCustomElement方法,找到parse aop:aspectj-autoproxy的handler(org.springframework.aop.config.AopNamespaceHandler)
  2. AopNamespaceHandler注册了<aop:aspectj-autoproxy/>的解析类是AspectJAutoProxyBeanDefinitionParser
  3. AspectJAutoProxyBeanDefinitionParser的parse 方法 通过AspectJAwareAdvisorAutoProxyCreator类去创建
  4. AspectJAwareAdvisorAutoProxyCreator实现了两类接口,BeanFactoryAware和BeanPostProcessor;根据Bean生命周期方法找到两个核心方法:postProcessBeforeInstantiation和postProcessAfterInitialization
    1. postProcessBeforeInstantiation:主要是处理使用了@Aspect注解的切面类,然后将切面类的所有切面方法根据使用的注解生成对应Advice,并将Advice连同切入点匹配器和切面类等信息一并封装到Advisor
    2. postProcessAfterInitialization:主要负责将Advisor注入到合适的位置,创建代理(cglib或jdk),为后面给代理进行增强实现做准备。

代理的创建

创建代理的方法是postProcessAfterInitialization:如果bean被子类标识为代理,则使用配置的拦截器创建一个代理

  1. /**
  2. * Create a proxy with the configured interceptors if the bean is
  3. * identified as one to proxy by the subclass.
  4. * @see #getAdvicesAndAdvisorsForBean
  5. */
  6. @Override
  7. public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
  8. if (bean != null) {
  9. Object cacheKey = getCacheKey(bean.getClass(), beanName);
  10. // 如果不是提前暴露的代理
  11. if (this.earlyProxyReferences.remove(cacheKey) != bean) {
  12. return wrapIfNecessary(bean, beanName, cacheKey);
  13. }
  14. }
  15. return bean;
  16. }

wrapIfNecessary方法主要用于判断是否需要创建代理,如果Bean能够获取到advisor才需要创建代理

  1. /**
  2. * Wrap the given bean if necessary, i.e. if it is eligible for being proxied.
  3. * @param bean the raw bean instance
  4. * @param beanName the name of the bean
  5. * @param cacheKey the cache key for metadata access
  6. * @return a proxy wrapping the bean, or the raw bean instance as-is
  7. */
  8. protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
  9. // 如果bean是通过TargetSource接口获取
  10. if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
  11. return bean;
  12. }
  13. // 如果bean是切面类
  14. if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
  15. return bean;
  16. }
  17. // 如果是aop基础类?是否跳过?
  18. if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
  19. this.advisedBeans.put(cacheKey, Boolean.FALSE);
  20. return bean;
  21. }
  22. // 重点:获取所有advisor,如果没有获取到,那说明不要进行增强,也就不需要代理了。
  23. Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
  24. if (specificInterceptors != DO_NOT_PROXY) {
  25. this.advisedBeans.put(cacheKey, Boolean.TRUE);
  26. // 重点:创建代理
  27. Object proxy = createProxy(
  28. bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
  29. this.proxyTypes.put(cacheKey, proxy.getClass());
  30. return proxy;
  31. }
  32. this.advisedBeans.put(cacheKey, Boolean.FALSE);
  33. return bean;
  34. }

获取所有的Advisor

我们看下获取所有advisor的方法getAdvicesAndAdvisorsForBean

  1. @Override
  2. @Nullable
  3. protected Object[] getAdvicesAndAdvisorsForBean(
  4. Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
  5. List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
  6. if (advisors.isEmpty()) {
  7. return DO_NOT_PROXY;
  8. }
  9. return advisors.toArray();
  10. }

通过findEligibleAdvisors方法获取advisor, 如果获取不到返回DO_NOT_PROXY(不需要创建代理),findEligibleAdvisors方法如下

  1. /**
  2. * Find all eligible Advisors for auto-proxying this class.
  3. * @param beanClass the clazz to find advisors for
  4. * @param beanName the name of the currently proxied bean
  5. * @return the empty List, not {@code null},
  6. * if there are no pointcuts or interceptors
  7. * @see #findCandidateAdvisors
  8. * @see #sortAdvisors
  9. * @see #extendAdvisors
  10. */
  11. protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
  12. // 和上文一样,获取所有切面类的切面方法生成Advisor
  13. List<Advisor> candidateAdvisors = findCandidateAdvisors();
  14. // 找到这些Advisor中能够应用于beanClass的Advisor
  15. List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
  16. // 如果需要,交给子类拓展
  17. extendAdvisors(eligibleAdvisors);
  18. // 对Advisor排序
  19. if (!eligibleAdvisors.isEmpty()) {
  20. eligibleAdvisors = sortAdvisors(eligibleAdvisors);
  21. }
  22. return eligibleAdvisors;
  23. }

获取所有切面类的切面方法生成Advisor

  1. /**
  2. * Find all candidate Advisors to use in auto-proxying.
  3. * @return the List of candidate Advisors
  4. */
  5. protected List<Advisor> findCandidateAdvisors() {
  6. Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
  7. return this.advisorRetrievalHelper.findAdvisorBeans();
  8. }

找到这些Advisor中能够应用于beanClass的Advisor

  1. /**
  2. * Determine the sublist of the {@code candidateAdvisors} list
  3. * that is applicable to the given class.
  4. * @param candidateAdvisors the Advisors to evaluate
  5. * @param clazz the target class
  6. * @return sublist of Advisors that can apply to an object of the given class
  7. * (may be the incoming List as-is)
  8. */
  9. public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
  10. if (candidateAdvisors.isEmpty()) {
  11. return candidateAdvisors;
  12. }
  13. List<Advisor> eligibleAdvisors = new ArrayList<>();
  14. for (Advisor candidate : candidateAdvisors) {
  15. // 通过Introduction实现的advice
  16. if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
  17. eligibleAdvisors.add(candidate);
  18. }
  19. }
  20. boolean hasIntroductions = !eligibleAdvisors.isEmpty();
  21. for (Advisor candidate : candidateAdvisors) {
  22. if (candidate instanceof IntroductionAdvisor) {
  23. // already processed
  24. continue;
  25. }
  26. // 是否能够应用于clazz的Advice
  27. if (canApply(candidate, clazz, hasIntroductions)) {
  28. eligibleAdvisors.add(candidate);
  29. }
  30. }
  31. return eligibleAdvisors;
  32. }

创建代理的入口方法

获取所有advisor后,如果有advisor,则说明需要增强,即需要创建代理,创建代理的方法如下:

  1. /**
  2. * Create an AOP proxy for the given bean.
  3. * @param beanClass the class of the bean
  4. * @param beanName the name of the bean
  5. * @param specificInterceptors the set of interceptors that is
  6. * specific to this bean (may be empty, but not null)
  7. * @param targetSource the TargetSource for the proxy,
  8. * already pre-configured to access the bean
  9. * @return the AOP proxy for the bean
  10. * @see #buildAdvisors
  11. */
  12. protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
  13. @Nullable Object[] specificInterceptors, TargetSource targetSource) {
  14. if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
  15. AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
  16. }
  17. ProxyFactory proxyFactory = new ProxyFactory();
  18. proxyFactory.copyFrom(this);
  19. if (proxyFactory.isProxyTargetClass()) {
  20. // Explicit handling of JDK proxy targets (for introduction advice scenarios)
  21. if (Proxy.isProxyClass(beanClass)) {
  22. // Must allow for introductions; cant just set interfaces to the proxys interfaces only.
  23. for (Class<?> ifc : beanClass.getInterfaces()) {
  24. proxyFactory.addInterface(ifc);
  25. }
  26. }
  27. }
  28. else {
  29. // No proxyTargetClass flag enforced, lets apply our default checks...
  30. if (shouldProxyTargetClass(beanClass, beanName)) {
  31. proxyFactory.setProxyTargetClass(true);
  32. }
  33. else {
  34. evaluateProxyInterfaces(beanClass, proxyFactory);
  35. }
  36. }
  37. Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
  38. proxyFactory.addAdvisors(advisors);
  39. proxyFactory.setTargetSource(targetSource);
  40. customizeProxyFactory(proxyFactory);
  41. proxyFactory.setFrozen(this.freezeProxy);
  42. if (advisorsPreFiltered()) {
  43. proxyFactory.setPreFiltered(true);
  44. }
  45. // Use original ClassLoader if bean class not locally loaded in overriding class loader
  46. ClassLoader classLoader = getProxyClassLoader();
  47. if (classLoader instanceof SmartClassLoader && classLoader != beanClass.getClassLoader()) {
  48. classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader();
  49. }
  50. return proxyFactory.getProxy(classLoader);
  51. }

proxyFactory.getProxy(classLoader)

  1. /**
  2. * Create a new proxy according to the settings in this factory.
  3. * <p>Can be called repeatedly. Effect will vary if weve added
  4. * or removed interfaces. Can add and remove interceptors.
  5. * <p>Uses the given class loader (if necessary for proxy creation).
  6. * @param classLoader the class loader to create the proxy with
  7. * (or {@code null} for the low-level proxy facilitys default)
  8. * @return the proxy object
  9. */
  10. public Object getProxy(@Nullable ClassLoader classLoader) {
  11. return createAopProxy().getProxy(classLoader);
  12. }

依据条件创建代理(jdk或cglib)

DefaultAopProxyFactory.createAopProxy

  1. @Override
  2. public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
  3. if (!NativeDetector.inNativeImage() &&
  4. (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))) {
  5. Class<?> targetClass = config.getTargetClass();
  6. if (targetClass == null) {
  7. throw new AopConfigException("TargetSource cannot determine target class: " +
  8. "Either an interface or a target is required for proxy creation.");
  9. }
  10. if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
  11. return new JdkDynamicAopProxy(config);
  12. }
  13. return new ObjenesisCglibAopProxy(config);
  14. }
  15. else {
  16. return new JdkDynamicAopProxy(config);
  17. }
  18. }

几个要点

  • config.isOptimize() 是通过optimize设置,表示配置是自定义的,默认是false;
  • config.isProxyTargetClass()是通过<aop:config proxy-target-class="true" />来配置的,表示优先使用cglib代理,默认是false;
  • hasNoUserSuppliedProxyInterfaces(config) 表示是否目标类实现了接口

由此我们可以知道:

Spring默认在目标类实现接口时是通过JDK代理实现的,只有非接口的是通过Cglib代理实现的。当设置proxy-target-class为true时在目标类不是接口或者代理类时优先使用cglib代理实现。

更多文章

  • Spring基础 - Spring和Spring框架组成
    • Spring是什么?它是怎么诞生的?有哪些主要的组件和核心功能呢? 本文通过这几个问题帮助你构筑Spring和Spring Framework的整体认知。
  • Spring基础 - SpringMVC请求流程和案例
    • 前文我们介绍了Spring框架和Spring框架中最为重要的两个技术点(IOC和AOP),那我们如何更好的构建上层的应用呢(比如web 应用),这便是SpringMVC;Spring MVC是Spring在Spring Container Core和AOP等技术基础上,遵循上述Web MVC的规范推出的web开发框架,目的是为了简化Java栈的web开发。 本文主要介绍SpringMVC的请求流程和基础案例的编写和运行。
  • Spring进阶 - Spring IOC实现原理详解之IOC体系结构设计
    • 在对IoC有了初步的认知后,我们开始对IOC的实现原理进行深入理解。本文将帮助你站在设计者的角度去看IOC最顶层的结构设计
  • Spring进阶 - Spring IOC实现原理详解之IOC初始化流程
    • 上文,我们看了IOC设计要点和设计结构;紧接着这篇,我们可以看下源码的实现了:Spring如何实现将资源配置(以xml配置为例)通过加载,解析,生成BeanDefination并注册到IoC容器中的
  • Spring进阶 - Spring IOC实现原理详解之Bean实例化(生命周期,循环依赖等)
    • 上文,我们看了IOC设计要点和设计结构;以及Spring如何实现将资源配置(以xml配置为例)通过加载,解析,生成BeanDefination并注册到IoC容器中的;容器中存放的是Bean的定义即BeanDefinition放到beanDefinitionMap中,本质上是一个ConcurrentHashMap<String, Object>;并且BeanDefinition接口中包含了这个类的Class信息以及是否是单例等。那么如何从BeanDefinition中实例化Bean对象呢,这是本文主要研究的内容?
  • Spring进阶 - Spring AOP实现原理详解之切面实现
    • 前文,我们分析了Spring IOC的初始化过程和Bean的生命周期等,而Spring AOP也是基于IOC的Bean加载来实现的。本文主要介绍Spring AOP原理解析的切面实现过程(将切面类的所有切面方法根据使用的注解生成对应Advice,并将Advice连同切入点匹配器和切面类等信息一并封装到Advisor,为后续交给代理增强实现做准备的过程)。
  • Spring进阶 - Spring AOP实现原理详解之AOP代理
    • 上文我们介绍了Spring AOP原理解析的切面实现过程(将切面类的所有切面方法根据使用的注解生成对应Advice,并将Advice连同切入点匹配器和切面类等信息一并封装到Advisor)。本文在此基础上继续介绍,代理(cglib代理和JDK代理)的实现过程。
  • Spring进阶 - Spring AOP实现原理详解之Cglib代理实现
    • 我们在前文中已经介绍了SpringAOP的切面实现和创建动态代理的过程,那么动态代理是如何工作的呢?本文主要介绍Cglib动态代理的案例和SpringAOP实现的原理。
  • Spring进阶 - Spring AOP实现原理详解之JDK代理实现
    • 上文我们学习了SpringAOP Cglib动态代理的实现,本文主要是SpringAOP JDK动态代理的案例和实现部分。
  • Spring进阶 - SpringMVC实现原理之DispatcherServlet初始化的过程
    • 前文我们有了IOC的源码基础以及SpringMVC的基础,我们便可以进一步深入理解SpringMVC主要实现原理,包含DispatcherServlet的初始化过程和DispatcherServlet处理请求的过程的源码解析。本文是第一篇:DispatcherServlet的初始化过程的源码解析。
  • Spring进阶 - SpringMVC实现原理之DispatcherServlet处理请求的过程
    • 前文我们有了IOC的源码基础以及SpringMVC的基础,我们便可以进一步深入理解SpringMVC主要实现原理,包含DispatcherServlet的初始化过程和DispatcherServlet处理请求的过程的源码解析。本文是第二篇:DispatcherServlet处理请求的过程的源码解析。

文章标签:

原文连接:https://juejin.cn/post/7115172628251459614

相关推荐

浅谈spring-createBean

Hippo4J v1.3.1 发布,增加 Netty 监控上报、SpringCloud Hystrix 线程池监控等特性

SpringBoot集成文件 - 集成POI之Excel导入导出

Spring基础入门

SpringWeb 拦截器

这样优化Spring Boot,启动速度快到飞起!

Java开发学习(十四)----Spring整合Mybatis及Junit

SpringCloud OpenFeign 自定义响应解码器

SpringCloud 微服务接口调用组件 - OpenFeign 简介

SpringBoot到底是什么?

【Spring】IOC与解耦合

SpringBoot数据库管理 - 用flyway对数据库管理和迁移

Spring源码(十六)-ConfigurationClassPostProcessor

2022 年最新 Java 后端薪资统计出炉,看看你有没有拖后腿

SpringBoot数据库管理 - 用Liquibase对数据库管理和迁移?

【Spring源码解析】Spring XML方式获取bean源码初步解析

SpringMVC底层——请求参数处理流程描述

Spring 通过注解来存储和读取对象

SpringBoot接口 - API接口有哪些不安全的因素?如何对接口进行签名?

SpringDataJpa的使用 -- 一对一、一对多、多对多 关系映射