一.原生注解
Java注解是一种元数据,它提供了在Java代码中插入附加信息的方式。注解可以用于类、方法、变量、参数等的声明上,用于描述、标记或配置程序代码,而不改变代码的实际逻辑。
Java注解使用@
符号作为前缀,紧跟着注解名称,并可以包含一系列的参数。注解可以通过编译器处理或在运行时解析。
1.1原生注解的分类
1.1 .1JDK基本注解:
@Override
:用于标记方法覆盖了父类的方法。
@Deprecated
:用于标记方法、类或字段已经过时,不推荐使用。
@SuppressWarnings
:用于抑制编译器警告。
⭐⭐ 1.1.2JDK元注解 :
@Retention:定义注解的保留策略
@Retention(RetentionPolicy.SOURCE) 注解仅存在于源码中,在 class字节码文件中不包含
@Retention(RetentionPolicy.CLASS)默认的保留策略,注解会在 class字节码文件中存在,但运行时无法获得,
@Retention(RetentionPolicy.RUNTIME)注解会在class字节码文件 中存在,在运行时可以通过反射获取到
@Target:指定被修饰的Annotation可以放置的位置(被修饰的目标)
@Target(ElementType.TYPE) 接口、类
@Target(ElementType.FIELD) 属性
@Target(ElementType.METHOD) 方法
@Target(ElementType.PARAMETER) 方法参数。。。。。
@Inherited:指定被修饰的Annotation将具有继承性
@Documented:指定被修饰的该Annotation可以被javadoc工具提取成文档.
1.1.3 自定义注解:
- 标记注解:没有成员变量的Annotation; 这种Annotation仅利用自身的存在与否来提供信息
- 元数据注解:包含成员变量的Annotation; 它们可以接受(和提供)更多的元数据;
使用@interface关键字, 其定义过程与定义接口非常类似, 需要注意的是:
Annotation的成员变量在Annotation定义中是以无参的方法形式来声明的, 其方法名和返回值类型定义了该成员变量的名字和类型,而且我们还可以使用default关键字为这个成员变量设定默认值;
二.注解的案例
先来导入自定义注解的pom依赖:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.7.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.yinzi</groupId> <artifactId>spboottest01</artifactId> <version>0.0.1-SNAPSHOT</version> <name>spboottest01</name> <description>Demo project for Spring Boot</description> <properties> <java.version>8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <!-- <scope>test</scope>--> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
2.1 案例一(获取类与方法上的注解值)
定义一个类:
package com.yinzi.annotation; public enum TranscationModel { Read, Write, ReadWrite;//定义三个实例,可以将它看作类 }
写三个不同的注解:
/** * MyAnnotation1注解可以用在类、接口、属性、方法上 * 注解运行期也保留 * 不可继承 */ @Target({ElementType.TYPE, ElementType.FIELD,ElementType.METHOD})//用在类、接口、属性、方法上 @Retention(RetentionPolicy.RUNTIME) @Documented public @interface MyAnnotation1 { String name(); } /** * MyAnnotation2注解可以用在方法上 * 注解运行期也保留 * 不可继承 */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface MyAnnotation2 { TranscationModel model() default TranscationModel.ReadWrite; } /** * MyAnnotation3注解可以用在方法上 * 注解运行期也保留 * 可继承 */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface MyAnnotation3 { TranscationModel[] models() default TranscationModel.ReadWrite; }
第三步,创建几个方法使用这些注解
/** * * 获取类与方法上的注解值 */ @MyAnnotation1(name = "abc") public class Demo1 { @MyAnnotation1(name = "xyz")//获取这里的值 private Integer age; @MyAnnotation2(model = TranscationModel.Read) public void list() { System.out.println("list"); } @MyAnnotation3(models = {TranscationModel.Read, TranscationModel.Write}) public void edit() { System.out.println("edit"); } }
最后,进行测试
2.2 案例二(获取类属性上的注解属性值,默认值的赋予)
自定义一个注解,并赋予默认值:
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface TestAnnotation { String value() default "默认value值"; String what() default "这里是默认的what属性对应的值"; }
建立类测试:
有些两个值都赋予了,有些只赋予了一个
/** * 获取类属性上的注解属性值 */ public class Demo2 { @TestAnnotation(value = "这就是value对应的值_msg1", what = "这就是what对应的值_msg1") private static String msg1; @TestAnnotation("这就是value对应的值1")//没有指定,默认value private static String msg2; @TestAnnotation(value = "这就是value对应的值2") private static String msg3; @TestAnnotation(what = "这就是what对应的值") private static String msg4; }
测试结果:
2.3 案例三(获取参数修饰注解对应的属性值,非空注解)
同样,先建立一个非空注解
/** * 非空注解:使用在方法的参数上,false表示此参数可以为空,true不能为空 */ @Documented @Target({ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) public @interface IsNotNull { boolean value() default false;//默认为false }
建立方法,进行测试:
测试
三.AOP结合自定义注解案例⭐⭐
配置相关AOP pom文件
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
applicationContext.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" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!--1. 注解式开发 --> <!-- 注解驱动 --> <context:annotation-config/> <!-- 用注解方式注入bean,并指定查找范围:com.javaxl.ssh2及子子孙孙包--> <context:component-scan base-package="com.yinzi"/> <!--开启动态代理--> <aop:aspectj-autoproxy /> </beans>
定义一个标志日志的注解
package com.yinzi.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * @author yinzi * 日志注解 */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface MyLog { String desc(); }
然后,我们创建一个切面类 LogAspect
,用于实现日志记录的逻辑。
/** * @author yinzi */ @Component @Aspect public class MyLogAspect { private static final Logger logger = LoggerFactory.getLogger(MyLogAspect.class); /** * 只要用到了com.javaxl.p2.annotation.springAop.MyLog这个注解的,就是目标类 */ @Pointcut("@annotation(com.yinzi.annotation.MyLog)") private void MyValid() { } @Before("MyValid()") public void before(JoinPoint joinPoint) { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); logger.debug("[" + signature.getName() + " : start.....]"); System.out.println("[" + signature.getName() + " : start.....]"); MyLog myLog = signature.getMethod().getAnnotation(MyLog.class); logger.debug("【目标对象方法被调用时候产生的日志,记录到日志表中】:"+myLog.desc()); System.out.println("【目标对象方法被调用时候产生的日志,记录到日志表中】:" + myLog.desc()); } }
在方法上运用日志注解
/** * @author yinzi */ @Controller public class LogController { @RequestMapping("/mylog") @MyLog(desc = "这是结合spring aop知识,讲解自定义注解应用的一个案例") public void testLogAspect(){ System.out.println("这里随便来点啥"); } }
运行结果: 这只是大概的模拟了一下