一、设计模式-代理模式
代理模式:给某一个对象提供一个代理对象,并由代理对象控制对源对象的引用。代理 就是一个人或一个机构代表另一个人或者一个机构采取行动。某些情况下,客户不想或者不 能够直接引用一个对象,代理对象可以在客户和目标对象直接起到中介的作用。客户端分辨 不出代理主题对象与真实主题对象。代理模式可以并不知道真正的被代理对象,而仅仅持有 一个被代理对象的接口,这时候代理对象不能够创建被代理对象,被代理对象必须有系统的 其他角色代为创建并传入。 为什么要使用代理模式呢? 第一,它有间接的特点,可以起到中介隔离作用。就好比在租房的时候,房东可能不在 本地,而短期内又不能赶回来,此时中介的出场,就作为房东的代理实现和我们签订承租合 同。而我们和房东之间就没有耦合了。 第二,它有增强的功能。还以租房为例,我们首先考虑的是找一个靠谱的中介,由中介 给我们提供房源信息,并且告诉我们房屋的细节,合同的细节等等。当然我们也可以自己去 找一些个人出租的房屋,但是在这之中,我们要了解租赁合同,房屋验收,租金监管等情 况,这无疑对我们是繁重的工作。而有了中介作为我们的代理中间人,他把了解到的信息告 诉我们,我们一样可以租到房子,而不必做那些繁重的工作。
二、AOP思想及实现原理
1、AOP思想
在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通 过预编译方 式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中 的一个 热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对 业务逻辑 的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性, 同时提高 了开发的效率。
2、实现原理
在上面的概念中描述出aop的实现原理是基于动态代理技术实现的。下面是针对动态代 理的一些介绍:
特点: 字节码随用随创建,随用随加载
分类: 基于接口的动态代理,基于子类的动态代理
作用: 不修改源码的基础上对方法增强 基于接口的动态代理:
提供者是:JDK官方
使用要求:被代理类最少实现一个接口。
涉及的类:Proxy
创建代理对象的方法:newProxyInstance
方法的参数: ClassLoader:类加载器。用于加载代理对象的字节码的。和被代理对象使 用相同的类加载器。固定写法。
Class[]:字节码数组。用于给代理对象提供方法。和被代理对象具有相同的 方法。 被代理类是一个普通类:
被代理类对 象.getClass().getInterfaces();
被代理类是一个接口:new Class[]{被代理了.class}
它也是固定写法
InvocationHanlder:要增强的方法。此处是一个接口,我们需要提供它的 实现类。 通常写的是匿名内部类。增强的代码谁用谁写。 基于子类的动态代理
提供者是:第三方cglib包,在使用时需要先导包(maven工程导入坐标即可)
使用要求:被代理类不能是最终类,不能被final修饰
涉及的类:Enhancer
创建代理对象的方法:create
方法的参数: Class:字节码。被代理对象的字节码。可以创建被代理对象的子类,还可以 获取被代理对象的类加载器。
Callback:增强的代码。谁用谁写。通常都是写一个接口的实现类或者匿名 内部类。
Callback中没有任何方法,所以我们一般使用它的子接口: MethodInterceptor
3、Spring中AOP的术语
Joinpoint(连接点):
所谓连接点是指那些被拦截到的点。在spring中,指的是方法,因为spring只支持方 法类型的连接点。
Pointcut(切入点):
所谓切入点是指我们要对哪些Joinpoint进行拦截的定义。
Advice(通知/增强):
所谓通知是指拦截到Joinpoint之后所要做的事情就是通知。 通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知。
Introduction(引介):
引介是一种特殊的通知在不修改类代码的前提下, 可以在运行期为类动态地添加一 些方法或Field。
Target(目标对象): 代理的目标对象。
Weaving(织入):
是指把增强应用到目标对象来创建新的代理对象的过程。 spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入。
Proxy(代理): 一个类被AOP织入增强后,就产生一个结果代理类。
Aspect(切面):
是切入点和通知(引介)的结合。
三、Spring注解驱动AOP开发入门
1、写在最前
a.Spring的aop是基于ioc的。所以需要有spring的ioc基础。(本篇内容不对ioc进行讲 解)
b.本章节我们只是对aop的使用做基本功能展示,目的是为了以此讲解aop中的注解和执行原 理分析。
2、注解驱动入门案例介绍
需求: 实现在执行service方法时输出执行日志。(除了业务层外,表现层和持久层也可 以实现)
3、案例实现
实体类:(在本案例中没有实际作用)
/**
* @author 黑马程序员
* @Company http://www.itheima.com
*/
public class User implements Serializable {
private String id;
private String username;
private String password;
private String email;
private Date birthday;
private String gender;
private String mobile;
private String nickname;
}
业务层接口:
/**
* @author 黑马程序员
* @Company http://www.itheima.com
*/
public interface UserService {
/**
* 保存用户
* @param user
*/
void save(User user);
}
业务层实现类:
/**
* 用户的业务层实现类
* @author 黑马程序员
* @Company http://www.itheima.com
*/