① 注解
和 XML 配置文件一样,注解本身并不能执行,注解本身仅仅只是做一个标记,具体的功能是框架检测到注解标记的位置,然后针对这个位置按照注解标记的功能来执行具体操作。
本质上:所有一切的操作都是Java代码来完成的,XML和注解只是告诉框架中的Java代码如何执行。
② 扫描
Spring 为了知道程序员在哪些地方标记了什么注解,就需要通过扫描的方式,来进行检测。然后根据注解进行后续操作。
一、SpringIOC 常用注解
四个典型注解没有本质区别:对于Spring使用IOC容器管理这些组件来说没有区别。所以@Controller、@Service、@Repository这三个注解只是给开发人员看的,让我们能够便于分辨组件的作用。
注意:虽然它们本质上一样,但是为了代码的可读性,为了程序结构严谨我们肯定不能随便胡乱标记。
1. 使用@Component注解标记的普通组件
通过查看源码我们得知,@Controller、@Service、@Repository这三个注解只是在@Component注解的基础上起了三个新的名字。
@Component
public class CommonComponent {
}
2. 使用@Controller注解标记的控制器组件
这个组件就是我们在三层架构中表述层里面,使用的控制器。以前是Servlet,以后我们将会使用Controller来代替Servlet。
@Controller
public class SoldierController {
}
3. 使用@Service注解标记的业务逻辑组件
这个组件就是我们在三层架构中使用的业务逻辑组件。
@Service
public class SoldierService {
}
4. 使用@Repository注解标记的持久化层组件
这个组件就是我们以前用的Dao类,但是以后我们整合了Mybatis,这里就变成了Mapper接口,而Mapper接口是由Mybatis和Spring的整合包负责扫描的。
由于Mybatis整合包想要把Mapper接口背后的代理类加入Spring的IOC容器需要结合Mybatis对Mapper配置文件的解析,所以这个事情是Mybatis和Spring的整合包来完成,将来由Mybatis负责扫描,也不使用@Repository注解。
@Repository
public class SoldierDao {
}
5. 组件的beanName
在我们使用XML方式管理bean的时候,每个bean都有一个唯一标识,便于在其他地方引用。现在使用注解后,每个组件仍然应该有一个唯一标识。
① 默认情况
类名首字母小写就是bean的id。例如:SoldierController类对应的bean的id就是soldierController。
@Controller
public class SoldierController {
}
② 使用value属性指定
@Controller(value = "tianDog")
public class SoldierController {
}
当注解中只设置一个属性时,value属性的属性名可以省略:
@Service("smallDog")
public class SoldierService {
}
二、SpringIOC 注入bean的注解
1. 自动装配的实现前提
参与自动装配的组件(需要装配别人、被别人装配)全部都必须在IOC容器中。
2. @Autowired注解
在成员变量上直接标记@Autowired注解即可,不需要提供setXxx()方法。
以后我们在项目中的常用的正式用法就是以下这样:
@Controller
public class SoldierController {
@Autowired
private SoldierService soldierService;
public void getMessage() {
soldierService.getMessage();
}
}
3. @Autowired注解其他细节
① 标记在构造器
@Controller(value = "tianDog")
public class SoldierController {
private SoldierService soldierService;
@Autowired
public SoldierController(SoldierService soldierService) {
this.soldierService = soldierService;
}
……
② 标记在setXxx()方法
@Controller("tianDog")
public class SoldierController {
private SoldierService soldierService;
@Autowired
public void setSoldierService(SoldierService soldierService) {
this.soldierService = soldierService;
}
……
4. @Autowired工作流程
-
首先根据所需要的组件类型到IOC容器中查找
-
能够找到唯一的bean:直接执行装配
-
如果完全找不到匹配这个类型的bean:装配失败
-
和所需类型匹配的bean不止一个
-
没有@Qualifier注解:根据@Autowired标记位置成员变量的变量名作为bean的id进行匹配
- 能够找到:执行装配
- 找不到:装配失败
-
使用@Qualifier注解:根据@Qualifier注解中指定的名称作为bean的id进行匹配
- 能够找到:执行装配
- 找不到:装配失败
-
-
@Qualifier注解:根据@Qualifier注解中指定的名称作为bean的id进行匹配
@Controller(value = "tianDog")
public class SoldierController {
@Autowired
@Qualifier(value = "maomiService222")
// 根据面向接口编程思想,使用接口类型引入Service组件
private ISoldierService soldierService;
5. @Autowired注解佛系装配
给@Autowired注解设置required = false属性表示:能装就装,装不上就不装。但是实际开发时,基本上所有需要装配组件的地方都是必须装配的,用不上这个属性。
@Controller(value = "tianDog")
public class SoldierController {
// 给@Autowired注解设置required = false属性表示:能装就装,装不上就不装
@Autowired(required = false)
private ISoldierService soldierService;
6. @Configuration注解 创建配置类
使用@Configuration注解将一个普通的类标记为Spring的配置类。
@Configuration
public class MyConfiguration {
}
7. @Bean注解
@Bean注解相当于XML配置文件中的bean标签
@Bean注解标记的方法的返回值会被放入IOC容器
@Configuration
public class MyConfiguration {
// @Bean注解相当于XML配置文件中的bean标签
// @Bean注解标记的方法的返回值会被放入IOC容器
@Bean
public CommonComponent getComponent() {
CommonComponent commonComponent = new CommonComponent();
commonComponent.setComponentName("created by annotation config");
return commonComponent;
}
}
8. @ComponentScan注解
@ComponentScan注解 在配置类中配置自动扫描的包
@Configuration
@ComponentScan("com.liush.ioc.component")
public class MyConfiguration {
……
9. Junit4和Junit5注解
Junit4注解
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(value = {"classpath:applicationContext.xml"}) public class AOPTest {}
Junit5注解
@ExtendWith(SpringExtension.class) 表示使用 Spring 提供的扩展功能。 @ContextConfiguration(value = {"classpath:spring-context.xml"}) 还是用来指定 Spring 配置文件位置,和整合 junit4 一样。
@SpringJUnitConfig 注解综合了前面两个注解的功能,此时指定 Spring 配置文件位置即可。但是注意此时需要使用 locations 属性,不是 value 属性了。
@SpringJUnitConfig(locations = {"classpath:spring-context.xml"}) public class Junit5IntegrationTest {}
JUnit4 | JUnit5 | 说明 |
---|---|---|
@Test | @Test | 表示该方法是一个测试方法。JUnit5与JUnit 4的@Test注解不同的是,它没有声明任何属性,因为JUnit Jupiter中的测试扩展是基于它们自己的专用注解来完成的。这样的方法会被继承,除非它们被覆盖 |
@BeforeClass | @BeforeAll | 表示使用了该注解的方法应该在当前类中所有使用了@Test @RepeatedTest、@ParameterizedTest或者@TestFactory注解的方法之前 执行; |
@AfterClass | @AfterAll | 表示使用了该注解的方法应该在当前类中所有使用了@Test、@RepeatedTest、@ParameterizedTest或者@TestFactory注解的方法之后执行; |
@Before | @BeforeEach | 表示使用了该注解的方法应该在当前类中每一个使用了@Test、@RepeatedTest、@ParameterizedTest或者@TestFactory注解的方法之前 执行 |
@After | @AfterEach | 表示使用了该注解的方法应该在当前类中每一个使用了@Test、@RepeatedTest、@ParameterizedTest或者@TestFactory注解的方法之后 执行 |
@Ignore | @Disabled | 用于禁用一个测试类或测试方法 |
@Category | @Tag | 用于声明过滤测试的tags,该注解可以用在方法或类上;类似于TesgNG的测试组或JUnit 4的分类。 |
@Parameters | @ParameterizedTest | 表示该方法是一个参数化测试 |
@RunWith | @ExtendWith | @Runwith就是放在测试类名之前,用来确定这个类怎么运行的 |
@Rule | @ExtendWith | Rule是一组实现了TestRule接口的共享类,提供了验证、监视TestCase和外部资源管理等能力 |
@ClassRule | @ExtendWith | @ClassRule用于测试类中的静态变量,必须是TestRule接口的实例,且访问修饰符必须为public。 |
三、SpringAOP 常用注解
1. @Aspect注解:表示这个类是一个切面类
@Order(2)注解:表示切面的优先级
- @Order(较小的数):优先级高
- @Order(较大的数):优先级低
@Component
@Aspect //表明当前是一个切面类
public class WuDaAspect {
//1.获取连接点的信息
@Before("execution(* *Bing(..))")
public void song(JoinPoint joinPoint){
//joinPoint称之为连接点
//1.获取方法签名
Signature signature = joinPoint.getSignature();
System.out.println(signature.getName());
System.out.println(signature.getModifiers());
System.out.println(signature.getDeclaringType().getName());
//2.获取目标方法的实际参数
Arrays.asList(joinPoint.getArgs()).forEach(System.out::println);
}
//2.获取目标方法的返回值信息
@AfterReturning(value = "execution(* *Bing(..))",returning = "number")
public void song2(Integer number){
System.out.println("目标方法的返回值是:"+number);
}
//3.获取目标方法的异常信息
@AfterThrowing(value = "execution(* *Bing(..))",throwing = "throwable")
public void song3(Throwable throwable){
System.out.println("得到的异常信息:"+throwable.getMessage());
System.out.println("没事没事,高蛋白!");
}
}
2. @Before注解:在方法执行之前执行(方法上)
value属性:切入点表达式,告诉Spring当前通知方法要套用到哪个目标方法上
@Before("execution(* *Bing(..))")
3. @After注解: 在方法执行之后执行(方法上)
从spring5.3.x开始,增强执行顺序是:
@Before
@AfterReturning 或者 @AfterThrowing
@After
@Component
@Aspect
public class WuDaAspect {
@Before("execution(* *Bing(..))")
public void song(){
System.out.println("1.送大麦茶...");
}
@AfterReturning("execution(* *Bing(..))")
public void song2(){
System.out.println("2.送玫瑰茶");
}
@AfterThrowing("execution(* *Bing(..))")
public void song3(){
System.out.println("3.送茉莉花茶");
}
@After("execution(* *Bing(..))")
public void song4(){
System.out.println("4.送菊花茶...");
}
}
4. @AfterReturning注解标记返回通知方法
在返回通知中,通过@AfterReturning注解的returning属性获取目标方法的返回值
在返回通知中获取目标方法返回值分两步:
第一步:在@AfterReturning注解中通过returning属性设置一个名称
第二步:使用returning属性设置的名称在通知方法中声明一个对应的形参
// @AfterReturning注解标记返回通知方法
// 在返回通知中获取目标方法返回值分两步:
// 第一步:在@AfterReturning注解中通过returning属性设置一个名称
// 第二步:使用returning属性设置的名称在通知方法中声明一个对应的形参
@AfterReturning(
value = "execution(public int com.liush.aop.api.Calculator.add(int,int))",
returning = "targetMethodReturnValue"
)
public void printLogAfterCoreSuccess(JoinPoint joinPoint, Object targetMethodReturnValue) {
String methodName = joinPoint.getSignature().getName();
System.out.println("[AOP返回通知] "+methodName+"方法成功结束了,返回值是:" + targetMethodReturnValue);
}
5. @AfterThrowing注解标记异常通知方法
在异常通知中,通过@AfterThrowing注解的throwing属性获取目标方法抛出的异常对象
在异常通知中获取目标方法抛出的异常分两步:
第一步:在@AfterThrowing注解中声明一个throwing属性设定形参名称
第二步:使用throwing属性指定的名称在通知方法声明形参,Spring会将目标方法抛出的异常对象从这里传给我们
// @AfterThrowing注解标记异常通知方法
// 在异常通知中获取目标方法抛出的异常分两步:
// 第一步:在@AfterThrowing注解中声明一个throwing属性设定形参名称
// 第二步:使用throwing属性指定的名称在通知方法声明形参,Spring会将目标方法抛出的异常对象从这里传给我们
@AfterThrowing(
value = "execution(public int com.liush.aop.api.Calculator.add(int,int))",
throwing = "targetMethodException"
)
public void printLogAfterCoreException(JoinPoint joinPoint, Throwable targetMethodException) {
String methodName = joinPoint.getSignature().getName();
System.out.println("[AOP异常通知] "+methodName+"方法抛异常了,异常类型是:" + targetMethodException.getClass().getName());
}
6. @Around注解:标明环绕通知方法
环绕通知对应整个try...catch...finally结构,包括前面四种通知的所有功能。
@Around(value = "com.liush.spring.aop.aspect.LogAspect.declarPointCut()")
public Object roundAdvice(ProceedingJoinPoint joinPoint) {
7. @PointCut注解:切入点表达式重用
在一处声明切入点表达式之后,其他有需要的地方引用这个切入点表达式。易于维护,一处修改,处处生效。声明方式如下:
// 切入点表达式重用
@Pointcut("execution(* *..*.add(..))")
public void declarPointCut() {}
切点表达式的语法:
① 用*号代替“权限修饰符”和“返回值”部分表示“权限修饰符”和“返回值”不限
* *Bing(..) 第一个*表示访问修饰符和返回值类型不限
public void *Bing(..) 访问修饰符必须是public,返回值类型必须是void
* void *Bing(..) 错误写法 , 比较特殊的是,这种写法是允许的: public * *Bing(..)
② 在包名部分,*代表某一层包任意。
例如: com.liush.dao.*.*.*Bing(..) com.atguigu.dao包下的任意子包(有且只有一层),第二个*代表任意类名
③ 在包名部分,*..代表任意层的包
例如: com.liush.*..*.*Bing(..) com.atguigu下任意子包(层数也是任意的)
④ 在类名部分,*代表任意类名称,也可以代表部分类名称
例如:com.liush.dao.User*.*(..)
com.liush.dao.*.add(..)
⑤ 在方法名部分:*代表方法名任意,也可以代表方法名的部分任意
例如:com.liush.service.impl.UserServiceImpl.get*(..) 表示UserServiceImpl下的get方法
⑥ 在方法的参数部分:
(..) 参数个数和类型任意
(int,..) 第一个参数必须是int,后面的参数任意
(int,..) 和(Integer,..)不是一回事
⑦ 在方法的访问修饰符和返回值部分:
public int *..*.*(..) 所有的public修饰的方法,而且要求返回值类型是int
* int *..*.*(..) 错误写法,因为第一个*已经表明访问修饰符和返回值类型不限制
特殊的,这个是正确的: public * *..*.*(..)
⑧ 切点表达式中也是支持逻辑运算符的: && || !
execution(* com.liush.book.service.impl.User*.*(..)) || execution(* com.liush.book.service.impl.Book*.*(..))
8. 事务的注解
① 事务基本注解:只读、回滚、超时
@Transactional
@Transactional(readOnly = true)
- readOnly = true:把当前事务设置为只读
@Transactional(readOnly = false, timeout = 3)
- readOnly = false:把当前事务设置为非只读
- timeout = 3:过三秒超时自动结束事务
@Transactional(rollbackFor = Exception.class)
- rollbackFor属性:需要设置一个Class类型的对象
- rollbackForClassName属性:需要设置一个字符串类型的全类名
- rollbackFor = Exception.class,noRollbackFor = FileNotFoundException.class:除了 FileNotFoundException 之外,其他所有 Exception 范围的异常都回滚;但是碰到 FileNotFoundException 不回滚。
② 事务隔离级别
isolation属性:设置事务的隔离级别
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
- READ_UNCOMMITTED:读未提交
@Transactional(isolation = Isolation.READ_COMMITTED)
- READ_COMMITTED:读已提交
@Transactional(isolation = Isolation.Repeatable_Read)
- Repeatable_Read:可重复读
@Transactional(isolation = Isolation.SERIALIZABLE)
- SERIALIZABLE:序列化
③ 事务传播行为
- propagation属性:设置事务的传播行为
@Transactional(propagation = Propagation.REQUIRED)
@Transactional(propagation = Propagation.SUPPORTS)
@Transactional(propagation = Propagation.MANDATORY)
@Transactional(propagation = Propagation.REQUIRES_NEW)
@Transactional(propagation = Propagation.NOT_SUPPORTED)
@Transactional(propagation = Propagation.NEVER)
@Transactional(propagation = Propagation.NESTED)
四、SpringMVC 常用注解
1. @RequestMapping
@RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
@RequestMapping注解的作用就是将请求 和 处理请求的 控制器方法 关联起来,建立映射关系。
SpringMVC 接收到指定的请求,就会来找到在映射关系中对应的控制器方法来处理这个请求。
2. @RequestMapping
@RequestMapping(value = "/emp",method = RequestMethod.GET)
@GetMapping("/emp")
@RequestMapping(value = "/emp",method = RequestMethod.POST)
@POSTMapping("/emp")
@RequestMapping注解的作用就是将请求 和 处理请求的 控制器方法 关联起来,建立映射关系。
SpringMVC 接收到指定的请求,就会来找到在映射关系中对应的控制器方法来处理这个请求。属性:
- value:指定为形参赋值的请求参数的参数名。
- required:设置是否必须传输此请求参数,默认值为true,如果为true没传值则400。
- defaultValue:不管required属性值为true或false,当value所指定的请求参数没有传输或传输的值为""时,则使用默认值为形参赋值。
3. @RequestHander
@RequestHeader是将请求头信息和控制器方法的形参创建映射关系。
通过这个注解获取请求消息头中的具体数据。
@RequestMapping("/request/header")
public String getRequestHeader(
// 使用 @RequestHeader 注解获取请求消息头信息
// name 或 value 属性:指定请求消息头名称
// defaultValue 属性:设置默认值
@RequestHeader(name = "Accept", defaultValue = "missing") String accept
) {
logger.debug("accept = " +accept);
return "target";
}
4. @CookieValue
获取当前请求中的 Cookie 数据。
@RequestMapping("/request/cookie")
public String getCookie(
// 使用 @CookieValue 注解获取指定名称的 Cookie 数据
// name 或 value 属性:指定Cookie 名称
// defaultValue 属性:设置默认值
@CookieValue(value = "JSESSIONID", defaultValue = "missing") String cookieValue,
// 形参位置声明 HttpSession 类型的参数即可获取 HttpSession 对象
HttpSession session
) {
logger.debug("cookieValue = " + cookieValue);
return "target";
}
5. @RequestBody
@RequestBody可以获取请求体,需要在控制器方法设置一个形参,使用@RequestBody进行标识,当前请求的请求体就会为当前注解所标识的形参赋值。
6. @ResponseBody
@ResponseBody用于标识一个控制器方法,可以将该方法的返回值直接作为响应报文的响应体响应到浏览器。
7. @RestController
@RestController注解是springMVC提供的一个复合注解,标识在控制器的类上,就相当于为类添加了@Controller注解,并且为其中的每个方法添加了@ResponseBody注解。
8. @ControllerAdvice
标记为异常处理类(Java代码异常,非Http请求状态异常),一个异常处理类有很多异常处理器。
9. @ExceptionHandler
异常处理器,在异常处理类中声明。
10. @Configuration
声明此类为注解类,可代替xml配置。
11. @PathVariable
如果我们想要获取链接地址中的某个部分的值,就可以使用 @PathVariable 注解。
主要体现在restful风格上了。
12. @RequestParam
主要用于将请求参数区域的数据映射到控制层方法的参数上