0. AOP
AOP是一种编程范式,通过分离cross-cutting concerns的处理,达到模块化的目的,并使用的地方采用声明的方式即可。有多种实现框架,java语言最常用的AOP框架就是AspectJ和spring AOP。二者的设计目的不同,spring AOP的设计初衷是服务于spring IOC框架,解决常见的AOP问题;而AspectJ就是为了提供完整的AOP解决方案。
另外,二者的weaving方式不同:spring AOP采用runtime weaving,通过目标对象的代理proxy,包括JDK动态代理和CGLIB代理。AspectJ提供了3种方式:编译时weaving(把target和aspect代码结合后进行编译),编译后weaving(二进制weaving),加载时weaving(类似于二进制weaving,只是weaving发生在类加载过程)。
spring AOP引入AspectJ的注解配置方式,但weaving方式仍然保留为runtime weaving。如果要在spring中使用AspectJ的注解进行配置,需要用@EnableAspectJAutoProxy;并且把aspect类用@Aspect进行标注;诸如@PointCut,@Aspect,@Around/@Before/@After,ProceedingJoinPoint等注解和类都是AspectJ提供的。
关键名词:
1)join point:aspect要切入的程序执行点。
2)point cut:用来标识切入点的表达式
3)advice:相当于interceptor,有before/after/around等方式,还支持@AfterReturning,@AfterThrowing等。
4)aspect:定义具体要执行的action,如权限验证。
5)weaving:the process of linking aspects with targeted objects to create an advised object
1. Spring AOP的应用
1)基于接口的权限控制:各个接口都需要处理该问题,如果在各个接口分别处理,会造成重复代码,模糊业务逻辑;通过aop的方式,在需要权限控制的controller action处配置注解,然后写一个aspect来识别带有注解的方法(pointcut),并对它们统一处理权限控制。
2)记录日志:在方法入口记录方法调用与参数;在方法出口记录返回值。
3)缓存
4)事务操作
@Pointcut("execution(public * *.*(..) && @annotation(Permission))") public void annotatedMethods() {}
@Around("annotatedMethods()")public void doSomething(ProceedingJoinPoint joinPoint) {}
2. Spring AOP的底层实现
如果被代理对象有接口,Spring使用JDK动态代理;Spirng默认采用JDK动态代理机制。如果被代理对象没有接口,则使用CGLib。
2.1. JDK动态代理
JDK动态代理设计模式,主要涉及java.lang.reflect包下边的两个类:Proxy和InvocationHandler。InvocationHandler里有一个invoke方法,aspect逻辑写在该方法中,并且该方法还会调用目标方法的逻辑,这部分是通过把目标对象传给InvocationHandler,然后反射调用。
public static Target newProxyInstance(Target target) { return (Target) Proxy.newProxyInstance(JdkDynamicProxyTest.class.getClassLoader(), new Class<?>[]{Target.class}, new JdkDynamicProxyTest(target)); }
使用jdk动态代理只能针对实现了接口的类;因为jdk动态代理生成的代理类会继承Proxy类,java是单继承的,因此无法再继承实现类,只能用实现接口的方式。
2.2 cglib
JDK动态代理的限制在于只能为接口创建代理实例,而对于没有通过接口定义业务方法的类,如何创建动态代理实例哪?答案就是CGLib、Code Generation Library。CGLib采用ASM字节码技术,为目标类创建子类作为代理,在子类中采用方法拦截的技术拦截所有父类方法的调用并顺势的织入横切逻辑,也就是覆盖父类的方法。
此时AOP只能针对public方法,因为private方法无法被继承;另外如果被代理类被final关键字所修饰,也无法代理。
3. Spring AOP的使用注意事项
同类方法调用无法使用切面。破解方法是applicationContext.getBean(xx.Class).methodToCall()
网友评论