Spring AOP配置日志打印基础准备
- 三个核心包
- spring-aop:AOP核⼼功能,例如代理⼯⼚
- aspectjweaver:简单理解,⽀持切⼊点表达式
- aspectjrt:简单理解,⽀持aop相关注解
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.11</version>
</dependency>
- 添加schema
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.2.xsd"
xmlns:aop="http://www.springframework.org/schema/aop">
基于XML环境配置
- 配置横切关注点
public class TimeHandler {
public void printBefore(){
System.out.println("printBefore:"+ LocalDateTime.now().toString());
}
public void printAfter(){
System.out.println("printAfter:"+ LocalDateTime.now().toString());
}
}
配置接口和实现类
public interface VideoService {
public Video findById(int id);
public int save(Video video);
}
public class VideoServiceImpl implements VideoService {
@Override
public Video findById(int id) {
System.out.println("findById调用");
return null;
}
@Override
public int save(Video video) {
System.out.println("save调用");
return 1;
}
}
织入
<bean id="timeHandler" class="cn.junko.aop.TimeHandler"/>
<bean id="videoService" class="cn.junko.service.VideoServiceImpl"/>
<!--aop配置-->
<aop:config>
<!--横切关注点-->
<aop:aspect id="timeAspect" ref="timeHandler">
<!--定义切入点表达式-->
<aop:pointcut id="allMethod" expression="execution(* cn.junko.service.VideoService.*(..))"/>
<!--配置通知-->
<aop:before method="printBefore" pointcut-ref="allMethod" />
<aop:after method="printAfter" pointcut-ref="allMethod" />
</aop:aspect>
</aop:config>
当需要多个关注点的时候,可以配置多个横切关注点
基于注解配置
声明切⾯类 @Aspect(切⾯): 通常是⼀个类,⾥⾯可以定义切⼊点和通知
配置切入点和通知,并且开启Spring AOP注解和扫描
@Component
//告诉spring这是一个切面类,里面可以定义切入点和通知
@Aspect
public class LogAdvice {
@Pointcut("execution(* cn.junko.service.VideoService.*(..)))")
public void aspect(){
}
@Before("aspect()")
public void beforeLog(){
System.out.println("前置通知执行了");
}
@After("aspect()")
public void AfterLog(){
System.out.println("后置通知执行了");
}
}
@Configuration //标记这是一个配置类
@ComponentScan("cn.junko")
@EnableAspectJAutoProxy //开启spring对aspect的支持
public class AnnotationConfig {
}
public class AnnotationTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AnnotationConfig.class);
// //扫描包路径,当扫描的类有注解将自动加入到容器
// context.scan("cn.junko");
// //实例化,里面完成初始化操作
// context.refresh();
VideoService videoServiceImpl = (VideoService) context.getBean("videoServiceImpl");
videoServiceImpl.findById(3);
Video video = (Video) context.getBean("video");
VideoOrder videoOrder = (VideoOrder) context.getBean("videoOrder");
}
}
因为我们有了一个配置类,并且在new的时候传入进去AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AnnotationConfig.class);
告诉他spring负责扫描的包与开启注解,所以就不需要下面两行代码了
// //扫描包路径,当扫描的类有注解将自动加入到容器
// context.scan("cn.junko");
// //实例化,里面完成初始化操作
// context.refresh();
AOP的环绕通知案例
配置环绕通知:打印⽅法请求耗时时间
环绕通知获取⽬标⽅法和参数
/**
* 环绕通知
*/
@Around("aspect()")
public void around(JoinPoint joinPoint){
Object target = joinPoint.getTarget().getClass().getName();
System.out.println("调用者是:"+target);
System.out.println("调用方法是:"+joinPoint.getSignature());
//joinPoint获取参数
Object[] args = joinPoint.getArgs();
System.out.println("参数为:"+args[0]);
long start = System.currentTimeMillis();
System.out.println("环绕通知前");
//执行连接点的方法
try {
Object proceed = ((ProceedingJoinPoint) joinPoint).proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("环绕通知后");
System.out.println("调用时长:"+(end-start));
}
}