什么是AOP?
我们先来思考一个问题:“怎么把大象放到冰箱里面”?其实,很多人已经知道答案,就三步:1.打开冰箱们,2.把大象放进冰箱,3.关上冰箱门。那同理,我们也是同样的操作水果跟蔬菜;
大象:1.打开冰箱们,2.把大象放进冰箱,3.关上冰箱门
水果:1.打开冰箱们,2.把水果放进冰箱,3.关上冰箱门
蔬菜:1.打开冰箱们,2.把蔬菜放进冰箱,3.关上冰箱门
可以看到,我们的主要业务是把目标对象(大象,水果,蔬菜)放进冰箱,而次要业务是“打开冰箱们”和“关上冰箱门”,而且这些业务都是一样的。那我们这时候就想想能不能把相同的部分抽离出来,当他们执行操作时,我们动态的监控,如果你想要把对象放到冰箱里面,那他就会在执行的过程中调用这个公共的部分。事实上,AOP就是在做这样子的事情
AOP(官方解释)
AOP:面向切面编程,相当于平面的X轴,OOP面向对象编程,相当于Y轴。OOP引入封装、继承和多态性等概念来建立一种对象层次结构,继承或者实现,相当先有父级再有子级,从上到下继承和实现,也就是说,OOP是从上到下的关系,而不是从左到右的关系,简单来说,就像一个执行的过程,比如上面的例子“把大象放入冰箱”,实际上是有一个从左到右的过程,又或者例如日志功能,数据库事务以及异常通知等等一些公共的模块代码,它跟对象的核心功能毫无关系。如果每个OOP设计,都写这些公共的代码,那它导致了大量代码的重复,而不利于各个模块的重用。
自我理解
我的理解就是:AOP就是把一些不是目标对象的次要业务公共部分逻辑,把它封装到一个可以重用的模块;将那些与主要业务无关,却为业务模块所共同调用的逻辑或责任封装起来供给对象集体调用,达到可以让我们动态的控制程序的执行流程及执行结果,这样就减少了代码的重复性,降低模块间的耦合度,你可以想象如果每个对象都写这个打开冰箱门,关闭冰箱们这些次要逻辑代码,那是不是很冗余。
AOP是实现原理之动态代理
动态代理多种:JDK、CGLIB、javassist、ASM。而Spring中我们只了解其中的JDK和CGLIB两种动态代理
JDK:JDK的动态代理机制只能代理实现了接口(InvocationHandler)的类,而不能实现接口的类就不能实现JDK的动态代理。
CGLIB:针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,采用的是继承。
下面通过小例子来简单的认识一下AOP的JDK动态代理
1.创建动态代理对象,关联目标对象
2.实现代理的自我逻辑方法
目标对象主要业务:吃饭(目标对象)
次要业务:洗手、处理剩菜、清洗餐具、处理急事。(代理的逻辑方法)
public interface DinnerService{
public void hava();
}
@Service
public class LanuchServiceImpl implements DinnerService{
public void hava(){
System.out.println("吃饭罗");
}
}
@Service
public class DinnerProxy implements InvocationHandler{
//目标对象
pravite Object target = null;
//拦截器
pravate DinnerInterceptor dinnerInterceptor = null
//建立代理对象和目标对象的关联关系
public static Object bind(Object target,DinnerInterceptor dinnerInterceptor){
DinnerProxy dinnerProxy = new DinnerProxy();
dinnerProxy.target = target;
dinnerProxy.dinnerInterceptor =dinnerInterceptor ;
Object proxy = Proxy.newProxyInstance(
//类加载器
target.getClass().getClassLoader(),
//将代理对象下发到什么接口下
target.getClass().getInterfaces(),
//使用dinnerProxy的invoke方法作为代理逻辑
dinnerProxy);
rerurn proxy ;
}
/**
*代理对象的逻辑
*@param proxy---代理对象
*@param method---方法
*@param args ----参数
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
/****没有拦截器的实现方式**/
/*System.out.println("洗手");
Object obj = method.invoke(target,args);
System.out.println("收拾剩饭");
System.out.println("收拾残局");*/
/****增加拦截器实现方式**/
this.dinnerInterceptor.before();
Object obj = null;
try{
obj = methdo.invoke(target,args);
}catch(){
flag = true;
}finally{
this.dinnerInterceptor.after();
}
if(flag){
this.dinnerInterceptor.afterThrowing();
}else{
this.dinnerInterceptor.afterReturning();
}
}
}
public class AopMain{
public void static main(String[] args){
//目标对象
DinnerService target = new LanuchServiceImpl();
//拦截器
DinnerInterceptorImpl interceptoy = new DinnerInterceptorImpl ();
//这个是获取到代理对象和目标对象的关联关系,关联起来后,代理对象就可以操作目标对象的方法了。有拦截器就追加拦截器,增强对目标对象的控制,没有也是可以的。
DinnerService proxy = (DinnerService)DinnerProxy.bind(target,interceptoy);
proxy.hava();
}
}
//拦截器的方法
public Interface DinnerInterceptor{
public void before();
public void after();
public void afterReturning();
public void afterThrowing();
}
//拦截器的方法
public class DinnerInterceptorImpl implements DinnerInterceptor{
public void before(){System.out.println("洗手")};
public void after(){System.out.println("清洗餐具")};
public void afterReturning(){System.out.println("收拾剩饭")};
public void afterThrowing(){System.out.println("处理急事去了")};
}
对于普通开发者来说,我们只需要知道执行的流程,还有暴露的接口,而里边的具体实现动态代理的细节,这个就是设计者考虑的逻辑,因为这些逻辑可能很抽象。简单来说,就是我们需要知道操作的流程图是怎么样的,还有需要调用的AOP接口。
现在的你是否已经对AOP有初步的印象了呢?当然了,这里只是一个前菜,只是作为一个小的了解,下来我们会正式的学习AOP的一些重点的概念并进行实践。