Java注解Annotation与自定义注解详解
Java注解简介
开发中经常使用到注解,在项目中也偶尔会见到过自定义注解,今天就来探讨一下这个注解是什么鬼,以及注解的应用场景和如何自定义注解。
下面列举开发中常见的注解
@Override:用于标识该方法继承自超类, 当父类的方法被删除或修改了,编译器会提示错误信息(我们最经常看到的toString()方法上总能看到这货)
@Deprecated:表示该类或者该方法已经不推荐使用,已经过期了,如果用户还是要使用,会生成编译的警告
@SuppressWarnings:用于忽略的编译器警告信息
Junit测试:@Test
Spring的一些注解:@Controller、@RequestMapping、@RequestParam、@ResponseBody、@Service、@Component、@Repository、@Resource、@Autowire
Java验证的注解:@NotNull、@Email
下面看一下注解Override.java的庐山真面目
|
1
2
3
4
5
|
@Target(ElementType.METHOD)@Retention(RetentionPolicy.SOURCE)public @interface Override {} |
二:Java注解基本知识
1. Java注解数据类型
注解是写在.java文件中,使用@interface作为关键字, 所以注解也是Java的一种数据类型,从广泛的定义来说,Class、Interface、Enum、Annotation都属于Class类型。
2. Java元注解
在创建注解的时候,需要使用一些注解来描述自己创建的注解,就是写在@interface上面的那些注解,这些注解被称为元注解,如在Override中看到的@Target、@Retention等。下面列出一些元注解
@Documented: 用于标记在生成javadoc时是否将注解包含进去,可以看到这个注解和@Override一样,注解中空空如也,什么东西都没有
|
1
2
3
4
5
6
|
@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.ANNOTATION_TYPE)public @interface Documented {} |
@Target:用于定义注解可以在什么地方使用,默认可以在任何地方使用,也可以指定使用的范围,开发中将注解用在类上(如@Controller)、字段上(如@Autowire)、方法上(如@RequestMapping)、方法的参数上(如@RequestParam)等比较常见。
TYPE : 类、接口或enum声明
FIELD: 域(属性)声明
METHOD: 方法声明
PARAMETER: 参数声明
CONSTRUCTOR: 构造方法声明
LOCAL_VARIABLE:局部变量声明
ANNOTATION_TYPE:注释类型声明
PACKAGE: 包声明
Target.java
|
1
2
3
4
5
6
7
8
9
10
11
12
|
@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.ANNOTATION_TYPE)public @interface Target { /** * Returns an array of the kinds of elements an annotation type * can be applied to. * @return an array of the kinds of elements an annotation type * can be applied to */ ElementType[] value();} |
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
public enum ElementType { /** Class, interface (including annotation type), or enum declaration */ TYPE, /** Field declaration (includes enum constants) */ FIELD, /** Method declaration */ METHOD, /** Formal parameter declaration */ PARAMETER, /** Constructor declaration */ CONSTRUCTOR, /** Local variable declaration */ LOCAL_VARIABLE, /** Annotation type declaration */ ANNOTATION_TYPE, /** Package declaration */ PACKAGE, /** Type parameter declaration */ TYPE_PARAMETER, /** Use of a type */ TYPE_USE} |
@Inherited:允许子类继承父类中的注解,可以通过反射获取到父类的注解
|
1
2
3
4
5
6
|
@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.ANNOTATION_TYPE)public @interface Inherited {} |
@Constraint:用于校验属性值是否合法
|
1
2
3
4
5
6
|
@Documented@Target({ElementType.ANNOTATION_TYPE})@Retention(RetentionPolicy.RUNTIME)public @interface Constraint { Class<? extends ConstraintValidator<?, ?>>[] validatedBy();} |
@Retention:注解的声明周期,用于定义注解的存活阶段,可以存活在源码级别、编译级别(字节码级别)、运行时级别
SOURCE:源码级别,注解只存在源码中,一般用于和编译器交互,用于检测代码。如@Override, @SuppressWarings。
CLASS:字节码级别,注解存在于源码和字节码文件中,主要用于编译时生成额外的文件,如XML,Java文件等,但运行时无法获得。 如mybatis生成实体和映射文件,这个级别需要添加JVM加载时候的代理(javaagent),使用代理来动态修改字节码文件。
RUNTIME:运行时级别,注解存在于源码、字节码、java虚拟机中,主要用于运行时,可以使用反射获取相关的信息。
|
1
2
3
4
5
6
7
8
9
10
|
@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.ANNOTATION_TYPE)public @interface Retention { /** * Returns the retention policy. * @return the retention policy */ RetentionPolicy value();} |
3. Java注解的内容
在上面的注解源码中可以看到有的注解中没有任何内容,有的注解的有内容,看似像方法。
注解的内容的语法格式: 数据类型 属性名() default 默认值,数据类型用于描述属性的数据类型,默认值是说当没有给属性赋值时使用默认值,一般String使用空字符串”“作为默认值,数组一般使用空数组{ }作为默认值.
下面看一下SpringMVC中的RequestMapping的注解的声明
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
@Target({ElementType.METHOD, ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Mappingpublic @interface RequestMapping { String name() default ""; @AliasFor("path") String[] value() default {}; @AliasFor("value") String[] path() default {}; RequestMethod[] method() default {}; String[] params() default {}; String[] headers() default {}; String[] consumes() default {}; String[] produces() default {};} |
使用SpringMVC中的RequestMapping注解
|
1
2
3
4
5
6
|
@RequestMapping(value = "/list", method = RequestMethod.POST, produces = {"application/json;charset=UTF-8;"})public String list(){} |
4. 注解的使用场景
可以通过注解的声明周期来分析注解的使用场景:
SOURCE源码级别:给编译器使用,如@Override、@Deprecated 等, 这部分开发者应该使用的场景不多
CLASS:字节码级别,这部分也很少见到
RUNTIME:运行时级别,这个是最多的,几乎开发者使用到的注解都是运行时级别,运行时注解常用的有以下几种情况
注解中没有任何属性的,空的注解,这部分注解通常起到一个标注的作用,如@Test、@Before、@After,通过获取这些标记注解在逻辑上做一些特殊的处理
可以使用约束注解@Constraint来对属性值进行校验,如@Email, @NotNull等
可以通过在注解中使用属性来配置一些参数,然后可以使用反射获取这些参数,这些注解没有其他特殊的功能,只是简单的代替xml配置的方式来配置一些参数。使用注解来配置参数这在Spring boot中得到了热捧,如@Configuration
关于配置方式xml vs annotation, 一般使用xml配置一些和业务关系不太紧密的配置,使用注解配置一些和业务密切相关的参数。
三:Java注解和反射基本API
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
// 获取某个类型的注解public <A extends Annotation> A getAnnotation(Class<A> annotationClass);// 获取所有注解(包括父类中被Inherited修饰的注解)public Annotation[] getAnnotations(); // 获取声明的注解(但是不包括父类中被Inherited修饰的注解)public Annotation[] getDeclaredAnnotations();// 判断某个对象上是否被某个注解进行标注public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)// 获取某个类声明的所有字段public Field[] getDeclaredFields() throws SecurityException;// 获取某个方法public Method getMethod(String name, Class<?>... parameterTypes); |
四:自定义注解
使用自定义注解+拦截器或者是AOP等可以进行权限的控制。
下面通过定义一个注解用来限制当用户访问接口时必须要登录的示例
步骤一:定义注解
RequiresLogin.java
|
1
2
3
4
5
6
|
@Documented@Target({ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)public @interface RequiresLogin {} |
步骤二:使用注解
|
1
2
3
4
5
6
7
8
9
10
11
|
@Controller@RequestMapping("/user")public class UserController { @RequiresLogin @RequestMapping(value = "/list", produces = {"application/json;charset=UTF-8;"}) public String getUserList(){ System.out.println("--------------"); return "[{'id': 1, 'username':'zhangsan'}]"; }} |
步骤三:使用AOP进行拦截,解析注解
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
public class LoginAdvices { public void before(JoinPoint joinPoint) throws Exception{ Object target = joinPoint.getTarget(); String methodName = joinPoint.getSignature().getName(); System.out.println(target + "-------" + methodName); Method method = target.getClass().getMethod(methodName); boolean annotationPresent = method.isAnnotationPresent(RequiresLogin.class); if (annotationPresent) { // 用户必须登录 boolean isLogin = false; if (!isLogin) { throw new Exception("访问该接口必须先登录"); } else { System.out.println("已登录..."); } } }} |
在applicationContext.xml中配置aop
|
1
2
3
4
5
6
7
8
9
10
11
|
<bean id="loginAdvices" class="com.mengdee.manager.aop.LoginAdvices"/> <!-- aop配置 --> <aop:config proxy-target-class="true"> <!--切面 --> <aop:aspect ref="loginAdvices"> <!-- 切点 --> <aop:pointcut id="pointcut1" expression="execution(* com.mengdee.manager.controller.*.*(..))"/> <!--连接通知方法与切点 --> <aop:before method="before" pointcut-ref="pointcut1"/> </aop:aspect> </aop:config> |
自定义异常
为什么要自定义异常
Java虽然提供了丰富的异常处理类,但是在项目中还会经常使用自定义异常,其主要原因是Java提供的异常类在某些情况下还是不能满足各种业务的需求。 例如系统中有些错误是符合Java语法,但不符合业务逻辑。如当用户登录时账号不存在或者账号已锁定可以自定义一个账号异常AccountException。
或者有些情况下Java的同一个异常可能会有多种原因引起,在排查问题时不容易定位错误,此时可以使用自定义一个更加明确的异常。
自定义异常的好处:自定义异常可以使异常更加明确,可以隐藏底层的异常,这样更安全,异常信息更加直观。
自定义异常的使用:自定义异常一般继承自Exception或者RuntimeException,根据业务需要可以带一些属性作为构造函数的参数,自定义异常需要程序员手动抛出异常,并处理异常。
下面是Apache Shiro中自定义异常的示例
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public class ShiroException extends RuntimeException { public ShiroException() { } public ShiroException(String message) { super(message); } public ShiroException(Throwable cause) { super(cause); } public ShiroException(String message, Throwable cause) { super(message, cause); }} |
以上即是关于Java注解Annotation与自定义注解的详细说明
Java注解Annotation与自定义注解详解的更多相关文章
- 深入JAVA注解(Annotation):自定义注解 (转)
原文出自:http://blog.csdn.net/yjclsx/article/details/52101922 一.基础知识:元注解 要深入学习注解,我们就必须能定义自己的注解,并使用注解,在定义 ...
- [2]注解(Annotation)-- 深入理解Java:注解(Annotation)自定义注解入门
转载 http://www.cnblogs.com/peida/archive/2013/04/24/3036689.html 深入理解Java:注解(Annotation)自定义注解入门 要深入学习 ...
- java 日志脱敏框架 sensitive-v0.0.4 系统内置常见注解,支持自定义注解
项目介绍 日志脱敏是常见的安全需求.普通的基于工具类方法的方式,对代码的入侵性太强.编写起来又特别麻烦. 本项目提供基于注解的方式,并且内置了常见的脱敏方式,便于开发. 特性 基于注解的日志脱敏. 可 ...
- Java日志脱敏框架 sensitive-v0.0.4 系统内置常见注解,支持自定义注解
项目介绍 日志脱敏是常见的安全需求.普通的基于工具类方法的方式,对代码的入侵性太强.编写起来又特别麻烦. 本项目提供基于注解的方式,并且内置了常见的脱敏方式,便于开发. 特性 基于注解的日志脱敏. 可 ...
- Java学习-007-Log4J 日志记录配置文件详解及实例源代码
此文主要讲述在初学 Java 时,常用的 Log4J 日志记录配置文件详解及实例源代码整理.希望能对初学 Java 编程的亲们有所帮助.若有不足之处,敬请大神指正,不胜感激!源代码测试通过日期为:20 ...
- 【转】Java魔法堂:String.format详解
Java魔法堂:String.format详解 目录 一.前言 二.重载方法 三.占位符 四.对字符.字符串进行格式化 五.对整数进行格式化 六. ...
- Java 反射 设计模式 动态代理机制详解 [ 转载 ]
Java 反射 设计模式 动态代理机制详解 [ 转载 ] @author 亦山 原文链接:http://blog.csdn.net/luanlouis/article/details/24589193 ...
- 牛客网 Java 工程师能力评估 20 题 - 详解
牛客网 Java 工程师能力评估 20 题 - 详解 不知在看博客的你是否知道 牛客网,不知道就太落后了,分享给你 : 牛客网 此 20 题,绝对不只是 20 题! 免责声明:本博客为学习笔记,如有侵 ...
- Java 中的异常和处理详解
Java 中的异常和处理详解 原文出处: 代码钢琴家 简介 程序运行时,发生的不被期望的事件,它阻止了程序按照程序员的预期正常执行,这就是异常.异常发生时,是任程序自生自灭,立刻退出终止,还是输出错误 ...
随机推荐
- iOS 图表工具charts之CombinedChartView
关于charts的系列视图介绍传送门: iOS 图表工具charts介绍 iOS 图表工具charts之LineChartView iOS 图表工具charts之BarChartView iOS 图表 ...
- MySQL备份工具之mysqlhotcopy
mysqlhotcopy使用lock tables.flush tables和cp或scp来快速备份数据库.它是备份数据库或单个表最快的途径,完全属于物理备份,但只能用于备份MyISAM存储引擎和运行 ...
- 老白关于rac性能调优的建议
RAC应用设计方面需要在底层做很有设计.虽然ORACLE的售前人员总是说RAC的扩展性是透明的,只要把应用分到不同的节点,就可以平滑的扩展系统能力了.而事实上,RAC的CACHE FUSION机制决定 ...
- 更新操作 关于json字符串的拼接、json字符串与json对象之间的转换
更新操作 后台 /** * 更新人员 * @return "updateSdr" */ public String updateTheSdr(){ jsonstr = " ...
- java:easyui(jQueryEasyUI,分页)
1.介绍: jQuery EasyUI是一组基于jQuery的UI插件集合体,而jQuery EasyUI的目标就是帮助web开发者更轻松的打造出功能丰富并且美观的UI界面.开发者不需要编写复杂的ja ...
- plsql连接本地oracle数据库,而远程主机却无法连接,出现无监听程序的解决方法(转)
原文转自:plsql连接本地oracle数据库,而远程主机却无法连接,出现无监听程序的解决方法 最近在使用plsql连接本地oracle数据库的时候,在同一网络环境中,出现了可以连接本地oracle, ...
- 《Google工作法》读书笔记
最近一段时间,拜读了<Google工作法>,工作效率提升10倍的57个技巧. 作者是彼得·费利克斯·格日瓦奇,波兰人. 其中印象最深刻的部分如下: (1)不要被邮件夺走时间 不用邮件,所有 ...
- kali安装redis
下载 wget http://download.redis.io/releases/redis-4.0.11.tar.gz 解压 tar -zxvf redis-4.0.11.tar.gz 切换目录 ...
- 【神经网络与深度学习】【VS开发】【CUDA开发】VS2013 配置CUDNN V4 DEMO
VS2013 配置CUDNN V4 DEMO 众所周知,当前主流深度学习的实现中调用的底层API都是cudnn,自己做项目需要开发深度学习模块时,也需要调用cudnn库,因此熟悉cudnn库是很有必要 ...
- 第六周课程总结&试验报告(四)
一.实验目的 (1)掌握类的继承方法 (2)变量的继承和覆盖,方法的继承,重载和覆盖实现 二.实验内容 三.实验过程 1. 实验源码 package test; import java.util.Sc ...