一. 点睛
AOP:面向切面编程,是相对于OOP面向对象编程而言的。
Spring的AOP的存在目的是为了解耦。AOP可以让一组类共享相同的行为。在OOP中只能通过继承类和实现接口来实现,但是这样的缺点是会使代码的耦合度增加,且类继承只能为单继承,阻碍更多行为添加到一组类上,AOP的出现弥补了OOP的不足。
Spring支持AspectJ的注解式切面编程:
(1) 使用@Aspect注解在类上声明该类是一个切面。
(2) 使用@After,@Before,@Around定义建言(advice),可直接将拦截规则(切点)作为参数。
(3) 其中@After,@Before,@Around参数的拦截规则为切点(PointCut),为了使切点复用,可使用@PointCut专门定义拦截规则,然后在@After,@Before,@Around的参数中调用。
(4) 其中符合条件的每一个被拦截处为连接点(JoinPoint)。
下面将通过模拟记录操作的日志系统的实现来演示基于注解拦截和基于方法规则拦截两种方式。其中注解式拦截能够很好的控制要拦截的粒度和获得更加丰富的信息,Spring本身在事务处理(@Transaction)和数据缓存(@Cacheable等)上面都使用此种形式的拦截。
二. 示例
1. 添加spring aop支持以及AspectJ依赖。
org.springframework
spring-aop
${spring-framework.version}
org.aspectj
aspectjrt
1.8.6
org.aspectj
aspectjweaver
1.8.5
2. 编写拦截规则的注解
package org.light4j.sping4.base.aop;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Action {
String name();
}
代码解释:
这里说下注解,注解本身是没有任何功能的,就和xml是一样的。注解和xml都是一种元数据,元数据即解释数据的数据,这就是所谓的配置。
(3). 编写使用注解的被拦截类
package org.light4j.sping4.base.aop;
import org.springframework.stereotype.Service;
@Service
public class DemoAnnotationService {
@Action(name="注解式拦截的add操作")
public void add(){}
}
(4). 编写使用方法拦截规则的被拦截类
package org.light4j.sping4.base.aop;
import org.springframework.stereotype.Service;
@Service
public class DemoMethodService {
public void add(){}
}
(5). 编写切面
package org.light4j.sping4.base.aop;
import java.lang.reflect.Method;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
@Aspect //①
@Component //②
public class LogAspect {
@Pointcut("@annotation(org.light4j.sping4.base.aop.Action)") //③
public void annotationPointCut(){};
@After("annotationPointCut()") //④
public void after(JoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
Action action = method.getAnnotation(Action.class);
System.out.println("注解式拦截 " + action.name()); //⑤
}
@Before("execution(* org.light4j.sping4.base.aop.DemoMethodService.*(..))") //⑥
public void before(JoinPoint joinPoint){
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
System.out.println("方法规则式拦截,"+method.getName());
}
}
代码解释:
①通过@Aspect注解声明该类是一个切面。
②通过@Component让此切面成为Spring容器管理的Bean。
③通过@Pointcut注解声明切面。
④通过@After注解声明一个建言,并使用@Pointcut定义的切点。
⑤通过反射可以获得注解上面的属性,然后做日志记录相关的操作,下面的相同。
⑥通过@Before注解声明一个建言,此建言直接使用拦截规则作为参数。
(6). 配置类
package org.light4j.sping4.base.aop;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@ComponentScan("org.light4j.sping4.base.aop")
@EnableAspectJAutoProxy //①
public class AopConfig {
}
代码解释:
①使用@EnableAspectJAutoProxy注解开启Spring对AspectJ的支持。
(7). 运行
package org.light4j.sping4.base.aop;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AopConfig.class); //1
DemoAnnotationService demoAnnotationService = context.getBean(DemoAnnotationService.class);
DemoMethodService demoMethodService = context.getBean(DemoMethodService.class);
demoAnnotationService.add();
demoMethodService.add();
context.close();
}
}
运行结果如下图所示:
(8). 源代码示例:
github地址:点击查看
码云地址:点击查看
打赏
微信扫一扫,打赏作者吧~欢迎关注人生设计师的微信公众账号
公众号ID:longjiazuoA