文章目录
- Spring AOP概述及其实现机制
- Spring AOP概述
- Spring AOP的实现机制
- 设计模式之代理模式
- 动态代理
- 动态字节码生成
- 小结
Spring AOP概述及其实现机制
同OOP一样,AOP也是一种解决问题的思路或者理念;仅有理论是不够的,还需要付诸实践,接下来我们将了解到的便是Spring对AOP的实现;
在上一篇文章中,我们介绍了AOP诞生的背景和一些基本概念;现在我们将学习Spring是如何实现这些概念;
如果对AOP的基本概念还不熟悉,建议移步一起来看AOP~。
Spring AOP概述
一般认为,Spring框架的“质量三角”为IoC容器、AOP和轻量级服务集成;Spring AOP以Java作为AOL,学习曲线更为平滑、项目集成更为容易;
它并不提供100%的AOP概念支持,而是以20%的AOP支持实现80%的AOP需求;如果觉得Spring AOP不够强大,那也可以使用AspectJ,Spring对其也提供了很好的集成支持;
Spring AOP从框架发布以来,就保持其稳定的AOP模型,即便后来支持AspectJ,但是总的设计和实现依旧延续最初的设想——动态代理和字节码生成机制;
Spring AOP的实现机制
Spring AOP属于第二代AOP,即动态AOP;它通过在运行时将横切逻辑织入目标对象,为目标对象生成一个代理对象,系统最终使用该代理对象来完成AOP和OOP的结合,即织入过程;
这里就不得不提代理模式啦;
设计模式之代理模式
代理对象将访问者和被访问者之间的交互进行隔离;
代理通常拥有被代理者的全部职能,所以访问者访问代理对象即可获得相应的结果;对于代理能处理的请求,代理就会完成,如果不能处理再交给被访问者处理即可;
SubjectProxy即为代理对象,它除了对请求进行转发外,更多时候是对请求添加访问控制;系统使用代理对象的时候,原来对象的逻辑就和横切逻辑完全融合到一起啦;
代理模式还可以细分,所根据的依据包括代理对象如何产生(运行时?编译时?)以及Client能否和真是对象交互等;
Spring AOP就是通过代理模式来实现AOP与OOP的结合——织入;
动态代理
还记得Pointcut吗?它描述了一组Joinpoint,而这一组Joinpoint将织入相同的横切逻辑;
也就是需要被代理的对象会有很多,手动为所需要代理的对象创建代理对象将变得不切实际。处理这种情况的一种解决方法就是动态生成代理对象嘛,这种代理模式也被称为动态代理;(嗯,从写死到写活,只需要一个完成该任务的程序)
通过动态代理机制,我们将可以为实现特定接口的所有类在系统运行期间动态生成代理对象,从而帮助我们从静态代理实现AOP过渡到动态AOP;
Java为动态代理提供了相应支持:Proxy类和Invocation Handler接口;
当Proxy动态生成的代理对象上相应的接口方法被调用时,Invocation Handler就会拦截对应的方法调用,并进行相应的处理;
动态代理虽然强大,但是其只能针对实现了相应接口的类进行代理,如果目标对象没有实现任何接口,动态代理就无能为力了;
Spring AOP默认情况下,如果目标对象实现了某个接口,那么就会采用动态规划;否则将使用CGLIB动态字节码增强的方法为目标对象生成代理;
动态字节码生成
通过动态字节码生成技术进行织入的原理是继承;通过继承,为目标对象实现一个加入了横切逻辑的子类作为目标对象的代理;
使用CGLIB对类进行扩展的唯一限制就是无法对final方法进行复写;
//以下为动态字节码和动态代理模式演示代码所需要的实体类
public interface IWorker {
void work();
}
public class Coder implements IWorker {
public void work() {
System.out.println("996?不要!");
}
}
public class Manager implements IWorker {
public void work() {
System.out.println("他们必须996!");
}
}
public class MyAdvisor {
public static boolean giveAdvice(){
Calendar calendar=Calendar.getInstance();
boolean result=true;
System.out.println("今天是星期"+(calendar.get(Calendar.DAY_OF_WEEK)-1));
if(calendar.get(Calendar.DAY_OF_WEEK)>=Calendar.MONDAY
&&calendar.get(Calendar.DAY_OF_WEEK)<=Calendar.FRIDAY){
System.out.println("今天正常工作!");
}else if(calendar.get(Calendar.DAY_OF_WEEK)==Calendar.SATURDAY){
System.out.println("今天加班,哈哈哈!");
}else{
System.out.println("我们从来不997!今天休息");
result=false;
}
return result;
}
}
//cglib实现aop
public class WorkerCallback implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
if(method.getName().equals("work")){
if(MyAdvisor.giveAdvice()){
return methodProxy.invokeSuper(o,args);
}
}
return null;
}
}
public class Main {
public static void main(String[] args){
Enhancer enhancer=new Enhancer();
enhancer.setSuperclass(Coder.class);
enhancer.setCallback(new WorkerCallback());
Coder coder=(Coder)enhancer.create();
coder.work();
}
}
//动态代理模式实现aop
public class MyInvocationHandler implements InvocationHandler {
private IWorker worker;
public MyInvocationHandler(IWorker worker) {
this.worker = worker;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if(method.getName().equals("work")){
if(MyAdvisor.giveAdvice()){
return method.invoke(worker,args);
}
}
return null;
}
}
public class Main {
public static void main(String[] args){
IWorker worker=(IWorker) Proxy.newProxyInstance(Main.class.getClassLoader(),
new Class[]{IWorker.class},
new MyInvocationHandler(new Coder()));
worker.work();
worker=(IWorker) Proxy.newProxyInstance(Main.class.getClassLoader(),
new Class[]{IWorker.class},
new MyInvocationHandler(new Manager()));
worker.work();
}
}
小结
再详细介绍Spring AOP的内容之前,我们首先对Spring AOP的实现方式进行了介绍;接下来我们将揭开Spring AOP的神秘面纱;