1. 基础复习
1.1 注解是什么?
注解是一种特殊的Java构造,也是一种引用数据类型,编译后也是生成.class文件。
自定义注解格式
[修饰符列表] @interface 注解类型名{
}
注解可以用在类,方法,字段,参数,变量,构造方法或包上;注解也可以用在注解上。
1.2 注解的组成部分
1.2.1 四个元注解
元注解:用来标注“注解类型”的注解
-
@Target
用来标注“被标注的注解”可以出现在哪些位置上。
例如:@Target(ElementType.METHOD)
表示“被标注的注解”只能出现在方法上。
@Target(value = {ElementType.TYPE, ElementType.FIELD})
表示“被标注的注解”可以出现在类上或者字段上 -
@Retention
用来标注“被注解的注解”最终保存在哪里。
@Retention(RetentionPolicy.SOURCE):表示该注解只被保留在java源文件中。@Retention(RetentionPolicy.CLASS):表示该注解被保存在class文件中。@Retention(RetentionPolicy.RUNTIME):表示该注解被保存在class文件中,并且可以被反射机制所读取。
这里注意:所有我们自定义(包括框架)的注解都要使用RetentionPolicy.RUNTIME,因为后面我们要通过反射去实现它的逻辑;一般由JDK自带的注解都是RetentionPolicy.SOURCE,因为它们的逻辑是JVM去实现的。 -
@Inherited
表明使用了@Inherited注解的注解,所标记的类的子类也会拥有这个注解 -
@Document
表明该注解标记的元素可以被Javadoc 或类似的工具文档化
1.2.2 注解内部属性
注解的代码块中可以有属性吗?
注解仅支持基本数据类型、字符串和枚举;这个枚举可以在注解内部定义。
注解中所有属性都定义为方法,可以提供默认值
例如这样的一个注解
@Target(value = {ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnno {
public enum Priority {LOW, MEDIUM, HIGH}
public enum Status {STARTED, NOT_STARTED}
String author() default "guaige";
double price() default 300.0;
Priority priority() default Priority.LOW;
Status status() default Status.NOT_STARTED;
}
我们这么去使用它
@MyAnno(author = "laoba", priority = MyAnno.Priority.HIGH)
public void testMethod1() {
}
如果注解只有一个String类型属性,它的名字必须为value,我们在使用注解,给这个属性赋值时可以不用写字段名。
@interface Author{
String value();
}
@Author("Yashwant")
public void someMethod() {
}
1.3 注解如何起作用?
首先我们看最常见的注解@Override的定义代码
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
发现没有,这个注解里没有定义任何业务逻辑。
如果注解不包含逻辑,那么必须有其他地方能读取到我们使用了这个注解,并为其添加逻辑。
像@Override这样的标准注解,它的逻辑就是JVM所写的。
那我们自定义的注解呢?
还拿上面自定义的MyAnno注解举例。
@Target(value = {ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnno {
public enum Priority {LOW, MEDIUM, HIGH}
public enum Status {STARTED, NOT_STARTED}
String author() default "guaige";
double price() default 300.0;
Priority priority() default Priority.LOW;
Status status() default Status.NOT_STARTED;
}
我们需要使用反射,反射提供了Class,Method和Field对象,他们都有一个
getAnnotation()方法,返回的是指定的注解对象。
除了getAnnotation(),其余的还有
isAnnotationPresent():判断当前元素是否被指定注解修饰
getAnnotations():返回所有的注解(一个Annotation数组)
创建一个类,写两个方法,一个加上这个注解,一个不加。
public class MyTest {
@MyAnno(author = "laoba", priority = MyAnno.Priority.HIGH)
public void testMethod1() {
}
public void testMethod2() {
}
}
写一个方法获取类中被@MyAnno注解的方法,拿到属性值。
class AnalysisAnno {
public void customer() {
Class<MyTest> myTestClass = MyTest.class;
for (Method method : myTestClass.getMethods()) {
MyAnno annotation = method.getAnnotation(MyAnno.class);
if (annotation != null) {
// 使用注解的方法的名字
System.out.println(method.getName());
// 属性值
System.out.println(annotation.author());
System.out.println(annotation.priority());
System.out.println(annotation.price());
}
}
}
public static void main(String[] args) {
AnalysisAnno analysisAnno = new AnalysisAnno();
analysisAnno.customer();
}
}
除了能拿到注解的属性值,当然还可以加入逻辑了。
比如我们想让上面被注解的这个方法,必须没有任何参数,否则报错。
public void customer2() {
Class<MyTest> myTestClass = MyTest.class;
for (Method method : myTestClass.getMethods()) {
MyAnno annotation = method.getAnnotation(MyAnno.class);
if (annotation != null) {
if (method.getParameterCount() != 0) {
throw new RuntimeException("被@MyAnno注解的方法不能有参数!");
}
}
}
}
2. 讲讲常用注解
2.1 Spring IOC相关
@Controller
放在控制层实现类的上面,创建控制器对象,注入到ioc容器中。
@Service
放在业务层实现类的上面,创建业务逻辑层对象,注入到ioc容器。
@Repository
放到dao层实现类上面,创建dao对象注入ioc容器。现在使用mybatis框架,dao对象是mybatis动态代理生成的,@Repository不再使用了。
不过依然可以和@Mapper注解一同使用。
@Component
放在类的上面,创建此类的对象,注入到ioc容器中,这个是针对普通的类的。
@Autowired
引用类型赋值,支持byName与byType的赋值方式,默认为byType。
该注解可以放在属性上或是方法上。
@Qualifer
引用类型赋值,使用byName方式赋值。
@Qualifer和@Autowired都是spring框架提供的
@Resource
是jdk提供的注解,引用类型的自动注入。
默认使用byName,如果byName失败,再使用byType注入。
@Bean
声明对象,将其注入到ioc容器。一般搭配@Configuration使用。
@Bean和@Autowired的区别:
@Bean是放入ioc容器,@Autowired是从ioc容器中拿出
2.2 Spring AOP相关
@Aspect
表示被注解的类是切面类。是一种AOP思想。
有五种常用的通知注解:
@Before:前置通知
@After:后置通知,无论方法什么情况都会执行,优先级高于@AfterReturning
@AfterReturning:后置通知,在方法完全执行结束后执行
@Around:环绕通知,一般在这里执行切点逻辑
@AfterThrowing:抛出异常通知
@Pointcut
定义一个切入点表达式。用法是将此注解写在一个方法之上,之后所有的切入点表达式都可以用这个方法代替。
@Aspect
public class MyTest {
@Pointcut("execution(* *..service.*.*(..))")
private void myPoint(){
}
@After("myPoint()")
public String myDept() {
return null;
}
}
2.3 Spring其他
@Value
基本数据类型赋值(八大基本数据类型及其包装类,以及String)
可以数据写死赋值
@Value("李四")
private String name
也可以读配置文件(properties或yml)赋值
@Value("${server.port}")
private Integer port
@PropertySource
指定properties文件的位置
读取properties属性配置文件,可以实现外部化配置。
一般搭配@Value一起使用。
@ImportResource
不常用。作用是导入其他的xml配置文件。
@Transactional
在业务方法上使用@Transactional,使方法有事务功能
@EnableTransactionManager
在主启动类上加上这个注解,让上面的@Transactional注解生效。
2.4 Mybatis相关
@Mapper
放在mapper接口的上面,让mybatis找到mapper接口,通过动态代理创建其对象。
@MapperScan
放在主类(Application)上面,指定扫描的包,将这个包中所有接口都创建代理对象,注入ioc容器。
@Param
在mapper接口方法的形参前面,作为其命名参数在mapper的xml文件中使用。
2.5 SpringMVC相关
@ResponseBody
放在方法的上面,表示方法的返回值是数据。
将Java对象转换为json数据返回给前端。
@RequestBody
把post请求的请求体里的json数据读取为Java对象进行使用。
@RequestParam
常用于get请求,表示这个参数必须要有值,否则报错(400)
也可以用于指定收参数的名字
@GetMapping("/detail")
public String Detail(@RequestParam("id") String userId) {
return null;
}
例如这里,前端给我们传的是id,我们通过@RequestParam接收了id,但是方法形参可以任意,比如我们这里写的是userId
@RequestMapping
配置请求路径,可以放到Controller类上面,或者Controller类的接口方法上。
2.6 SpringBoot相关
@Configuration
放在一个类的上面,表示这个类作为配置文件使用。
@SpringBootApplication
复合注解,由
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
组成
@SpringBootConfiguration:使用此注解标注的类,可以作为配置文件使用,可以使用@Bean对象注入到容器。
@EnableAutoConfiguration:启用自动配置,把Java对象配置好,注入到ioc容器中。
@ComponentScan:包扫描器,找到注解,根据注解的功能创建对象、给属性赋值等等。
默认扫描的包:@ComponentScan注解的类 所在的包和子包。
@ConfigurationProperties
把配置文件的数据映射为Java对象,直接注入给类中属性。(不常用)
@PathVariable
从REST风格的url中获取数据,例如
@GetMapping("/detail/{id}")
public String detail(@PathVariable("id") String id) {
return null;
}
@GetMapping
@RequestMapping(method=RequestMethod.GET)
@PostMapping
@RequestMapping(method=RequestMethod.POST)
@PutMapping
@RequestMapping(method=RequestMethod.PUT)
@DeleteMapping
@RequestMapping(method=RequestMethod.DELETE)
@RestController
复合注解,是@Controller 和@ResponseBody组合。
在类的上面使用@RestController,表示所有方法上都加上了@ResponseBody
@Valid
这个注解通常用于post请求,用一个类接收前端的json参数时,对参数进行数据验证。参数前有了这个注解,接收参数的RO类里的注解就可以生效。
常用的几个做参数验证的注解
@NotBlank:不能为空或空字符串
@NotNull:不能为空值,可用在所有类型上面
@Min(value) :被注解的字段必须是数字,必须大于指定的最小值
@Max(value) :被注解的字段必须是数字,必须小于指定的最大值
@Size(min,max) :被注解的字段必须是字符串、集合或数组,长度在min和max之间
@Length(min,max) :被注解的字符串的长度在min与max之间。
@NotEmpty:用在String或集合上面,被注解的字段不为null且大小(长度)不为0
@Range(min,max) :被注解的字段必须是数字,值在min与max之间。