设计模式应用实例二(代理模式的应用)

前言
1、本节讲解代理模式的概念及其基本特性。
2、先讲解静态代理、动态代理这两种方式用法,应用场景以及它们被提出来的原因,也算是介绍代理模式的历史吧,让大家对代理模式有个大致的形象。
3、在实例方面选取典型的springAOP从场景问题和作者设计意图来简要讲解spring AOP 的设计思想,并简要描述spring事务的代理过程。

概念

结构型模式,是指为其它对象提供一种代理以控制某个对象的访问。

记忆关键点

控制目标对象(代理控制)

类结构简图

静态代理结构图

应用场景

最主要的两个经典场景是权限控制/业务控制延迟加载
例如手机刷淘宝、抖音时向上划加载商品简图的过程

学习目标

1、知道代理模式的使用场景
2、静态代理模式的基本用法
3、动态代理模式的基本用法

相似模式,区分及应用

装饰模式:结构型模式。指在不改变现有对象结构的情况下,动态地给该对象增加一些职责。即给目标对象增加多种变体。
区别:对于客户端类来说装饰模式表现在于目标对象变强了,好似游戏里的狼人形态,熊人形态。而代理模式给客户端的表现是客户端并不知道它要的东西是被处理过的,这就是代理模式控制的本质。
相关阅读:《设计模式应用实例三(装饰模式的应用)》

适配器模式:结构型模式。指将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。
即两种变压器一起工作为客户端提供适当的电压。
区别:适配器是协同工作,代理是控制。适配器在业务上有一定的相关性,代理在业务相关性上联系不大。适配器是充分利用当前资源进行整合,代理控制资源调配。

实例

前述:

首先从静态代理出发,理清代理的基本结构,再从实际场景出发,描述springAOP要解决的问题域来引出springAOP设计者的整个设计思路及大概实现过程,本实例不会详细讲解整个SpringAOP细节,只要理清设计者设计思路和解决问题的技术手段,我认为对整个框架理解方向不会错。细节问题,各位看官有时间有精力可以自行详阅spring源代码。
本实例spring版本是5.2.x

静态代理:

静态代理的焦点在类上,通过类的代理来控制类的防问。
它的代码模板就如下所示

//接口
public interface TargetInterface{
     public void handler();
}
//目标类
public class TargetSource implements TargetInterface{
	public void handler(){
	}
}
//代理类
public class ProxyTarget implements TargetInterface{
	private TargetSource target;
	public ProxyTarget(TargetInterface target){
		this.target = target;
	}
	public void handler(){
		preHandler();
		this.target.handler();
	}
	private void preHandler(){
	}
}

静态代理通过硬编码方式实现,是在知道目标实现类的情况下,实现的方式比较简单,可以快速解决业务实际问题。
但有个最大缺点是必须要有目标实现类,并且多一个目标实现类就要多写一个代理类。到最后庞大的类集团会让人产生恐惧感。

动态代理:

动态代理是在JVM环境生成一个$Proxy0对象,这个$Proxy0对象只有在程序启动时才会产生。
为了减轻密集恐惧症候人群的反应(每个人多多少少都有一点密集恐惧症,只是程度问题)。
那么有大神就提出了动态代理的解决方案,该方案将问题的焦点聚集在目标实现类的方法上。
既然代理控制是在目标实现类的方法前后执行代理的处理过程,那么把问题的焦点聚集在目标实现类的方法上就好了嘛,因此JDK那帮大神创造动态代理将目标类方法用InvocationHandler包装起来。
动态代理的简单实现如下

public class MethodInvocation implements InvocationHandler{
	Object target;
	public MethodInvocation(Object target){
		this.target = target;
	}
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
	    //TODO 前置执行你的业务(方法)
	    method.invoke(target, args);
	    //后置执行你的业务(方法)
	}
}

//客户端
public class client{
	public static void main(String[] args) {
        TargetInterface target= new TargetSource();
        InvocationHandler handler = new MethodInvocation (target);
        TargetInterface proxy = (TargetInterface) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), handler);
		proxy.handler();
    }

} 

通过给出这样的解决方案后,代理类集团被瓦解了。虽然解决了代理类集团,但代理业务处理过程还是被硬编码在了MethodInvocation 里(target类方法的前后置处理过程)

SpringAOP代理方案

为了更好的解决代理的硬编码问题,SpringAOP提出了切面的概念,即是将目标类方法定义为pointcut >> 切入点,切入点前后置方法分别为beforeAdivice,afterAdivice。它将代理类的前后置方法抽象出来,并用注解的技术手段绑定在目标类方法上。

静态代理、动态代理、SpringAOP关系

它们之间的关系如下

关系图
静态代理是最基本的代理模式,为了解决代理类过多的问题提出动态代理方案,为了解决硬编码问题,引入切面编程(代理)。这就是代理模式的进化图谱。

SpringAOP代理模型

创建AOP过程

一般AOP创建过程
在创建过程中将目标类的所有拦截器放入拦截器数组中以方便执行时进行链式(责任链模式)处理。
整个创建过程为
1、CacheProxyFactoryBean在加载时将前置后置拦截器(你的@Before@After@Pointcut等)设置进来
2、创建代理工厂ProxyFactory生成JdkDynamicAopProxy
3、JdkDynamicAopProxy按JDK动态代理Proxy.newProxyInstance规则创建代理类$Proxy0,并将$Proxy0放入cache中
代理执行过程
代理执行过程
执行时很简单,依次调用拦截器链,最后才执行真实目标类的方法。

Spring事务的代理

在spring中事务管理也是一个非常重要的部分。spring的事务也是采用springAOP代理方式来解决事务的。通过给目标类打上@Transactional定义事务拦截作数据操作的前后置处理。带着这样一个问题我们来看看被打上@Transactional标识的目标类究竟被做了什么手脚?
Spring事务的活动是这样的,这个图不一定很准确,大致的过程是这样的
Spring事务的代理
1、 加载时注入配置的PlatformTransactionManager实现类与TransactionAspectSupport
2、 如果方法被加上@Transactional则创建事务。事务创建后判断是否是嵌套事务,是嵌套事务就在数据库里设置事务点,然后执行目标类方法,有异常就事务回滚,没有异常就提交事务
3、不是嵌套事务就直接创建事务,执行目标类方法,提交事务

spring事务的几个关键方法

TransactionAspectSupport.createTransactionIfNecessary–(TransactionAspectSupport类360行)
Transactionstatus = tm.getTransaction(txAttr);(TransactionAspectSupport类572行)
AbstractPlatformTransactionManager.getTransaction()//生成事务
AbstractPlatformTransactionManager.handleExistingTransaction()//存在事务嵌套的方法处理
AbstractPlatformTransactionManager.startTransaction
AbstractPlatformTransactionManager::status.createAndHoldSavepoint();—457行
AbstractPlatformTransactionManager.startTransaction–394行,开始事务
DefaultTransactionStatus status =
prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);–AbstractPlatformTransactionManager455行
status.createAndHoldSavepoint();AbstractPlatformTransactionManager457行//设置事务点,以便异常时回滚
DataSourceTransactionManager.doBegin() //事务前处理

JdbcTransactionObjectSupport.createSavepoint();
160行conHolder.createSavepoint();
最后设置事务点是调用jdbc的statement.executeUpdate(‘SAVEPOINT’)来设置的。
spring事务的其它所有类都是为这一过程服务的,什么TransactionAttribute,TransactionDefinition等都是spring事务的领域对象,这些对象在事务创建过程中被使用而已。事务创建完成后,最终还是要调用AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);来执行目标类方法。
springAOP及其事务类浩繁如毛,这里不能一一解读,如果看官有兴趣可以自行研究细节,这里只说AOP代理的逻辑过程。

回顾

本节说了什么内容呢,我们来回顾一下
1、代理的概念,应用场景
2、静态代理,动态代理基本用法
3、静态代理,动态代理,SpringAOP三者的关系
4、针对同一个问题域,springAOP的设计思路与解决技巧
5、spring事务代理的整个过程

讨论:

谢谢大家耐心阅读完本节文章。本人对代理模式的肤浅理解已全部呈现给大家,如果各位看官对代理模式有不同的理解,可以在下方的评论区说出你的想法。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值