一、JAVA注解总结
1.说明
注解可以增强Java代码,利用反射技术可以扩充实现很多功能,被广泛应用于三大框架底层。
传统我们通过xml文本文件声明方式(但是XML比较繁琐且不易检查),而现在最主流的开发都是基于注解方式,代码量少,框架可以根据注解去自动生成很多代码,从而减少代码量,程序更易读。例如最火爆的SpringBoot就完全基于注解技术实现。
2.注解分类
- JDK自带注解
- 元注解
- 自定义注解
2.1JDK注解
@Override :用来标识重写方法
@Deprecated标记就表明这个方法已经过时了,但我就要用,别提示我过期
@SuppressWarnings(“deprecation”) 忽略警告
@SafeVarargs jdk1.7出现,堆污染,不常用
@FunctionallInterface jdk1.8出现,配合函数式编程拉姆达表达式,不常用
2.2元注解
@Target 注解用在哪里:类上、方法上、属性上等等
@Retention 注解的生命周期:源文件中、字节码文件中、运行中
@Inherited 允许子注解继承
@Documented 生成javadoc时会包含注解,不常用
@Repeatable注解为可重复类型注解,可以在同一个地方多次使用,不常用
2.2.1@Target(ElementType…)
ElementType.TYPE 应用于类的元素 ElementType.METHOD 应用于方法级 ElementType.FIELD
应用于字段或属性(成员变量) ElementType.ANNOTATION_TYPE 应用于注解类型
ElementType.CONSTRUCTOR 应用于构造函数 ElementType.LOCAL_VARIABLE 应用于局部变量
ElementType.PACKAGE 应用于包声明 ElementType.PARAMETER 应用于方法的参数
2.2.2 @Retention(RetentionPolicy…)
该注解定义了自定义注解被保留的时间长短,比如某些注解仅出现在源代码中,而被编译器丢弃;而另一些却被编译在class文件中; 编译在class文件中的注解可能会被虚拟机忽略,而另一些在class被装载时将被读取。
SOURCE 在源文件中有效(即源文件保留) CLASS 在class文件中有效(即class保留) RUNTIME
在运行时有效(即运行时保留)
3.自定义注解
package cn.tedu.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/*本类用于完成自定义注解*/
public class TestAnnotation {
}
//2.通过@Target注解标记自定义注解的使用位置
/*3.通过元注解@Target规定自定义注解可以使用的位置
* 我们使用"ElementType.静态常量"的方式来指定自定义注解具体可以加在什么位置
* 而且,值可以写多个,格式:@Target({ElementType.XXX,ElementType.XXX}*/
@Target({ElementType.METHOD,ElementType.TYPE})//可以加在方法&类上
//3.通过@Retention注解标记自定义注解的生命周期
/*4.通过元注解@Retention规则自定义注解的生命周期
* 我们使用"RetentionPolicy.静态常量"的方式来指定自定义注解的生命周期
* 注意:值只能写一个:SOURCE CLASS RUNTIME 3选1 */
@Retention(RetentionPolicy.RUNTIME)//到运行时都有效
//1.定义自定义注解
/*1.首先注意:注解定义的语法与Java不同
* 2.定义自定义注解的格式:@interface 注解名*/
@interface Rice{
//5.我们可以给注解进行功能增强--添加注解的属性
/*5.注意:int age();不是方法的定义,而是给自定义注解添加了一个age属性*/
//int age();//给自定义注解添加一个普通属性age,类型是int
int age() default 0;//给自定义注解的普通属性赋予默认值0
/*6.注解中还可以添加特殊属性value
* 特殊属性的定义方式与普通属性一样,主要是使用方式不同
* 注意:特殊属性的名字必须叫value,但是类型不做限制
* 特殊属性也可以赋予默认值,格式与普通属性一样,不能简写
* */
//String value();//定义一个特殊属性value,类型是String
String value() default "Lemon";//定义特殊属性并给特殊属性赋予默认值
}
//4.定义一个类用来测试自定义注解
//@Rice
class TestAnno{
/*测试1:分别给TestAnno类 name属性 eat方法都添加Rice注解
* 结论:属性上的注解报错了,说明自定义注解可以加在什么位置,由@Target决定*/
//@Rice//报错了
String name;
/*测试2:当我们给Rice注解添加了一个age属性以后,@Rice注解使用时直接报错
* 结论:当注解没有定义属性时,可以直接使用
* 当注解定义了属性以后,必须给属性赋值,格式:@Rice(age = 10)*/
/*测试3:给age属性赋予默认值以后,可以直接使用@Rice注解
* 不需要给age属性赋值,因为age属性已经有默认值0了*/
/*测试4:给Rice注解添加了特殊属性value以后,必须给属性赋值
* 只不过特殊属性赋值时可以简写成 @Rice("Apple")
* 测试5:如果特殊属性也赋予了默认值,那么可以直接使用这个注解
* 如果要给注解的所有属性赋值,每条赋值都不能简写*/
@Rice(age=10,value="orange")
//@Rice("Apple")
//@Rice(age = 10)
//@Rice(10)//报错,不可以简写,普通属性没有这种格式
public void eat(){
System.out.println("干饭不积极,思想有问题");
}
}
4.单元测试@Test
@Test
单元测试方法:是Java中最小的测试单位,使用灵活
二、Spring常用注解
1.配置类@Configuration
1.1用在方法上@Bean
@Bean是一个方法级别上的注解,主要用在@Configuration注解的类里,也可以用在@Component注解的类里。添加的bean的id为方法名。
将自己的返回值交给Spring容器管理。
案例:
@Configuration //将当前类标识为配置类
public class SpringConfig {//xml
/**1.xml形式
* <bean id="user" class="com.jt.demo.User"></bean>
* 2.注解形式
* Map集合的机构 Map<方法名,方法的返回值>
*/
//@Bean("user1")
@Bean
public User user(){
return new User();//反射机制
}
}
这个配置就等于在xml里的配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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">
<!--
知识点讲解:该配置文件作用是管理对象
术语: bean 被spring容器管理的对象称之为bean
属性说明:
id:是spring容器中对象的唯一标识符,不能重复
class:对象的全路径
-->
<bean id="user" class="com.jt.demo.User"></bean>
</beans>
2.将当前类交给Spring容器管理@Component
@Component 将当前的类,交给Spring容器管理, 对象的创建是由Spring通过反射机制自动创建对象。
3.指定路径包扫描
@ComponentScan(“com.jt”)
@ComponentScan(“com.jt”) 指定扫描的包路径, 可以扫描它的子孙包,用在配置类中
。
4.控制对象单例/多例@Scope
可在配置类中@Bean中添加此注解
@Scope(“singleton”) 默认就是单例模式
@Scope(“prototype”) 设置为多例模式
5.懒加载@Lazy
- 如果Spring容器创建,对象立即创建则该加载方式为“立即加载”,容器启动就创建;
- 如果Spring容器创建,对象在被使用的时候才创建,则称为“懒加载”,对象用时才创建。
@Lazy表示为懒加载
测试说明:主要测试对象中的无参构造什么时候执行!!
只要对象是多例模式,则都是懒加载
在单例模式中加此注解懒加载才有效
6.Spring生命周期注解
6.1.在对象创建之后立即调用@PostConstruct
init()此方法加上@PostConstruct生效
6.2.对象消亡时调用@PreDestroy
destroy()此方法对象消亡时调用
案例:
package com.jt.demo;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
@Component //将对象交给Spring容器管理 key=person value:反射对象
public class Person {
public Person(){
System.out.println("张三出生了,资质拉满");
}
@PostConstruct //在对象创建之后立即调用
public void init(){
System.out.println("张三称为少年奇才");
}
//业务方法
public void doWork(){
System.out.println("迎娶美人鱼!!!");
}
@PreDestroy //对象消亡时 进行调用
public void destory(){
System.out.println("销毁:全世界哀悼");
}
}
7.在对象中需要属性注入@Autowired注解
将Spring容器中的对象注入到属性中,如果需要依赖注入,则对象必须交给Spring容器管理
注入方式:
1.默认是按照类型注入,如果注入的属性是接口,则自动注入实现类的属性
2.按照名称注入(key),一般不用
7.1接口只有一个实现类
编辑Pet接口:
public interface Pet {
void hello();
}
编辑Pet接口实现类:
package com.jt.demo;
import org.springframework.stereotype.Component;
@Component //将对象交给spring容器管理 key:cat value:反射Cat对象
public class Cat implements Pet{
@Override
public void hello() {
System.out.println("我是喵喵喵");
}
}
编辑User类:
package com.jt.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component //将user交给Spring容器管理
public class User {
//效果: 将当前接口的实现类自动注入
@Autowired
private Pet pet;
public void say(){
//调用宠物的方法
pet.hello();
}
}
7.2接口有多个实现类@Autowired + @Qualifiter(“小写类名”)
package com.jt.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
@Component //将user交给Spring容器管理
public class User {
//效果: 将当前接口的实现类自动注入
@Autowired
@Qualifier("cat") //该注解不能单独使用,必须配合Autowired使用,根据key进行注入
private Pet pet; //2选1
public void say(){
//调用宠物的方法
pet.hello();
}
}
7.3与@Autowired + @Qualifier(“小写类名”)效果相同@Resource(name = “小写类名”)
8.Spring框架注解
8.1控制层@Controller
控制层 Controller 与前端页面交互的. @Controller
8.2业务层@Service
业务层 Service 编辑业务逻辑. @Service
8.3持久层,暂时用@Repositiry
持久层 Mapper 实现数据库的相关操作 暂时:@Repository
9.动态赋值@Value
@Value注解 可以直接为基本类型赋值和String类型
编辑UserMapperImpl类
@PropertySource(value = “classpath:/user.properties”,encoding = “utf-8”)
user.properties文件路径及编码方式
package com.jt.mapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Repository;
@Repository //为了让程序员开发更有层级概念
@PropertySource(value = "classpath:/user.properties",encoding = "utf-8") // :/ 代表资源加载路径
public class UserMapperImpl implements UserMapper{
//耦合性,动态赋值
//表达式: 固定写法${} springel表达式 取值方式 缩写spel表达式
//规则:通过表达式动态获取spring容器中的value
@Value("${id1}")
private int id1;
@Value("${name1}")
private String name1;
@Override
public void addUser() {
System.out.println("新增用户id:"+id1+"新增用户姓名:"+name1);
}
}
编辑user.properties
#1.key=value 等号连接 2.之间不要添加多余的空格
id1=008
name1=张三
10.AOP(面向切面编程)中的注解
10.1开启AOP,在配置中加入@EnableAspectJAutoProxy
10.2标识切面类@Aspect
10.3@Pointcut注解标识切入点表达式
10.3.1切入点表达式
- @Pointcut(“bean(userServiceImpl)”) (bean的id号)按照bean匹配
- @Pointcut(“within(com.jt.service.UserServiceImpl)”) (包名.类名)可以使用通配符
@Pointcut(“within(com.jt.service…*)”) - @Pointcut(“execution(* com.jt.service.UserServiceImpl.addUser())”) (返回值类型 包名.类名.方法名(参数列表))
@Pointcut(“execution(* com.jt.service….(…))”) - @Pointcut("@annotation(com.jt.anno.Gjh)") (包名.注解名称) 按照自定义注解
@Pointcut("@annotation(com.jt.anno.Gjh)")
//目标方法
public void pointcut(){
}
@annotation表达式
:
作用: 可以根据用户的自定义注解进行拦截
10.3.2通知类型注解
- @Before(“pointcut()”) 前置通知:在目标方法执行之前执行
- @AfterReturning(value = “pointcut()”,returning =
“result”) 后置通知:在目标方法执行之后执行,通过returning =
"result"属性,获取目标方法的返回值,当作参数传给result - @AfterThrowing(value = “pointcut()”,throwing =
“exception”) 异常通知:目标方法执行报错时,执行该通知 - @After(“pointcut()”) 最终通知:目标方法之后都要执行的通知
- @Around(“pointcut()”) (重点)环绕通知:在目标方法执行前后都要执行,控制目标方法
@Around("pointcut()")
public Object around(ProceedingJoinPoint joinPoint)throws Throwable{
System.out.println("环绕通知执行前");
Object result = joinPoint.proceed();
System.out.println("环绕通知执行后");
return result;
}
10.4执行AOP顺序@Order(数字)
数字越小越靠前
11.SpringMVC注解
11.1@ResponseBody将数据转化为JSON串返回
11.2@RequestBody将接收到的JSON串转为对象
@PostMapping("/saveUser")
public String saveUser(@RequestBody User user){
System.out.println(user);
return "新增用户成功!!!";
}
11.3@RestController
@RestController将该类交给SpringMVC,SpringMVC将该类交给Spring容器管理
,将数据转化为JSON串返回
。
和@Controller + @ResponseBody效果相同
11.4@RequestMapping("/方法名")
此注解在前后端交互时,浏览器地址栏输入注解中 /方法名
11.5restFul风格 @PathVariable
/**
* URL地址:
* http://localhost:8080/findUser/tomcat/18/男 get类型
* 参数: name/age/sex
* 返回值: 返回值获取的数据
* restFul语法:
* 1. 参数与参数之间使用/分割
* 2. 需要接收的参数使用{}包裹
* 3. 参数接收时采用@PathVariable取值
*/
@RequestMapping("/findUser/{name}/{age}/{sex}")
public String findUser(@PathVariable String name,
@PathVariable int age,
@PathVariable String sex){
return name+":"+age+":"+sex;
}
11.6允许所有方式跨域@CrossOrigin
11.7接收固定请求方式注解
11.7.1@PostMapping("/saveUser")
11.7.2@GetMapping
11.7.3@PutMapping
11.7.4@DeleteMapping
restful参数传给方法的参数时,每个参数都需加@PathVariable注解(不管是什么访问方式);restful参数传给对象时,不需要加注解。
POST和PUT访问方式访问时,方法的参数为对象,需要加@RequestBody注解(Json串转为对象)
11.8@RequestParam在controller层使用
- 为参数设定默认值
- 当提交参数名称与接收参数不一致时使用
例:
/**
* 如果提交参数为空时,可以设置默认值
* @RequestParam
* value/name 接收参数的名称
* required=true 为必填参数
* defaultValue="" 设定默认值
*/
@RequestMapping("/addUser")
public String addUser(@RequestParam(name = "id",defaultValue = "100") Integer id,
@RequestParam(name="name",defaultValue = "张三") String name){
System.out.println("动态获取数据:id:"+id);
System.out.println("动态获取数据:name:"+name);
//新增成功之后.跳转到user页面中
return "user";
}
11.9@Param在mapper层使用
- 为参数设定默认值
- 当提交参数名称与接收参数不一致时使用
12.lombok使用
12.1@Data
@Data相当于Getter/Setter/RequiredArgsConstructor/ToString/EqualsAndHashCode
12.2@Accessors(chain = true)重写了set方法,可实现链式加载
12.3@NoArgsConstructor无参构造方法
12.4@AllArgsConstructor全参构造方法
13. @SpringBootApplication启动类标识
13.1@ComponentScan(“包路径”)
当前包扫描的路径 默认就是主启动类所在的包路径…
注意事项: 以后写代码 必须在主启动类所在包路径的 同包及子包中编辑
13.2@EnableAutoConfiguration开箱即用-自动配置注解
该注解的作用用来加载springBoot-start-xxx的启动项
,当主启动类执行时,则会开始加载启动项中的配置.则功能加载成功.
14.@SpringBootTest
springBoot针对于测试方法
- 当运行@Test注解标识的方式时,SpringBoot程序启动.
- SpringBoot启动,内部Spring容器启动.基于IOC管理对象,DI注入对象
- 可以在任意的测试类中注入想要的对象
测试类的包路径,必须在主启动类的同包及子包中编辑
15.@Mapper将接口交给Spring容器管理
@Mapper 将接口交给Spring容器管理Map<userMapper,JDK代理对象>
16.@Param将数据封装为Map集合
mybatis只支持单值传参 将多值封装为单值
@Param(“key”) int minAge(值)
//Mybatis只支持单值传参 封装为Map集合
List<User> findUserList(@Param("start") int start,@Param("size") int size,@Param("query") String query);
17.@Transactional 事务的注解
一级缓存注解
增删改加上@Transactional 注解
特点:
1.Spring中默认对事务进行支持。
2.Spring中默认控制的是运行时异常,如果是检查异常Spring不负责处理。
核心原理:AOP
常见案例:
@Transactional(rollbackFor = Exception.class) 只要有异常,则全部回滚
问题:如果采用上述的代码,则AOP拦截所有的异常,运行效率低,所以一般只拦截运行时异常,检查异常由程序员手动控制。
18.@CacheNamespace 使用注解的二级缓存
19.Mybatis注解开发@Select,@Insert,@Update,@Delete
20.MapperSan(“路径”) 扫描mapper包的接口
21.全局异常处理的机制实现
21.1 @RestControllerAdvice
全局异常处理机制,只拦截Controller层
21.2 @ExceptionHandler
@ExceptionHandler(RuntimeException.class)指定异常的类型进行拦截
package com.jt.aop;
import com.jt.vo.SysResult;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice //advice通知
//全局异常处理机制,只拦截Controller层
public class SystemException {
//指定异常的类型进行拦截
@ExceptionHandler(RuntimeException.class)
public SysResult exception(Exception e){
e.printStackTrace(); //控制台打印异常信息
return SysResult.fail();//201
}
}
22.MybatisPlus常用注解
22.1@TableName(“user”)让对象与表名一一映射
22.2 @TableId(type = IdType.AUTO)标识主键注解,主键自增
编辑POJO对象
22.3@TableField(exist = false)当前属性不参加MP操作
pojo对象
@Data
@Accessors(chain = true)
@TableName("item_cat")
public class ItemCat extends BasePojo{
@TableId(type = IdType.AUTO)//主键自增
private Integer id; //定义主键
private Integer parentId; //定义父级菜单
private String name; //分类名称
private Boolean status; //分类状态 0 停用 1 正常
private Integer level; //商品分类等级 1 2 3
@TableField(exist = false) //当前属性不参加MP操作
private List<ItemCat> children; //业务数据
}
22.4@TableField(fill = FieldFill.INSERT)、@TableField(fill = FieldFill.INSERT_UPDATE) 自动填充
三、微服务中注解
23.@LoadBalanced
当使用@LoadBalanced注解描述RestTemplate对象时,系统底层再基于RestTemplate进行远程服务调用时,会被一个拦截器(Interceptor)拦截到,然后进行功能增强,这里功能增强指的是:基于LoadBalancerClient对象进行服务实例获取,而这个服务实例获取的过程,底层会采用负载均衡。
24.@EnableFeignClients
@EnableFeignClients 注解用于描述一些配置类
,告诉系统启动时为@FeignClient 注解描述接口创建实现类及对象,然后把对象交给spring管理。
25.@FeignClient描述远程服务调用接口
@FeignClient 注解用于描述远程服务调用接口,其value属性值有两个层面的含义:第一个是需要的远程服务名,第二个是当前bean的名字
@FeignClient描述的接口底层会为其创建实现类
26.@RefreshScope系统在浏览器中能看到日志级别的变化
第一步:在ProviderLogController类的上面添加一个@RefreshScope注解:
@RefreshScope的作用是在配置中心的相关配置发生变化以后,能够及时看到类中属性值的更新(底层是通过重新创建Controller对象的方式,对属性进行了重新初始化)。
@RefreshScope
@RestController
public class ProviderLogController{
//.....
}
第二步:添加ProviderLogController中添加一个获取日志级别(debug<info<warn<error)的的属性和方法:
@Value("${logging.level.com.jt:error}")
private String logLevel;
@GetMapping("/provider/log/doLog02")
public String doLog02(){
log.info("log level is {}",logLevel);
return "log level is "+logLevel;
}
27.@SentinelResource
Sentinel流控规则分析:
链路模式只记录指定链路入口的流量。也就是当多个服务对指定资源调用时,假如流量超出了指定阈值,则进行限流。被调用的方法用@SentinelResource进行注解,然后分别用不同业务方法对此业务进行调用,假如A业务设置了链路模式的限流,在B业务中是不受影响的。
28.缓存
28.1@EnableCaching开启spring中的缓存机制,扫描哪个类中用到了缓存
28.2@Cacheable(value = “permissionCache”)
此注解描述的方法为缓存切入点方法,从数据库查询到数据后, 可以将数据存储到本地的一个缓存对象中(底层是一个map对象)
28.3CachePut注解的意思是更新缓存
key是方法中参数,这里需要id,通过对象获取id
@CachePut(value = "menuCache",key = "#menu.id")
@Override
public Menu updateMenu(Menu menu) {
menuMapper.updateById(menu);
return menu;
}
29@EnableAuthorizationServer在Oauth2规范中启动认证和授权
在主启动类上使用
30.@Async 注解描述方法为一个异步切入点方法
此方法会有一个spring内置的线程池中的线程调用执行,
注意:描述的方法不能有返回值;
需要通过@EnableAsync注解对项目的启动类或者配置类进行描述,启动异步机制。