请选择 进入手机版 | 继续访问电脑版
查看: 151|回复: 0

Spring核心源码提升核心竞争力:读懂Spring框架的设计能力

[复制链接]

104

主题

104

帖子

334

积分

中级会员

Rank: 3Rank: 3

积分
334
发表于 2022-10-29 23:00:10 | 显示全部楼层 |阅读模式
手写简单Srping框架,解析Spring核心源码

提升核心竞争力:

1.快速阅读别人的,甚至是神级的框架代码。

2.设计一个让自己无可替代的技术方案。

切入点:阅读Spring框架核心源码,锻炼框架设计能力。根据经验,能够在某个方向编写 100,000 行代码使您成为该方向的专家,而 Spring 大约有 100 万行代码。

授之以鱼不如授之以渔:

1.通过自研框架了解Spring的设计

2.深入Spring源码洞察核心上下文



Spring基础架构图



弹簧芯:

1. 包含框架的基本核心工具类,其他组件必须使用该包中的类

2. 定义并提供对资源的访问

spring-bean:Spring主要是面向bean的编程(BOP)

一、bean的定义

2.豆类分析

3. bean的创建

弹簧上下文:

1.为spring提供一个运行环境,保存对象的状态

2.扩展的BeanFactory

spring-aop:最小的动态代理实现

1.JDK动态代理

2.cglib

3、只支持run-time weaving,只支持method-level weaving,只支持method execution pointcuts

spring-aspectj + spring-instrument :完整的 AspectJ

1.编译器编织

2、装车时的编织

3. 运行时编织

自研框架架构图:



一、环境准备 1.1 下载并编译Spring源码

下载JDK11、maven、IDEA。长期支持 JDK8 和 JDK11。

春天官网:。

Spring 托管到 github:. 在此处下载 5.2.0.RELEASE 版本,更稳定。5.2.0.RELEASE版本链接,下载后解压。

接下来编译,可以参考。

进入解压目录,打开build.gradle,添加阿里云配置

windows在命令行中执行

<p><pre>    <code class="prism language-shell">.<span class="token punctuation">\</span>gradlew :spring-oxm:compileTestJava
</code></pre></p>
编译成功



2.在IDEA中导入项目,

常见问题:引入jar包超时。解决方法:手动下载,放到C:\Users\zkp.gradle\caches\modules-2\files-2.1\xxx\xxx.jar,替换具体目录下的jar包。

编译成功



3.去掉spring-aspects,右键,选择加载/卸载模块,卸载



如果不移除,模块会报错。



4. 重建它

1.2 Spring官方文档

看完Overview and Core,你会有一个大概的了解。

软件版本:

1. GA:General Availability,正式发布的稳定版本。类似的含义是 RELEASE、Stable、Final。

2. RC:Release Candidate,发布候选版本,基本不增加新功能,用于修复bug,修复后作为GA上线。

3. Alpha:内测版本,BUG多,功能不完整。

4. Beta:公测版,晚于Alpha,会增加功能和修复bug。

5. M:Milestone,开发期间的发型版本,开发中发布。





2 商城项目业务

从整体到部分实现,采用MVC架构



单一职责原则:

1、尽量让一个班级负责相对独立的业务

2.保证类之间的低耦合,降低类复杂度

道层:

标题

店铺类别

服务层:

使用泛型返回泛型返回值。

2.1 服务层构建



2.2 控制器层构建

Servlet 用于接收和处理前端请求。它是Sun 提供的一种动态Web 资源开发技术。它本质上是一个Java程序,但它不能独立运行。它需要在 Tomcat 和 Jetty 等 Servlet 容器中运行。运行过程如下:



减少 servlet 的数量。参考 Srping MVC,请求是通过 DispatcherServlet 分派的。

1.阻止所有请求

2.解析请求

3.分发到对应Controller中的方法进行处理



3 补充知识 3.1 设计模式 3.1.1 立面模式

Facade Pattern,Facede Pattern动态泛目录,子系统外部与其内部的通信必须通过一个统一的对象来进行。

1.提供高级接口,使子系统更易于使用





3.1.2 工厂模式

简单工厂模式实际上并不是一种设计模式,而是一种编程习惯。定义一个工厂类,根据传入参数的值返回不同的实例。正在创建的实例有一个共同的父类或接口。



3.1.3 单例模式

单例模式。保证一个类只有一个实例,对外提供统一访问。

饥饿模式:当类被加载时,它被初始化并立即创建一个唯一的实例。

构造函数是私有的,防止外界调用构造函数初始化实例,对外提供静态方法调用。

<p><pre>    <code class="prism language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">StarvingSingleton</span> <span class="token punctuation">{</span>
    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">StarvingSingleton</span> starvingsingleton <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StarvingSingleton</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token class-name">StarvingSingleton</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span><span class="token punctuation">}</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">StarvingSingleton</span> <span class="token function">getInstance</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> starvingsingleton<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></p>
惰性模式:只有在客户端第一次调用时才创建一个唯一的实例。添加双重检查锁定机制以确保线程安全。

<p><pre>    <code class="prism language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">LazyDoubleCheckSingleton</span> <span class="token punctuation">{</span>
    <span class="token keyword">private</span> <span class="token keyword">volatile</span> <span class="token keyword">static</span> <span class="token class-name">LazyDoubleCheckSingleton</span> instance<span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token class-name">LazyDoubleCheckSingleton</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span><span class="token punctuation">}</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">LazyDoubleCheckSingleton</span> <span class="token function">getInstance</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// 第一次检测</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>instance <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">synchronized</span> <span class="token punctuation">(</span><span class="token class-name">LazyDoubleCheckSingleton</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                    <span class="token comment">//第二次检测</span>
                <span class="token keyword">if</span> <span class="token punctuation">(</span>instance <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                    instance <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">LazyDoubleCheckSingleton</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
                <span class="token punctuation">}</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">return</span> instance<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></p>
3.2 泛型

泛型,泛型。

1.使数据类型参数化

对应泛型类型时,对应的数据类型是不确定的

调用泛型方法时,指定具体类型

核心目标:解决容器类型在编译时被安全检查的问题。

泛型类

创建对象时,使用尖括号传入类。如:新的GenericClassExample。

例如:

<p><pre>    <code class="prism language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">GenericClassExample</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">T</span><span class="token punctuation">></span></span> <span class="token punctuation">{</span>
        <span class="token keyword">private</span> <span class="token class-name">T</span> member<span class="token punctuation">;</span>
        <span class="token keyword">public</span> <span class="token class-name">GenericClassExample</span><span class="token punctuation">(</span><span class="token class-name">T</span> member<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                <span class="token keyword">this</span><span class="token punctuation">.</span>member <span class="token operator">=</span> member<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token keyword">public</span> <span class="token class-name">T</span> <span class="token function">handleSomething</span><span class="token punctuation">(</span><span class="token class-name">T</span> target<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> target<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></p>
通用接口

泛型类的用法基本相同,常用于数据类型的生产工厂接口。泛型类或泛型接口都可以传入多个泛型,例如。实现接口时,传入一个类型,普通类可以实现泛型接口,泛型类也可以实现泛型接口。

例如:

<p><pre>    <code class="prism language-java"><span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">GenericIFactory</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">T</span><span class="token punctuation">,</span> <span class="token class-name">N</span><span class="token punctuation">></span></span> <span class="token punctuation">{</span>
        <span class="token class-name">T</span> <span class="token function">nextObject</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">N</span> <span class="token function">nextNumber</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">RobotFactory</span> <span class="token keyword">implements</span> <span class="token class-name">GenericIFactory</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">Integer</span><span class="token punctuation">></span></span> <span class="token punctuation">{</span>
        <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">GenericFactoryImpl</span> <span class="token generics"><span class="token punctuation"><</span><span class="token class-name">T</span><span class="token punctuation">,</span> <span class="token class-name">N</span><span class="token punctuation">></span></span> <span class="token keyword">implements</span> <span class="token class-name">GenericIFactory</span> <span class="token generics"><span class="token punctuation"><</span><span class="token class-name">T</span><span class="token punctuation">,</span> <span class="token class-name">N</span><span class="token punctuation">></span></span> <span class="token punctuation">{</span>
        <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
<span class="token punctuation">}</span>
</code></pre></p>
通用方法

可以用在泛型类、泛型接口,也可以用在普通类或普通接口中。不同的是有更多的方法声明。注意:泛型方法中的泛型标识符 T 独立于泛型类而存在。即使它们都是 T,也会有泛型方法传入的类型指定。

例如:

<p><pre>    <code class="prism language-java"><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token generics"><span class="token punctuation"><</span><span class="token class-name">E</span><span class="token punctuation">></span></span> <span class="token keyword">void</span> <span class="token function">printArray</span><span class="token punctuation">(</span><span class="token class-name">E</span><span class="token punctuation">[</span><span class="token punctuation">]</span> inputArray<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
<span class="token punctuation">}</span>
</code></pre></p>
注意:

1.泛型参数不支持原始类型

2.泛型相关信息不会进入运行阶段(泛型擦除)

在泛型中使用具有继承的类:

1. 使用通配符?,但泛型的类型检查将毫无意义

2. 为泛型类型添加上边界,? 扩展E,表示E或继承E的类

3. 为泛型类型添加一个下边界, ? super E,表示E或者E的父类

通用字母的含义:

E - 元素:用于集合,因为集合存储元素

T - 类型:Java 类

K——键:键

V——价值:价值

N - Number:数字类型

3.3 动态代理 3.3.1 JDK动态代理

基于反射机制,在程序运行时动态生成类的字节码,并加载到JVM中,要求被代理的类必须实现接口。但是代理类不能实现接口。

Proxy,重要的方法是newProxyInatance

InvocationHandler,重要的方法是invoke

优势:

1、JDK是原生的,运行在JVM中更可靠

2.平滑支持JDK版本升级

3.3.2 CGLIB动态代理

基于ASM机制的实现,生成业务类的子类作为代理类。

代码生成库:代码生成库。

1.代理类不需要实现接口

2.内部封装了ASM Java字节码操作框架(轻量级、高性能)

3.动态生成子类覆盖非final方法,绑定hook,回调自定义拦截器

需要在 pom.xml 中引入 cglib

<p><pre>    <code class="prism language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>dependency</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>groupId</span><span class="token punctuation">></span></span>cglib<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>groupId</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>artifactId</span><span class="token punctuation">></span></span>cglib<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>artifactId</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>version</span><span class="token punctuation">></span></span>3.2.9<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>version</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>dependency</span><span class="token punctuation">></span></span>
</code></pre></p>
回调接口标记

MethodInterceptor 继承 CallBack

Enhancer,核心是create方法

<p><pre>    <code class="prism language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">AlipayMethodInterceptor</span> <span class="token keyword">implements</span> <span class="token class-name">MethodInterceptor</span> <span class="token punctuation">{</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token class-name">Object</span> <span class="token function">intercept</span><span class="token punctuation">(</span><span class="token class-name">Object</span> o<span class="token punctuation">,</span> <span class="token class-name">Method</span> method<span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">,</span> <span class="token class-name">MethodProxy</span> methodProxy<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Throwable</span> <span class="token punctuation">{</span>
        <span class="token function">beforePay</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">Object</span> result <span class="token operator">=</span> methodProxy<span class="token punctuation">.</span><span class="token function">invokeSuper</span><span class="token punctuation">(</span>o<span class="token punctuation">,</span> args<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">afterPay</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> result<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">beforePay</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"before"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">afterPay</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"after"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">CglibUtil</span> <span class="token punctuation">{</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token generics"><span class="token punctuation"><</span><span class="token class-name">T</span><span class="token punctuation">></span></span> <span class="token class-name">T</span> <span class="token function">createProxy</span><span class="token punctuation">(</span><span class="token class-name">T</span> targetObject<span class="token punctuation">,</span> <span class="token class-name">MethodInterceptor</span> methodInterceptor<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token class-name">T</span><span class="token punctuation">)</span> <span class="token class-name">Enhancer</span><span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span>targetObject<span class="token punctuation">.</span><span class="token function">getClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> methodInterceptor<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">ProxyDemo</span> <span class="token punctuation">{</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">CommonPayment</span> commonPayment <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">CommonPayment</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">AlipayMethodInterceptor</span> alipayMethodInterceptor <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">AlipayMethodInterceptor</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">CommonPayment</span> payment <span class="token operator">=</span> <span class="token class-name">CglibUtil</span><span class="token punctuation">.</span><span class="token function">createProxy</span><span class="token punctuation">(</span>commonPayment<span class="token punctuation">,</span> alipayMethodInterceptor<span class="token punctuation">)</span><span class="token punctuation">;</span>
        payment<span class="token punctuation">.</span><span class="token function">pay</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></p>
优势:

1.代理对象不需要实现接口,可以实现代理类的不侵入

2.两者的效率其实很接近,CGLIB目前也快不了多少。

SpringAOP底层机制:

CGLIB 和 JDK 动态代理共存

默认策略:

如果bean实现了接口,使用JDK,否则使用CGLIB

自研框架

框架最基本的功能:

1.解析配置、xml、注解等,自研框架使用注解

2. 定位和注册对象

3.注入对象

4.提供通用工具

4 IoC容器的实现

实施要点:

创建注释、提取标记对象、实现容器、依赖注入

4.1 创建注释

@Target(ElementType.TYPE):表示这个注解作用于类

@Retention(RetentionPolicy.RUNTIME):表示生命周期为运行时

Controller层对应注解@Controller

Service层对应注解@Service

DAO层对应注解@Repository

@Component 是需要由容器管理的类的通用注解

4.2 提取标记对象

extractPackageClass 需要完成什么

1.获取类加载器

2.通过类加载器获取加载的资源信息

3.根据不同的资源类型,使用不同的方法获取资源集合

类加载器类加载器

URL 统一资源定位器

资源的唯一地址

通过获取.URL实例获取协议名、资源名路径等信息

这里稍微修改一下,使用getSource获取路径后,如果路径中有中文,会被编码,所以需要解码



4.3 实现容器

使用单例模式,这里倾向于使用饥饿的人模式。因为饥饿模式更简单,我们需要在启动时初始化容器以备后续使用。

注意:反射可以突破私有构造函数的限制。

解决方法:枚举。无视反射攻击。枚举的构造函数本身是私有的,外界无法访问。此外,还可以抵抗序列化和反序列化攻击,即先对实例进行序列化再反序列化。读取 ObjectInputStream 的 readObject 源。

<p><pre>    <code class="prism language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">EnumStarvingSingleton</span> <span class="token punctuation">{</span>
    <span class="token keyword">private</span> <span class="token class-name">EnumStarvingSingleton</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span><span class="token punctuation">}</span>
    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">EnumStarvingSingleton</span> <span class="token function">getInstance</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token class-name">ContainerHolder</span><span class="token punctuation">.</span>HOLDER<span class="token punctuation">.</span>instance<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">private</span> <span class="token keyword">enum</span> <span class="token class-name">ContainerHolder</span><span class="token punctuation">{</span>
        HOLDER<span class="token punctuation">;</span>
        <span class="token keyword">private</span> <span class="token class-name">EnumStarvingSingleton</span> instance<span class="token punctuation">;</span>
        <span class="token class-name">ContainerHolder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
            instance <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">EnumStarvingSingleton</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></p>
容器组件:

持有 Class 对象及其实例的载体,使用 ConcurrentHashMap

集装箱装载,

1.配置管理与获取

2.获取指定范围内的Class对象

3.根据配置提取Class对象,与实例一起存放在容器中

容器的工作原理

添加和删​​除操作

根据Class获取对应的实例

获取所有类和实例

通过注解获取注解标记的类

通过超类获取对应的子类Class

获取容器载体中存储的类数

clazz.isAssignableFro(clazz1)方法判断传入的类是clazz的实现类还是子类还是它自己。

4.4 依赖注入

目前容器中管理的Bean实例可能还不完整,部分成员变量还没有创建。

实施思路:

定义相关的注解标签

实现创建注解标记的成员变量的实例并将其注入到成员变量中

使用依赖注入

5 AOP的实现

Aspect:模块化封装横切关注点逻辑的实体对象

Notify Advice:类似于Class中的一个方法,同时也定义了编织逻辑的时序

JoinPoint JoinPoint:允许建议的地方

SpringAOP 默认只支持方法级别的 JoinPoint

Pointcut PointCut:定义一些列规则来过滤JoinPoint

目标对象Target:满足PointCut条件,待织入横切逻辑的对象

建议类型:

BeforeAdvice:在 JoinPoint 之前执行的通知

AfterAdice:类似于 finally 块

AfterReturningAdvice:在JoinPoint执行过程正常返回后执行

AfterThrowingAdvice:仅在 JpintPoint 执行过程中抛出异常时触发

AroundAdvice:在JoinPoint前后都执行,最常用的Advice

单个Aspect的执行顺序:



多个Aspect的执行顺序:

介绍——介绍建议

在目标类没有任何实现的情况下向目标类引入新接口

使目标类在使用过程中转化为新的接口对象,并调用新接口的方法

类加载器

1、通过包名的类获取对应类文件的二进制字节流

2、根据读取的字节流,将表示的静态存储结构转换为运行时数据结构

3、生成一个Class对象,表示该类作为方法区中该类的数据访问入口

按照一定的规则修改或生成一个新的字节流,并将切面逻辑织入其中——动态代理机制

5.1 AOP 1.0

使用CGLIB实现:不需要业务类实现接口,比较灵活。三步完成AOP1.0:

第一步,解决标记问题,定义横切逻辑的骨架

1.定义横切逻辑相关的注解

创建@Aspect标签动态泛目录,放在横切逻辑类上,表示以后这个类会被编织到其他的目标类中。

创建@Order标签,因为一个类中可能有不同的Aspect类,所以需要定义编织顺序。

2.定义一个横切的逻辑骨架供外部使用

创建 DefaultAspect 抽象类,它具有 before、afterThrowing、afterReturning 方法作为逻辑框架。这样,Aspect类只需要继承这个抽象类,选择性地实现这三个方法,就可以编织出相应的逻辑。每个 Aspect 类都需要扩展 DefaultAspect 类。

第二步,定义Aspect横切逻辑和代理方法的执行顺序

1、创建MethodInterceptor的实现类,对应多个Aspect,最后只调用一次invokeSuper方法。先按升序执行各个Aspect的before方法,再逆序执行各个Aspect的after...方法。创建一个新的 AspectListExecutor 类。新建一个AspectInfo类,封装两个成员变量DefaultAspect和orderIndex。

2.定义必要的成员变量——代理类和Aspect列表

3. 按顺序对方面进行排序

4.实现被代理对象的横切逻辑和方法的顺序执行

第三步,将横切逻辑编织到代理对象中,生成动态代理对象

ProxyCreator 类创建代理对象。

AspectWeaver类,其中的doAop方法可以实现所有Aspect类的编织。

5.2 AOP 2.0

用最小的装修成本换取最大的利润

SpringAOP的发展历程

1、Spring AOP 1.0是Spring自主开发的。使用起来不是很方便。它需要实现各种接口并继承指定的类。

2. Spring AOP2.0继承AspectJ,复用AspectJ语法树,只使用AspectJ的切面语法,不使用ajc编译工具,防止增加学习成本,编织机制遵循JDK和CGLIB动态代理机制

AspectJ 框架

提供完整的AOP解决方案,即AOP的Java实现版本。

1.定义切面语法和切面语法的解析机制

2.提供强大的编织工具



AspectJ 框架中的编织时序:

编译时编织:使用ajc将切面逻辑编织到类中生成类文件(静态)

编译后编织:使用ajc修改javac编译的class文件(静态)

在类加载期间编织:在类加载期间使用 java 代理,编织切面逻辑 (LTW)

介绍 AspectJ

1.让Pointcut更灵活

2.只需要介绍AspectJ的方面表达和相关的定位分析机制

修改@Aspect,删除值,改成String类型的切入点。

创建PointcutLocator类,成员变量pointcutParser为切入点解析器,pointcutExpression为表达式解析器。roughMatches 方法判断代理类是否是Aspect 的目标类,accumulateMatches 方法判断该方法是否是Aspect 的目标方法。为每个 Aspect 类创建 PointcutLoactor。

6 MVC的实现

MVC 模块。

DispatcherServlet 获取 HTTP 请求并发送 HTTP 响应。获得HTTP请求后,委托给RequestProcessorChain进行处理。为简单起见,仅处理 GET 和 POST 请求。



DispatcherServlet

1.解析请求路径和请求方法

2.依赖容器,建立并维护Controller方法与请求的映射关系

3.使用合适的Controller方法来处理特定的请求

/* 最高优先级,所有请求都会被处理;/ 低优先级。

请求处理器控制器请求处理器

1.针对具体的请求,选择匹配的Controller方法进行处理

2、解析请求中的参数及其对应的值,赋值给Controller方法的参数

3.选择合适的Render,准备渲染

结果渲染

对于 JSON,请使用来自 Google 的 Gson 包。

豪侠泛目录站群程序,专业泛目录,站群,二级目录,泛站群程序!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表