Spring中有两大重心:springIoc和springAop
springioc将bean的控制权交给了spring管理,直接从spring中获取,通过五大注解来告诉spring帮我管理这个对象。通过@Autowired和构造方法和set方法注入。
不仅仅是学习重点也是面试常考的难点。
springAop(难点):
aop是面向切面编程,和面向对象编程不是互斥也不是升级,而是补充。
AOP是⼀种思想, 它的实现⽅法有很多, 有Spring AOP,也有AspectJ、CGLIB等.
在这里我们想做一个Aop切面,让我们即使不用修改原本的代码也能够做到记录程序运行时间的方法。
第一步:使用AOP要先引入依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId>
</dependency>
第二步:引入一个切面(一类特定问题)
package com.syx.book.aspect;import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;@Component
@Aspect
public class TimeRecordAspect {
}
引入@Aspect注解,spring使用了AspectJ(第三方的jar包,类似于lombok)注解,但是实际上是spring实现的。
package com.syx.book.aspect;import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Slf4j
@Component
@Aspect
public class TimeRecordAspect {//记录耗时//作用范围@Around()@Around("execution(* com.syx.book.Controller.*.*(..))")public Object timeRecord(ProceedingJoinPoint joinPoint) throws Throwable {long start=System.currentTimeMillis();Object proceed = joinPoint.proceed();long end=System.currentTimeMillis();log.info("耗时时间"+(end-start)+"ms");return proceed;}
}
在这里就可以看到,我们并没有在原本代码上面改变,但是却能够同样实现时间耗时功能。
1. @Aspect: 标识这是⼀个切⾯类2. @Around: 环绕通知, 在⽬标⽅法的前后都会被执⾏. 后⾯的表达式表⽰对哪些⽅法进⾏增强.(侵入程序的时机,目标前后都会执行)3. ProceedingJoinPoint.proceed() 让原始⽅法执⾏
springAop核心概念介绍:
1.切点:一种规则
2.连接点:符合规则的对象
与切点的关系:切点是对连接点的一种筛选。所有的连接点构成了程序执行过程中的可能的关注点,而切点则用于从这些众多的连接点中挑选出符合特定条件的那些点,然后在这些挑选出来的连接点上应用切面的通知。
3.通知:方法内部的逻辑
表示连接点具体要做的事情(也就是方法里面咱们程序员写的逻辑等等),被叫做方法。
通知的几种类型:
- @Around: 环绕通知, 此注解标注的通知⽅法在⽬标⽅法前, 后都被执⾏
- @Before: 前置通知, 此注解标注的通知⽅法在⽬标⽅法前被执⾏
- @After: 后置通知, 此注解标注的通知⽅法在⽬标⽅法后被执⾏, ⽆论是否有异常都会执⾏
- @AfterReturning: 返回后通知, 此注解标注的通知⽅法在⽬标⽅法后被执⾏, 有异常不会执行
- @AfterThrowing: 异常后通知, 此注解标注的通知⽅法发⽣异常后执⾏
4.切面:符合规则做的事情
切点+连接点+通知=切面。
通知的几种介绍:
1.before和after同理 :
这是切面的设置以及切面的逻辑
package com.syx.aop.aspect;import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;@Slf4j
@Component
@Aspect
public class AspectDemo {//作用的范围是TestController@Before("execution(* com.syx.aop.Controller.*.*(..))")public void doBefore(){log.info("do before..........");}}
package com.syx.aop.Controller;import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("test")
public class TestController {@RequestMapping("doBefore")public String t1(){return "t1";}
}
下面表示调用t1方法然后就会打印日志。
doBefore是在程序执行之前打印。
2.Around
around是要求我们在切面配置的时候要求我们要返回一个object
@Around("execution(* com.syx.aop.Controller.*.*(..))")public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {log.info("do Around.............");Object proceed = joinPoint.proceed();log.info("do Around.............");return proceed;}}
Around必须要有返回函数。否则会没有返回值
在这里我们会发现假如同时配置了before after和around时候,around会优先执行。
3.AfterReturn
当接口正常的时候会先执行afterreturn
5.AfterThrowing
如果有异常的话比如在这里我们调用的时候出现了一个算数异常10/0,就不会执行AfterReturn和最后的Around而是直接执行AfterThrowing。
before和after不管咋样都会执行。
在这里的@Aspect中就有很多切面类。
6.pointcut
描述切点,在这里通过注释@pointcut描述
@Slf4j
@Component
@Aspect
public class AspectDemo {@Pointcut("execution(* com.syx.aop.Controller.*.*(..))")public void pt(){}//作用的范围是TestController@Before("pt()")public void doBefore(){log.info("do before..........");}
在下面在注解后写入pt()即可 。
如果其他类中需要使用这里的pt()方法必须要指定路径,,全限定路径。
如果有多个切面作用在同一个切点上,就会按照名称进行排序。这时候我们要用@order注解
7.order
数字越大级别越低,before的时候数字越小先执行。