|
手写简单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 包。
豪侠泛目录站群程序,专业泛目录,站群,二级目录,泛站群程序! |
|