做网站买流量网站线框图
news/
2025/9/23 22:23:59/
文章来源:
做网站买流量,网站线框图,苏州智信建设职业培训网站,wordpress的根目录前言众所周知#xff0c; 现在的 Spring 框架已经成为构建企业级 Java 应用事实上的标准了#xff0c;众多的企业项目都构建在 Spring 项目及其子项目之上#xff0c;特别是 Java Web 项目。Spring 的两个核心概念是 IoC(控制反转)和 AOP(面向切面编程)。想了解 Spring 的工…前言众所周知 现在的 Spring 框架已经成为构建企业级 Java 应用事实上的标准了众多的企业项目都构建在 Spring 项目及其子项目之上特别是 Java Web 项目。Spring 的两个核心概念是 IoC(控制反转)和 AOP(面向切面编程)。想了解 Spring 的工作原理毫无疑问首先要从这两个概念的 Spring 实现入手。但是 Spring 源码浩如烟海里面掺杂了太多的实现细节入门可谓极其困难。当我正苦于难以入门时好友介绍了 tiny-spring 这个开源项目这个项目用了不到千行的代码就将 Spring 的 IoC、AOP 的核心流程实现完毕真是居家旅行、吹逼面试之必备呀废话少说我们开始吧目录结构在 github 上 clone 下项目来之后我们关注 src 文件夹其余的是一些爱好者提的注释 PR恰巧被作者 merge 了不必理会。目录结构是这样的1.aop包顾名思义实现了 Spring 的 AOP 功能可以通过 bean 的自动 AOP 切入文件稍多暂时先不展开。 2.bean.factory包通过BeanFactory、AbstractBeanFactory、AutowireCapableBeanFactory三个类实现了BeanFactory的核心功能详情稍后讲解。 3.bean.io包定义了资源加载相关的抽象概念这里的资源包括 xml 配置文件等。 4.bean.xml包中只包含一个类XmlBeanDefinitionReader主要负责在 xml 配置文件中读取 bean 定义。 5.bean包其他类定义了 BeanDefinition 等核心概念详情后讲。 6.context包定义了ApplicationContext的核心概念。 7.BeanReference指的是引用类型的 Bean而不是实体类。IOC–浮沙筑台之根基IOC(控制翻转)是一种编程范式可以在一定程度上解决复杂系统对象耦合度太高的问题并不是 Spring 的专利。IOC 最常见的方式是 DI(依赖注入)可以通过一个容器将 Bean 维护起来方便在其他地方直接使用而不是重新 new。可以说IOC 是 Spring 最基本的概念没有 IOC 就没有 Spring。为什么 DI 可以起到解耦的作用一个软件系统包含了大量的对象每个对象之间都有依赖关系在普通的软件编写过程中对象的定义分布在各个文件之中对象之间的依赖只能通过类的构造器传参方法传参的形式来完成。当工程变大之后复杂的逻辑会让对象之间的依赖梳理变得异常困难。在 Spring IOC 中一般情况我们可以在 XML 文件之中统一的编写 bean 的定义bean 与 bean 之间的依赖关系从而增加逻辑的清晰度。而且bean 的创建是由 Spring 来完成的不需要编程人员关心编程人员只需要将精力放到业务的逻辑上面减轻了思维的负担。在tiny-spring里面整个beans和context包都是用来实现IOC的。beans包实现的核心关注点是BeanFactoryBeanFactory也叫作 Bean 容器顾名思义是用来盛放、管理 bean 的。context包实现的核心关注是ApplicationContextApplicationContext也是用来获取 Bean 的但是它更高层它的面向用户是 Spring 的使用者而 BeanFactory 面向的用户更多是 Spring 开发者。BeanFactory 定义了 Bean 初始化的流程ApplicationContext 定义了从 XML 读取到 Bean 初始化再到使用的过程。Bean 在哪定义刚才有说到Spring 通常通过 xml 文件来统一的描述 beanbean 与 bean 的依赖关系。所以说bean 的定义表述发生在 xml 配置文件之中。这个 XML 文件就是我们需要读取的资源文件。因此首要任务就是研究与读取 XML 资源文件相关的类。bean.io中存放的是读取资源文件的抽象概念。其中包含了三个类或者接口1.Resource接口这个接口只有一个方法InputStream getInputStream() throws IOException;。实现这个接口的类就是一个抽象的资源可以获取这个资源的输入流从而获取其中的内容。 2.UrlResource类这个类实现了Resource接口通过构造器传入一个 url 地址代表的是这个 url 所对应的文件。 3.ResourceLoader类只有一个方法public Resource getResource(String location)。输入 url 的文件地址(并不是真正的 URL 格式地址)来获取 Resource。通过分析上面三个类、接口我们知道这个包完成了一个任务通过ResourceLoader这个类获取某一个地址的Resource从而获取这个文件的输入流。因为使用了 Resource 概念可以使用网络文件或者本地文件。Bean 如何定义1.BeanDefinition是 Bean 定义的核心概念BeanDefinition包含了bean 的对象、bean 的类类型、bean 的名字bean 的所有属性。这个类对 bean 的基本信息做好一个包装。 2.BeanDefinitionReader接口只有一个方法void loadBeanDefinitions(String location) throws Exception;实现这个接口的类具有将某一个文件中的所有 bean 定义载入的功能。所以BeanDefinitionReader定义了在哪载入 bean 定义至于载入到哪里、如何载入稍后看具体实现。 3.AbstractBeanDefinitionReader抽象类上面刚说了实现了BeanDefinitionReader接口的类具有将某一个文件中描述的 bean 定义载入的功能AbstractBeanDefinitionReader就实现了这样一个抽象功能。它的作用就是定义载入到哪和如何载入的问题。在这个类里面有两个属性Map registry;和ResourceLoader resourceLoader;。registry是一个注册表他保存的就是所有的 Bean 定义Map 结构key 是 bean 的名字value 就是 BeanDefinition。resourceLoader描述了如何载入。 4.XmlBeanDefinitionReader这是beans.xml包里面的唯一一个方法也是最重要的方法之一。它继承了AbstractBeanDefinitionReader实现了所有方法解决了 bean 定义中在哪载入、如何载入、载入到哪的三个大问题。这个类面向用户的方法有两个一个是loadBeanDefinitions毫无疑问这个是必须的。另一个是getRegistry用来获取 bean 注册表得到所有 bean 的信息registry 是 bean 们在内存中实际的家。但是这个getRegistry方法并不是面向用户的而是面向 ApplicationContext 的。 5.PropertyValue和PropertyValue代表一种抽象概念在 xml 中bean 的属性包括属性名和属性对象PropertyValue就是这么一个实体。 6.BeanReference代表的是 Bean 的属性不是真实对象而是另一个 bean 的引用。Bean 的组装全过程上面两部分是铺垫而 BeanFactory 才是重点对象。beans.factory包中有三个类用来定义 BeanFactory 相关的概念。1.BeanFactory接口只有一个方法Object getBean(String name) throws Exception;实现这个接口的类就具有了得到一个 bean 的能力。 2.AbstractBeanFactory类较为复杂。详情后讲。 3.AutowireCapableBeanFactory继承了AbstractBeanFactory实现了 applyPropertyValues 方法通过反射将 bean 的所有属性通过 set 方法注入进去。AbstractBeanFactory有三大属性_beanDefinitionMap类似于 registry但是他是 BeanFactory 里面私有的代表的是这个 BeanFactory 里面暂时有哪些 bean 定义。_beanDefinitionNames代表里面这个 BeanFactory 里面有哪些 bean(名字)。 *beanPostProcessors代理处理器AOP 会用到详情后讲。AbstractBeanFactory实现了几大功能_getBean这是主要功能可以获取一个 Bean 对象。_registerBeanDefinition面向 ApplicationContext用来将 XML 配置文件里面的 bean 定义注册到 BeanFactory 里面。_preInstantiateSingletons面向 ApplicationContext用来在开始的时候将所有的 bean 都初始化完毕避免懒加载。_addBeanPostProcessor添加代理处理器。 *getBeansForType在 BeanFactory 里面获取某一个类型的所有 bean。经过上面的分析我们可以知道 BeanFactory 完成了 Bean 初始化的整个流程。BeanFactory 的工作流程如下getBean, 在 beanDefinitionMap 里面得到 bean如果没有的话先初始化。(为什么会没有因为 ApplicationContext 读取 xml 文件时候只是给 BeanDefinition 服了类类型并没有赋值对象这个对象还是需要 BeanFactory 通过反射生成的)。createBeanInstance通过反射根据 BeanDefinition 的类对象新建实体对象 - 将得到的 bean 对象赋值给 beandefinition然后将 BeanDefinition 里面的属性都注入到 Bean 里面这就完成了 doCreateBean。initializeBean 就是调用 BeanPostProcessor 的 postProcessBeforeInitilizztion 方法和 postProcessAfterIntilizatin 方法获取新的 bean这里会在 aop 中用到。好了到这 BeanFactory 就讲完了下面是更重要的 ApplicationContext。ApplicationContext - 用户与 BeanFactory 之间的桥梁beans.context包有三个类、接口完成了 ApplicationContext 的基本功能。ApplicationContext 接口没有任何方法只是继承了 BeanFactory 接口暗示 ApplicationContext 与 BeanFactory 都是获取 Bean 的地方。 2.AbstractApplicationContext抽象类首先它的构造函数接收入参 BeanFactory所以说 ApplicationContext 内部具有一个 BeanFactory。类似于一种装饰器模式但不是装饰器模式类似于代理模式但也不是代理模式。fresh 方法分为三个步骤1.loadBeanDefinitions这个是一个模板方法需要子类实现它的作用就是从某一个地方读取 BeanDefinition然后写入到 ApplicationContext 自己的 BeanFactory 里面这就是 ApplicationContext 与 BeanFactory 之间的联系也就是 ApplicationContext 还负责了读取定义。2. registerBeanPostProcessors这个就是在 BeanFactory 里面找到 BeanPostProcessor然后将他们放到 BeanFactory 的 beanPostProcessors 容器里面方便 BeanFactory 初始化使用。3. onRefresh 初始化一遍所有的 bean。 3.ClassPathXmlApplicationContext实现了 loadBeanDefinitions 的方法将 xml 文件和 BeanFactory 结合在一起。总结 - ApplicationContext 初始化流程ApplicationContext 初始化流程总结 - ApplicationContext 获取 bean 流程AOP–移花接木之魔法上一节讲完了 Spring IOC 的整个流程也就是 bean 从定义获取到得到 bean 之间的整个流程。本节我们接触一下 Spring 另一个重要概念AOP。AOP 用途十分广泛其中 Spring 内部的声明式事务和拦截器都是利用了 AOP 的强大威力才得以优雅的实现。AOP 是什么呢简单来说它可以让编程人员在不修改对象代码的情况下为这个对象添加额外的功能或者限制。很熟悉吧这就是代理模式Java 中存在两种代理模式一种叫静态代理就是通过接口继承复用的方式来完成的 代理类与被代理对象实现相同的接口然后代理类里面会拥有一个被代理对象代理类与被代理对象相同的方法活调用被代理对象的方法不过中间会加以限制您翻开任何一本设计模式相关的书翻到代理模式这一节讲的就是它了。另一种叫做动态代理动态代理就是允许我们在程序运行过程中为动态生成的对象动态的生成代理。显然这比静态代理灵活太多了。Java 默认提供了动态代理的实现方式但是有限制它要求被代理对象必须实现某一个接口。为了突破这一限制为普通类也可以提供代理CGLib 这个库横空出世。因为 AOP 涉及的知识较为复杂所以我先将背景知识介绍一下。Java 动态代理就是 Java 本身提供的代理实现要求对象必须实现某一个接口。CGLib 库为 Java 提供了为普通类提供代理的功能。aopallianceaop 联盟包统一类 aop 编程的一些概念这个包里没有具体的类实现而是定义了几个重要的概念接口具体的 aop 实现要遵从这些接口编程才能达到一定的通用性。aspectj 包实现了通过一种固定的编程语言通过这种简单的编程语言我们可以定位到被代理的类自动完成代理。在 aopallicance 里面定义了几个核心概念:Advice增强实现这个接口说明这个类负责某一种形式的增强。Joinpoint连接点表示切点与目标方法连接处的信息。MethodInterceptor继承了 Interceptor 接口而 Interceptor 继承了 Advice 接口是一种 Advice但是有一个方法 invoke。这个方法需要一个参数 MethodInvocation。MethodInvocation表示的是连接点的信息以及连接点函数的调用。结合上面的信息我们发现其实 MethodInterceptor 的 invoke 方法调用的就是 MethodInvocation 的 proceed 方法而这个 proceed 方法呢应该调用的肯定是 Method.invoke 方法。所以这是一种变相调用 method.invoke 的方式。为什么这样做呢猜一猜的话肯定是为了代码的复用哈哈哈这是废话。在 Spring 中还定义了几个核心概念Pointcut切点可以定位类以及方法。Advisor可以获取一个增强。PointcutAdvisor定义了哪些方法具有什么类型的增强。MethodMatcher表示某一个方法是否符合条件。ClassFilter定义了某个类是否符合条件。TargetSource被代理的对象包括对象本身类类型、所有接口。AdvisedSupport代理相关的元数据包括被代理的对象增强等。ProxyFactory代理工厂可以获得一个代理对象同时具有 AdvisedSupport 的所有特性。Cglib2AopProxy使用 cglib 实现的动态代理类继承了 AbstractAopProxy 抽象类这个类的主要方法就是 getProxy通过什么呢通过 AdvisorSupport。ReflectiveMethodInvocation可以获取连接点的信息代理的对象等。JdkDynamicAopProxy和 Cglib2AopProxy 类一个作用通过 AdvisorSupport 来 getProxy不过是使用 Java 自带的动态代理实现的。其中ProxyFactory 是获取一个代理对象的直接工厂而这个代理对象可以通过 Cglib2AopProxy 产生也可以通过 JdkDynamicAopProxy 产生。Spring AOP 之所以能够为动态生成的 Bean 提供代理得益于 PostProcessor 接口。我们会议 IOC 初始化流程中最后一部就是得到 BeanFactory 之中所有继承了 PostProcessor 接口的 bean调用它们的 postProcessBeforeInitilization、postProcessAfterInitilization 方法来代理 bean生成新的 bean。基于这个突破口我们只需要在 xml 配置文件中放入 PostProcessor 对象Spring 就会自动的用这写对象来代理真正的对象。在这里我们的对象是 AspectJAwareAdvisorAutoProxyCreator。在这个对象的方法中逻辑是这样的找到 xml 里面所有切面 bean然后在这些 bean 里面找到符合被代理类的切面 bean找到切面 bean 之后就可以获得增强切点等于是可有构造一个 AdvisorSupport知道了 AdvisorSupport我们就能够通过 proxyFactory 来获取代理了。至于如何这个类切面是用来切入代理类的这个就要交给 PointCut 来实现了pointcut 有很多实现方式这里我们用的是 aspectj。具体这个类我就不细讲了。到目前位置我自己已经将整个 AOP 的流程搞清楚了下面通过流程图的形式展示出来作者: WindMt来源: WindMt
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/914076.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!