前言
上一篇文章主要介绍的是spring的ioc容器,以及如何实现依赖注入,但是在创建bean的时候没有详细的讲解,为的就是引申这次要讲的内容AOP,不过在了解AOP时,我们要有一些技术背景:代理设计模式,jdk动态代理。
代理设计模式
代理,大白话讲就是,代理人以你的名义去帮你做事情,而你什么都不用做,坐享其成。 举一个例子:小明打电话订了一杯奶茶,然后小明找了一个代理人小马去把奶茶取回来。 用伪代码实现:
//定义一个抽象类,一个抽象的取奶茶方法
class abstract Person{
abstract void takeTea()
}
//小明
class XiaoMing extends Person{
//没有请跑腿的小明只能自己去取奶茶
void takeTea(){
print('小明自己跑来取奶茶')
}
}
class XiaoMaProxy extends Person{
//小明授权小马
XiaoMing xiaoMing = new XiaoMing();
void takeTea(){
print('小马跑来取奶茶')
xiaoMing.takeTea()
print('小明接力了小马的奶茶喝起来了')
}
}
//
main{
//使用代理类,就不用本体去做事情了
Person p = new XiaoMaProxy();
p.takeTea();
//没有使用代理类,本体做事情
Person p2 = new XiaoMing();
p2.takeTea();
}
上面的代理模式属于静态代理,需要我们编写小马这样的代理人,但是在JDK1.3开始就为我们提供了动态代理,不用我们每次使用代理模式都要写一次代理人。在运行期间,为相应的接口动态生成对应的代理对象。
//必须实现 InvocationHandler
public class PersonProxy implements InvocationHandler {
private Object subject;
private String name;
public PersonProxy(Object subject,String name) {
this.subject = subject;
this.name = name;
}
//执行代理方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("我是"+this.name+",来取奶茶了");
method.invoke( this.subject,args);
System.out.println("免费!!!");
return null;
}
}
main{
XiaoMing xiaoMing = new XiaoMing();
PersonProxy personProxy = new PersonProxy(xiaoMing,"动态代理人");
Person person = (Person) Proxy.newProxyInstance(
//类加载器
personProxy.getClass().getClassLoader(),
//代理的接口
xiaoMing.getClass().getInterfaces(),
//代理类
personProxy);
person.takeTea();
}
如果有调试过代码的朋友就会发现,创建bean返回的带线要么是proxy或者cglib,其实spring为我们创建的bean全都代理对象,不是一个个去new创建的,proxy或者cglib跟策略选择的,这是代理的方式不一样而已,我们只管它是代理对象就好了。
AOP
AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。大白话就是,在我们执行方法的前后加入自定义的逻辑,比如输出日志。在我们上面的例子中代理类在执行目标方法时,做了其他事情。
spring中的AOP概念
- Joinpoint:Joinpoint仅支持方法级别的调用,在方法被调用的时候进行横切织入。
- Pointcut:切点,指定要织入的方法名。
- Advice:不会中断程序执行
- Before Advice: 织入前,在Joinpoint执行前调用
- After Advice: 织入后,在Joinpoint执行后调用
- After return Advice:Joinpoint执行后执行
- After throwing Advice:抛出异常时执行
- Finally Advice:不管Joinpoint有没有抛出异常都会执行
- Around Advice:将Joinpoint包裹起来,将Before Advice和After Advice合在一起
- Aspect:用来承载切点的,对Pointcut进行模块化的封装的AOP实体。
AOP的应用案例
将上面的代理模式用AOP来实现
//织入的目标
@Component
public class XiaoMing implements Person{
@Override
public void takeTea() {
System.out.println("我是小明");
}
}
@Component
@Aspect //定义AOP实体
public class PersonAspect {
//定义切点 execution表达式
@Pointcut("execution(* com.xiaoma.mall.proxy.XiaoMing.takeTea())")
public void cut(){};
//织入前
@Before("cut()")
public void before(JoinPoint joinPoint){
System.out.println("我是动态代理人,来取奶茶了");
}
//执行JoinPoin后
@AfterReturning(pointcut = "cut()")
public void after(JoinPoint joinPoint){
System.out.println("免费!!!");
}
}
output
我是动态代理人,来取奶茶了
我是小明
免费!!!
小结
AOP是一项面向切面编程技术,帮我们在不改动目标代码的情况下完成的,将模块之间解耦,这样更加利于我们项目的扩展。应用的案例还好多,《spring 揭秘》中提到3种案例:异常处理,安全检测,缓存我们都可以去看下,了解下应用的场景,为我们后续的实践开发做好铺垫。