Spring AOP (面向切面编程)
主要用于事务控制、权限检查、日志…等
分类(按修改的时机):
静态AOP实现:AOP框架在编译阶段即实现对目标类的修改(增强),生成静态的AOP代理类(生成*.class文件已经被改掉了,需要使用特定的编辑器)。以AspectJ(需要安装 java -jar aspectj-1.9.2.jar,并添加环境变量和CLASSPATH(aspectjrt.jar、aspectjtools.jar))为代表。
动态AOP实现:AOP框架在运行阶段动态生成AOP代理(在内存中动态地生成AOP代理类:JDK动态代理、cglib、javassist),以实现对目标对象的增强。以Spring AOP为代表。
静态AOP性能更好,动态AOP更方便。
AOP相关概念:
切面(Aspect):业务流程运行的某个特定步骤,也就是应用运行过程的关注点。关注点可能横切多个对象,所以常常也称为横切关注点。
连接点(Joinpoint):程序执行过程中明确的点,如方法的调用,或者异常的抛出。Spring AOP中,连接点总是方法的调用,
增强处理(Advice):AOP框架在特定的切入点执行的增强动作。处理有“around”、“before”和“after”等类型。
切入点(Pointcut):可以插入增强处理的连接点。简而言之,当某个连接点满足指定要求时,该连接点将被添加增强处理,该连接点也就变成了切入点。
引入(Introduction):为被修改的类添加方法或成员变量。Spring允许引入新的接口到任何被处理的对象。例如,你可以使用一个引入,使任何对象实现IsModified接口,以此来简化缓存。
目标对象:被AOP框架进行增强处理的对象,也被成为被增强对象。如果AOP框架是通过运行时代理来实现的,那这个对象僵尸一个被代理的对象。
AOP代理:AOP框架创建的对象,简单地说,代理就是对目标对象的加强。Spring中的AOP代理可以是JDK的动态代理,也可以是CGLIB代理。前者为实现接口的目标对象的代理,后者为不实现接口的目标对象的代理。
织入(Weaving):将增强处理添加到目标对象中、并创建一个被增强的对象(AOP代理)的过程就是织入。织入有两种实现方式:编译时增强(例如AspectJ)和运行时增强(例如CGLIB)。Spring和其他船Java AOP框架一样,在运行时完成织入。
AOP配置:
定义Aspect:(3种方式)
注解、XML配置、将class改成aspect
定义Advice:(3种方式)
注解、XML配置、将方法签名改成特殊语法(例如:before():execution(* com.lwy.service.*.*(..)))
- XML配置实例:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="musicService" class="com.lwy.service.MusicService" />
<bean id="authAspect" class="com.lwy.aspect.AuthAspect" />
<aop:config>
<!-- 将指定的Bean转成Aspect切面 -->
<aop:aspect ref="authAspect">
<!-- 将auth方法转换成Before的Advice -->
<!-- 将Advice放到目标方法的指定位置 pointcut或pointcut-ref -->
<aop:before method="auth" pointcut="execution(* com.lwy.service.*.*(..))" />
</aop:aspect>
</aop:config>
</beans>
- 注解配置实例:
用注解时需要注意两点:
- 需要添加<aop:aspectj-autoproxy />元素
- 强制Spring去处理@Aspect的注解
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="com.lwy">
<!-- 告诉Spring去处理Aspect注解 -->
<context:include-filter type="annotation" expression="org.aspectj.lang.annotation.Aspect" />
</context:component-scan>
<aop:aspectj-autoproxy />
</beans>
package com.lwy.aspect;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class AuthAspect {
@Before(value="execution(* com.lwy.service.*.*(..))")
public void auth() {
System.out.println("模拟权限验证");
}
}
package com.lwy.service;
import org.springframework.stereotype.Component;
@Component
public class MusicService {
public void listenMusicService() {
System.out.println("模拟听音乐服务");
}
}