你自我介绍说很懂Spring配置类,那你怎么解释这个现象?(下)

简介: 你自我介绍说很懂Spring配置类,那你怎么解释这个现象?(下)

本方法我们需要关注对Enhancer实例的配置,有如下关注点:


  • 通过它增强的每个类都实现了EnhancedConfiguration接口,并且它还是BeanFactoryAware的子接口
  • 统一实现接口,这和Spring AOP创建代理是不是如出一辙?想一想
  • 实现了BeanFactoryAware接口,这样Spring在创建代理类实例的时候会给注入BeanFactory
  • 使用SpringNamingPolicy策略来生成类名称。这就是解释了为何代理类的名你都能看到BySpringCGLIB字样
  • 对于代理最为重要的当属过滤器/拦截器org.springframework.cglib.proxy.Callback,它们是实现功能的核心。配置此增强器时设置了CALLBACK_FILTER共三个拦截器


关于CALLBACK_FILTER,我们发现在类ConfigurationClassEnhancer最开始处就申明了三个拦截器放进去了:


ConfigurationClassEnhancer:
  private static final Callback[] CALLBACKS = new Callback[] {
      new BeanMethodInterceptor(),
      new BeanFactoryAwareMethodInterceptor(),
      NoOp.INSTANCE
  };


如果说前面都是做准备工作,那么拦截器才是运行期真正干活的“人”了。它能够解答我们今天的疑问~


拦截器分析


什么是动态代理?用通俗的话理解就是:代理的核心逻辑就是依赖于拦截器实现的,可见拦截器(也叫增强)之于代理类是何等重要。


上面的三个拦截器中,NoOp.INSTANCE代表什么都没做,因此我们只需要关注前两个。他俩均是MethodInterceptor接口的实现类,均实现了intercept()方法来做具体的拦截操作(他俩均是私有静态内部类哟)。


说明:本文的两个case用第一个拦截器即可解释,鉴于第二个拦截器非常的复杂,所以我把它放在下篇文章详解(已写得差不多了,因为太复杂,篇幅比本文还长)

BeanFactoryAwareMethodInterceptor


顾名思义,它表示的是BeanFactoryAware方法的拦截器,所以靠猜应该能猜到它拦截的是setBeanFactory(beanFactory)方法。


说明:Spring所有的拦截器实现的拦截都是方法级别的。虽然也支持构造器的拦截,但并没有内置实现,需要使用者自行扩展(比较复杂,一般并无使用场景)


相较于下文要讲的第二个拦截器,这个拦截器比较简单。但是它实现的功能可不简约哦,因为它能够解释文首提出的两个case,让你谈薪更有底气。


既然是拦截器,就应该按如下两步去了解它:执行时机 + 做了何事。


执行时机


执行时机决定了增强逻辑何时执行,毕竟一般来说都不可能是增强所有的嘛。


BeanFactoryAwareMethodInterceptor:
    // 当执行到setBeanFactory(xxx)方法时匹配成功
    @Override
    public boolean isMatch(Method candidateMethod) {
      return isSetBeanFactory(candidateMethod);
    }
    // 此方法标记为public static 是因为下面这个拦截器也会用到
    public static boolean isSetBeanFactory(Method candidateMethod) {
      return (candidateMethod.getName().equals("setBeanFactory") &&
          candidateMethod.getParameterCount() == 1 &&
          BeanFactory.class == candidateMethod.getParameterTypes()[0] &&
          BeanFactoryAware.class.isAssignableFrom(candidateMethod.getDeclaringClass()));
    }



我们知道setBeanFactory()方法是由Spring容器在初始化Bean时回调调用的,而代理类实现了EnhancedConfiguration接口(间接实现了BeanFactoryAware接口),所以该拦截器的执行时机为:在Spring初始化代理类实例时执行拦截。


说明:isSetBeanFactory()判断方法做这么“复杂”主要是为了容错,“担心”你自己定义了一个名为setBeanFactory的方法而“搞错了”。


做了何事


作为一个拦截器,增强逻辑才是它的核心。


BeanFactoryAwareMethodInterceptor:
    @Override
    @Nullable
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
      // 找到本类(代理类)里名为`$$beanFactory`的字段
      // 若没找到直接报错。若找到了此字段,就给此字段赋值
      Field field = ReflectionUtils.findField(obj.getClass(), BEAN_FACTORY_FIELD);
      Assert.state(field != null, "Unable to find generated BeanFactory field");
      field.set(obj, args[0]);
      // 如果用户类(也就是你自己定义的类)自己实现了该接口,那么别担心,也会给你赋值上
      if (BeanFactoryAware.class.isAssignableFrom(ClassUtils.getUserClass(obj.getClass().getSuperclass()))) {
        return proxy.invokeSuper(obj, args);
      }
      return null;
    }


从执行时机知道了,它拦截的是setBeanFactory()方法的执行。所以这里的Method就代表的是setBeanFactory()方法,Object[] args的值是当前容器的BeanFactory工厂(注意理解这句话)实例。

此拦截器增强完成后,结果截图如下:


image.png


好了,介绍到这里本文就先告一段落。如果你是认真的看完了本文的分析,那么现在你再“回到顶部”理解那两个case的结果,你就豁然开朗了。


建议一定弄懂,我觉得已经很明朗了,所以就不再废话。若有不清楚,可以下方扫码加我微信私聊我吧(或者文末留言)


总结


又是一篇关于Spring配置类的长文,只希望对你有帮助才有意义。最为核心的两个增强/拦截器,迫于篇幅和读者的脑力(毕竟理解起来还是比较费劲的),今天只讲一个。我把另外一个更为重要、更为复杂、更为多金的部分放在了下文专文阐述,你可关注我公众号保持“收看”。

相关文章
|
5天前
|
存储 Java 数据安全/隐私保护
|
2天前
|
Java 开发者 Spring
Spring Boot中的资源文件属性配置
【4月更文挑战第28天】在Spring Boot应用程序中,配置文件是管理应用程序行为的重要组成部分。资源文件属性配置允许开发者在不重新编译代码的情况下,对应用程序进行灵活地配置和调整。本篇博客将介绍Spring Boot中资源文件属性配置的基本概念,并通过实际示例展示如何利用这一功能。
10 1
|
11天前
|
存储 安全 Java
第2章 Spring Security 的环境设置与基础配置(2024 最新版)(下)
第2章 Spring Security 的环境设置与基础配置(2024 最新版)(下)
18 0
|
11天前
|
安全 Java 数据库
第2章 Spring Security 的环境设置与基础配置(2024 最新版)(上)
第2章 Spring Security 的环境设置与基础配置(2024 最新版)
35 0
|
12天前
|
XML Java 数据库
在Spring框架中,XML配置事务
在Spring框架中,XML配置事务
|
12天前
|
Java Windows Spring
Spring Boot 3.x 全新的热部署配置方式(IntelliJ IDEA 2023.1)
Spring Boot 3.x 全新的热部署配置方式(IntelliJ IDEA 2023.1)
15 1
|
12天前
|
安全 Java Spring
Spring Security 5.7 最新配置细节(直接就能用),WebSecurityConfigurerAdapter 已废弃
Spring Security 5.7 最新配置细节(直接就能用),WebSecurityConfigurerAdapter 已废弃
30 0
|
XML 前端开发 Java
Spring 最常用的 7 大类注解,史上最强整理!
随着技术的更新迭代,Java5.0开始支持注解。而作为java中的领军框架spring,自从更新了2.5版本之后也开始慢慢舍弃xml配置,更多使用注解来控制spring框架。
|
2月前
|
Java 应用服务中间件 Maven
SpringBoot 项目瘦身指南
SpringBoot 项目瘦身指南
46 0
|
2月前
|
缓存 安全 Java
Spring Boot 面试题及答案整理,最新面试题
Spring Boot 面试题及答案整理,最新面试题
121 0