代理
之前我们讲nginx的时候说过,代理是指存在于我们与操作目标之间的一个东西,我们可以自己去操作目标,也可以通过代理去操作操作目标;就比如黄牛,我们可以自己去买火车票,也可以通过代理(黄牛)去买火车票。通过代理,我们可以附加更多的操作。比如操作目标里面是没有日志输出的,但是我们可以在代理类中给它加上。
aop
AOP是什么和优点
AOP 专门用于处理系统中分布于各个模块(不同方法)中的交叉关注点的问题,在 Java EE 应用中,常常通过 AOP 来处理一些具有横切性质的系统级服务,如事务管理、安全检查、缓存、对象池管理等,AOP 已经成为一种非常常用的解决方案。
在进行OOP开发时,都是基于对组件(比如类)进行开发,然后对组件进行组合,OOP最大问题就是无法解耦组件进行开发,比如我们上边举例,而AOP就是为了克服这个问题而出现的,它来进行这种耦合的分离。
总而言之,AOP有以下几个优点:
- 用于横切关注点的分离和织入横切关注点到系统;比如上边提到的日志等等;
- 完善OOP;
- 降低组件和模块之间的耦合性;
- 使系统容易扩展;
- 而且由于关注点分离从而可以获得组件的更好复用。
AOP术语
@Before(value = "execution(* com.huangzp.test.aop.*.sayHello(..))")
public void sayHello(){
System.out.println("我是Aop config");
}
连接点(Jointpoint):表示需要在程序中插入横切关注点的扩展点,连接点可能是类初始化、方法执行、方法调用、字段调用或处理异常等等,Spring只支持方法执行连接点,在AOP中表示为“在哪里干”;
切入点(Pointcut):选择一组相关连接点的模式,即可以认为连接点的集合,Spring支持perl5正则表达式和AspectJ切入点模式,Spring默认使用AspectJ语法,在AOP中表示为“在哪里干的集合”,上面就是一个切入点,具体到HelloService.sayHello()就是一个连接点。
通知(Advice):在连接点上执行的行为,通知提供了在AOP中需要在切入点所选择的连接点处进行扩展现有行为的手段;包括前置通知(before advice)、后置通知(after advice)、环绕通知(around advice),在Spring中通过代理模式实现AOP,并通过拦截器模式以环绕连接点的拦截器链织入通知;在AOP中表示为“干什么”;
方面/切面(Aspect):横切关注点的模块化,比如上边提到的日志组件。可以认为是通知、引入和切入点的组合;在Spring中可以使用Schema和@AspectJ方式进行组织实现;在AOP中表示为“在哪干和干什么集合”;
引入(inter-type declaration):也称为内部类型声明,为已有的类添加额外新的字段或方法,Spring允许引入新的接口(必须对应一个实现)到所有被代理对象(目标对象), 在AOP中表示为“干什么(引入什么)”;
目标对象(Target Object):需要被织入横切关注点的对象,即该对象是切入点选择的对象,需要被通知的对象,从而也可称为“被通知对象”;由于Spring AOP 通过代理模式实现,从而这个对象永远是被代理对象,在AOP中表示为“对谁干”;
AOP代理(AOP Proxy):AOP框架使用代理模式创建的对象,从而实现在连接点处插入通知(即应用切面),就是通过代理来对目标对象应用切面。在Spring中,AOP代理可以用JDK动态代理或CGLIB代理实现,而通过拦截器模型应用切面。
织入(Weaving):织入是一个过程,是将切面应用到目标对象从而创建出AOP代理对象的过程,织入可以在编译期、类装载期、运行期进行。
意义和举个栗子
我写代码,尤其添加,修改和删除等重要操作的时候,特别喜欢加日志,比如当我保存一只猫的时候:
public int saveCat(Cat cat){
int result = dao.save(cat);
logger.info("save Cat;cat = {}, result = {}", cat, result);
return result;
}
当我更新一只猫/删除一只猫的时候,也是如此:
public int updateCat(Cat cat){
int result = dao.update(cat);
logger.info("updateCat;cat = {}, result = {}", cat, result);
return result;
}
public int deleteCat(Cat cat){
int result = dao.delete(cat);
logger.info("deleteCat;cat = {}, result = {}", cat, result);
return result;
}
如果只有一只动物那还好,要是我家是开动物园的,鸡鸭鹅都有,那我不是每次都要加重复的日志,岂不是很奔溃。这个日志和业务本身关系不大,但是又比较重要,所以不能去掉。那有什么方法是可以正常打出日志,但是不会在业务本身显式调用的呢?利用aop可以解决这个问题,在每次方法执行完以后,在比这个方法更上一层的地方(代理类),输出这个方法的参数和返回值的日志即可。
代理与AOP
我的理解是AOP可以通过代理来实现的,但是代理不是唯一实现AOP的方式。比如像aspectj,它完全把切面织入到了目标对象,而不是通过再搞一个代理类来实现的。