Spring Aware源码设计示例解析

目录
  • 1. Aware介绍
  • 2. Aware类别
    • 2.1 BeanClassLoaderAware
    • 2.2 BeanFactoryAware
    • 2.3 BeanNameAware
    • 2.4 ApplicationContextAware
  • 3. Aware的使用
  • 4. Aware的作用
  • 5. Aware的调用

1. Aware介绍

前一篇讲到了BeanPostProcessor的相关知识,我们知道BeanPostProcessor是对整个容器中的Bean做前置和后置增强处理。这样的实现方式限制了开发者只能按照Spring提供的模板,对Bean做前置和后置的增强,这样虽然已经很灵活了,但是如果开发者想要对Spring中的Bean做更复杂的操作或者开发者想要使用Spring中的BeanFactory、ClassLoader时,这样的方式明显就不够方便了,因此Spring也考虑到了这样的情况,就提供了另外的方式提升Spring的扩展性和灵活性,这种方式就是Aware。

单纯说Aware可能不熟悉,但是如果说BeanNameAware、BeanFactoryAware那么是不是就知道这个Aware到底是何方神圣了。

接下来就说一下Spring提供给开发者Aware的这个功能。

Spring中Aware的源码如下:

public interface Aware {
}

从源码中可以看到Aware就是一个简单的接口,该接口是一个无实现的接口,一般看到这种接口可以都是作为最顶级的父类接口使用的,使用时一般都是instanceof判断是否是顶级接口类型。

2. Aware类别

在Spring中Aware有几个继承接口,分别是:

  • BeanClassLoaderAware
  • BeanFactoryAware
  • BeanNameAware

2.1 BeanClassLoaderAware

首先是BeanClassLoaderAware接口,从字面意思翻译就可以大概知道这是一个关于Bean的类加载器的接口,因此该接口的功能就聚焦在类加载器上。

BeanClassLoaderAware源码如下:

public interface BeanClassLoaderAware extends Aware {
	//set方法,赋值ClassLoader方法
	void setBeanClassLoader(ClassLoader classLoader);
}

从源码可以看到该接口只提供了一个setBeanClassLoader方法,该方法就是简单的设置Bean的类加载器的方法,所以从这个方法中就可以知道BeanClassLoaderAware就单纯提供了一个赋值ClassLoader的方法,这里的接口并不会指定ClassLoader的接收方,因此接收方需要在实现该接口的实现类中指定,然后将ClassLoader赋值给实现类中的具体常量。

2.2 BeanFactoryAware

BeanFactoryAware接口,看到这个就立马想到Spring中的BeanFactory,BeanFactory在Spring中是作为Bean的工厂,那么该接口一定是与BeanFactory相关的接口。

BeanFactoryAware源码如下:

public interface BeanFactoryAware extends Aware {
    void setBeanFactory(BeanFactory beanFactory) throws BeansException;
}

从源码中可以看到BeanFactoryAware跟BeanClassLoaderAware相似都只提供了一个set方法,该接口中只定义了setBeanFactory一个方法。

该接口中的方法 功能跟BeanClassLoaderAware功能相同,都是赋值,但是该接口赋值的是BeanFactory。

2.3 BeanNameAware

源码如下:

public interface BeanNameAware extends Aware {
    void setBeanName(String name);
}

该接口功能同上。(说实话实际开发中没用到过这个,只用过前两个,所以我也没搞懂该类到底可以干啥)。

2.4 ApplicationContextAware

该接口则是一个特别的接口了,因为该接口跟前三个继承Aware的接口不同,ApplicationContextAware并不是spring-bean中提供的接口,而是在spring-context中提供的接口,该接口是从spring-context包中提供的接口,该接口的作用也是跟前三个类似,并且大部分开发者用的最多的也是这个。

源码如下:

public interface ApplicationContextAware extends Aware {
    void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
    @Nullable
    String getId();
    String getApplicationName();
    String getDisplayName();
    long getStartupDate();
    @Nullable
    ApplicationContext getParent();
    AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;
}

源码中也是简单的赋值操作,但是赋值的对象是ApplicationContext对象,对于这个对象使用Spring的一定不陌生。

可以这样说:ApplicationContext给了开发者最多的权限用于操作Bean。

从ApplicationContext源码中也可以看到该接口继承了ListableBeanFactory、HierarchicalBeanFactory、ApplicationEventPublisher等其它接口,这样就将更多的Bean的权限通过ApplicationContext下放给开发者!(又是被Spring的高灵活性折服的时刻)。

3. Aware的使用

@Component
public class MySpringAware implements BeanFactoryAware, BeanClassLoaderAware, ApplicationContextAware, BeanNameAware {
    private ApplicationContext applicationContext;
    private ListableBeanFactory beanFactory;
    private ClassLoader classLoader;
    private String beanName;
    /**
     * 获取某个接口下的所有实现类
     *
     * @param filter
     */
    public void registryFilter(FilterProcessor filter) {
        Map<String, MyFilter> beans = beanFactory.getBeansOfType(MyFilter.class);
        beans.values().stream().sorted(AnnotationAwareOrderComparator.INSTANCE).forEach(filter::register);
    }
        /**
     * 获取环境配置
     *
     * @return
     */
    public Environment getApplicationData() {
        return applicationContext.getEnvironment();
    }
    public ApplicationContext getApplicationContext() {
        return applicationContext;
    }
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        this.classLoader = classLoader;
    }
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = (ListableBeanFactory) beanFactory;
    }
    @Override
    public void setBeanName(String s) {
        this.beanName = s;
    }
}
@Component
public class FilterProcessor {
    private final List<MyFilter> filterList = new ArrayList();
    public void register(MyFilter filter) {
        this.filterList.add(filter);
    }
    public List<MyFilter> getFilterList() {
        return filterList;
    }
}
public interface MyFilter {
    void doFilter();
}
@Component
@Order(1)
public class MyDemoFilter extends FilterProcessor implements MyFilter{
    @Override
    public void doFilter() {
        System.out.println("执行第一个过滤器MyDemoFilter");
    }
}
@Component
@Order(2)
public class MyDemoFilter2 extends FilterProcessor implements MyFilter{
    @Override
    public void doFilter() {
        System.out.println("执行第二个过滤器MyDemoFilter2");
    }
}

运行结果:

以上的例子中通过MySpringAware实现了前文中说到的几个Aware,分别使用了其中的BeanFactory和ApplicationContext。这样在MySpringAware中就可以使用我们定义的常量接收Spring容器中的BeanFactory、ClassLoader、ApplicationContext等功能。

4. Aware的作用

从以上的例子中可以看到,Aware为开发者提供了插桩式的接口,开发者只要实现该接口就可以获得Spring容器的某些管理权。

比如BeanClassLoaderAware是获得对Bean的类加载器的管理权。

BeanFactoryAware是活的对Bean工厂的管理权。

这样插桩式的扩展可以保证开发者在使用时可以获得Spring中某些功能的管理权,方便开发者对Spring的理解和使用,不需要复杂的实现就可以获得Spring内部的管理。

5. Aware的调用

前面说完了Aware的介绍、类别和作用,最后来说实现Aware相关接口的实现类在Spring中是如何被调用的。

实现Aware相关接口的实现类被调用的方式与前面讲的BeanPostProcessor有一定区别。

区别如下:

BeanPostProcessor的调用:

  • 调用方式:注册+读取注册列表(通过register.List和遍历beanPostProcessorList)
  • 调用时机:Bean执行初始化函数(invokeInitMethods)之前或者之后

Aware的调用:

  • 调用方式:通过Bean是否实现了Aware/BeanClassLoaderAware/BeanFactoryAware,然后调用相应的实现类的重写方法
  • 调用时机:Bean执行初始化函数(invokeInitMethods)之前且beanPostProcessor#before之前

源码如下:

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
		implements AutowireCapableBeanFactory {
    //初始化Bean的方法
	protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
		if (System.getSecurityManager() != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                //调用Bean的Aware重写接口
				invokeAwareMethods(beanName, bean);
				return null;
			}, getAccessControlContext());
		}
		else {
            //调用Bean的Aware重写接口
			invokeAwareMethods(beanName, bean);
		}
		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
            //调用BeanPostProcessor前置接口
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}
		try {
            //调用Bean的初始化函数
			invokeInitMethods(beanName, wrappedBean, mbd);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					(mbd != null ? mbd.getResourceDescription() : null),
					beanName, "Invocation of init method failed", ex);
		}
		if (mbd == null || !mbd.isSynthetic()) {
            //调用BeanPostProcessor后置接口
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}
		return wrappedBean;
	}
	//调用Aware的实现
    private void invokeAwareMethods(String beanName, Object bean) {
        if (bean instanceof Aware) {
            if (bean instanceof BeanNameAware) {
                ((BeanNameAware) bean).setBeanName(beanName);
            }
            if (bean instanceof BeanClassLoaderAware) {
                ClassLoader bcl = getBeanClassLoader();
                if (bcl != null) {
                    ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
                }
            }
            if (bean instanceof BeanFactoryAware) {
                ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
            }
        }
    }
}

区别梳理如下:

以AbstractAutowireCapableBeanFactory为主线梳理调用Aware接口的链路如下:

  • org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
  • org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean
  • org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
  • org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean
  • org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#invokeAwareMethods

对于ApplicationContextAware的调用链路梳理如下:

  • org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean
  • org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization
  • org.springframework.context.support.ApplicationContextAwareProcessor#postProcessBeforeInitialization
  • org.springframework.context.support.ApplicationContextAwareProcessor#invokeAwareInterfaces

根据以上的链路可以很清晰的看到ApplicationContextAware的调用实现。

以上就是Spring Aware源码设计示例解析的详细内容,更多关于Spring Aware源码设计的资料请关注我们其它相关文章!

(0)

相关推荐

  • Spring Aware标记接口使用案例解析

    Aware接口是一个标记接口 XXXAare在Spring中表示对XXX可以感知,通俗点解释就是:如果在某个类里面想要使用Spring的一些东西,就可以通过实现XXXAware接口告诉Spring,Spring看到后就会送过来,而接受的方式是通过实现接口唯一的方法setXXX.比如ApplicationContextAware ApplicationContextAware使用 编写SpringAware实现ApplicationContext接口 package com.rookie.bigd

  • 详解spring中的Aware接口功能

    目录 一,ApplicationContextAware 二.ApplicationEventPublisherAware 在spring中有很多以XXXAware命名的接口,很多人也不清楚这些接口都是做什么用的,这篇文章将描述常用的一些接口. 一,ApplicationContextAware 获取spring容器,用来访问容器中定义的其他bean.实现接口方法public void setApplicationContext(ApplicationContext applicationCon

  • Spring实战之ResourceLoaderAware加载资源用法示例

    本文实例讲述了Spring实战之ResourceLoaderAware加载资源用法.分享给大家供大家参考,具体如下: 一 配置文件 <?xml version="1.0" encoding="GBK"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/be

  • Spring的Aware接口你知道多少

    若 Spring 检测到 bean 实现了 Aware 接口,则会为其注入相应的依赖.所以通过让bean 实现 Aware 接口,则能在 bean 中获得相应的 Spring 容器资源. Spring 中提供的 Aware 接口有: BeanNameAware:注入当前 bean 对应 beanName BeanClassLoaderAware:注入加载当前 bean 的 ClassLoader BeanFactoryAware:注入 当前BeanFactory容器 的引用 BeanNameAw

  • Spring的Aware接口实现及执行顺序详解

    目录 一.实现了Aware的接口 二.为什么要使用 Aware 接口 三.Aware接口执行顺序 一.实现了Aware的接口 Spring中有很多继承于aware中的接口,这些接口到底是做什么用到的,下面我们就一起来看看吧. Aware 接口用于注入一些与容器相关信息,例如: EnvironmentAware:实现EnvironmentAware接口重写setEnvironment方法后,可以获得配置文件属性值 BeanClassLoaderAware:注入加载当前 bean 的 ClassLo

  • Spring Aware源码设计示例解析

    目录 1. Aware介绍 2. Aware类别 2.1 BeanClassLoaderAware 2.2 BeanFactoryAware 2.3 BeanNameAware 2.4 ApplicationContextAware 3. Aware的使用 4. Aware的作用 5. Aware的调用 1. Aware介绍 前一篇讲到了BeanPostProcessor的相关知识,我们知道BeanPostProcessor是对整个容器中的Bean做前置和后置增强处理.这样的实现方式限制了开发者

  • Spring Security源码解析之权限访问控制是如何做到的

    〇.前文回顾 在实战篇<话说Spring Security权限管理(源码详解)>我们学习了Spring Security强大的访问控制能力,只需要进行寥寥几行的配置就能做到权限的控制,本篇来看看它到底是如何做到的. 一.再聊过滤器链 源码篇中反复提到,请求进来需要经过的是一堆过滤器形成的过滤器链,走完过滤器链未抛出异常则可以继续访问后台接口资源,而最后一个过滤器就是来判断请求是否有权限继续访问后台资源,如果没有则会将拒绝访问的异常往上向异常过滤器抛,异常过滤器会对异常进行翻译,然后响应给客户端

  • Spring cache源码深度解析

    Spring cache是一个缓存API层,封装了对多种缓存的通用操作,可以借助注解方便地为程序添加缓存功能.常见的注解有@Cacheable.@CachePut.@CacheEvict,有没有想过背后的原理是什么?楼主带着疑问,阅读完Spring cache的源码后,做一个简要总结.先说结论,核心逻辑在CacheAspectSupport类,封装了所有的缓存操作的主体逻辑,下面详细介绍. 题外话:如何阅读开源代码? 有2种方法,可以结合起来使用: 静态代码阅读:查找关键类.方法的usage之处

  • Spring cache源码深度解析

    目录 前言 题外话:如何阅读开源代码? 核心类图 源码分析(带注释解释) 1.解析注解 2.逻辑执行 总结 前言 Spring cache是一个缓存API层,封装了对多种缓存的通用操作,可以借助注解方便地为程序添加缓存功能. 常见的注解有@Cacheable.@CachePut.@CacheEvict,有没有想过背后的原理是什么?楼主带着疑问,阅读完Spring cache的源码后,做一个简要总结. 先说结论,核心逻辑在CacheAspectSupport类,封装了所有的缓存操作的主体逻辑,下面

  • Redis源码设计剖析之事件处理示例详解

    目录 1. Redis事件介绍 2. 事件的抽象 2.1 文件事件结构 2.2 时间事件结构 2.3 事件状态结构 3. 事件的实现 1. Redis事件介绍 Redis服务器是一个事件驱动程序,所谓事件驱动就是输入一条命令并且按下回车,然后消息被组装成Redis协议的格式发送给Redis服务器,这个时候就会产生一个事件,Redis服务器会接收改命令,处理该命令和发送回复,而当我们没有与服务器进行交互时,服务器就会处于阻塞等待状态,它会让出CPU然后进入睡眠状态,当事件触发时,就会被操作系统唤醒

  • Spring IOC源码之bean的注册过程讲解

    目录 BeanDefition加载注册过程 进入obtainFreshBeanFactory方法 ​进入AbstractRefreshableApplicationContext类中的refreshBeanFactory方法 进入AbstractXmlApplicationContext类的loadBeanDefinitions方法 进入doLoadBeanDefinitions方法 Spring IoC--Bean的创建和初始化 Spring介绍 IoC介绍 IoC是什么 IoC能做什么 源码

  • Spring AOP源码深入分析

    目录 1. 前言 2. 术语 3. 示例 4. @EnableAspectJAutoProxy 5. AbstractAutoProxyCreator 6. 构建Advisor 7. 创建代理对象 8. DynamicAdvisedInterceptor 9. CglibMethodInvocation 10. Advice子类 1. 前言 Spring除了IOC和DI,还有另一个杀手锏功能——Spring AOP.AOP是一种面向切面的编程思想,它的关注点是横向的,不同于OOP的纵向.面向对象

  • Spring IOC源码剖析_如何整体认知Spring体系结构

    目录 如何整体认知Spring体系结构 一.来自官网的Spring 二.Spring的优缺点 三.一张图理解Spring Framework 4.x 四.详解"七层"宝塔 1. 核心容器(Core Container) 2. 数据访问/集成(Data Access/Integration)层 3. Web层 4. AOP(Aspect Oriented Programming)模块 5. 植入(Instrumentation)模块 6. 消息传输(Messaging) 7. 测试(Te

  • Spring Aop 源码增强获取分享

    目录 1 前言 2 spring 增强器 3 总结 1 前言 在前文中,已经讲述了 AOP的后置处理器使用和方法,在本文中继续分享增强信息相关的源码,这里才是 AOP 的核心代码. 2 spring 增强器 之前已经讲述了 spring AbstractApplicationContext.refresh 方法,在以下方法中都会处理会处理 BeanPostProcessor 接口. invokeBeanFactoryPostProcessors registerBeanPostProcessor

  • 使用Vue3+ts 开发ProTable源码教程示例

    目录 前台实现 实现效果 技术栈 使用方法 ProTable 设计思路 编码风格 css 小知识 表格操作 小结 后期功能扩展 后台实现 数据库 mysql 新建项目 RESTful 风格的 URL 定义 Sequelize controller model router.js API 文档 Apifox ts用到的一些 前台实现 实现效果 技术栈 vue3 + typescript + element-plus 使用方法 <template> <el-tabs type="b

随机推荐