一、注解的基本概念和原理及其简单实用

注解(Annotation)提供了一种安全的类似注释的机制,为我们在代码中添加信息提供了一种形式化得方法,使我们可以在稍后某个时刻方便的使用这些数据(通过解析注解来使用这些数据),用来将任何的信息或者元数据与程序元素(类、方法、成员变量等)进行关联。其实就是更加直观更加明了的说明,这些说明信息与程序业务逻辑没有关系,并且是供指定的工具或框架使用的。Annotation像一种修饰符一样,应用于包、类型、构造方法、方法、成员变量、参数及本地变量的申明语句中。

Annotation其实是一种接口。通过Java的反射机制相关的API来访问Annotation信息。相关类(框架或工具中的类)根据这些信息来决定如何使用该程序元素或改变它们的行为。Java语言解释器在工作时会忽略这些Annotation,因此在JVM中这些Annotation是“不起作用”的,只能通过配套的工具才能对这些Annotation类型的信息进行访问和处理。

Annotation和interface的异同:

1、 annotition的类型使用关键字@interface而不是interface。它继承了java.lang.annotition.Annotition接口,并非申明了一个interface。

2、 Annotation类型、方法定义是独特的、受限制的。Annotation类型的方法必须申明为无参数、无异常抛出的。这些方法定义了Annotation的成员:方法名称为了成员名,而方法返回值称为了成员的类型。而方法返回值必须为primitive类型、Class类型、枚举类型、Annotation类型或者由前面类型之一作为元素的一位数组。方法的后面可以使用default和一个默认数值来申明成员的默认值,null不能作为成员的默认值,这与我们在非Annotation类型中定义方法有很大不同。Annotation类型和他的方法不能使用Annotation类型的参数,成员不能是generic。只有返回值类型是Class的方法可以在Annotation类型中使用generic,因为此方法能够用类转换将各种类型转换为Class。

参考链接:https://blog.csdn.net/u010987379/article/details/52152795

3、 Annotation类型又与接口有着近似之处。它们可以定义常量、静态成员类型(比如枚举类型定义)。Annotation类型也可以如接口一般被实现或者继承。

* 元注解@Target,@Retention,@Documented,@Inherited 

* @Target 表示该注解用于什么地方,可能的 ElemenetType 参数包括: 
* ElemenetType.CONSTRUCTOR 构造器声明 
* ElemenetType.FIELD 域声明(包括 enum 实例) 
* ElemenetType.LOCAL_VARIABLE 局部变量声明 
* ElemenetType.METHOD 方法声明 
* ElemenetType.PACKAGE 包声明 
* ElemenetType.PARAMETER 参数声明 
* ElemenetType.TYPE 类,接口(包括注解类型)或enum声明 

* @Retention 表示在什么级别保存该注解信息。可选的 RetentionPolicy 参数包括: 
* RetentionPolicy.SOURCE 注解将被编译器丢弃 
* RetentionPolicy.CLASS 注解在class文件中可用,但会被VM丢弃 
* RetentionPolicy.RUNTIME VM将在运行期也保留注释,因此可以通过反射机制读取注解的信息。 

* @Documented 将此注解包含在 javadoc 中 

* @Inherited 允许子类继承父类中的注解

@Target(ElementType.METHOD) 
@Retention(RetentionPolicy.RUNTIME) 
@Documented 
@Inherited

下面的示例来简单的讲述spring注解原理:

本例实现了在set方法上和在字段属性上注解的处理解析。

1、定义注解

  1. package com.yt.annotation;
  2. import java.lang.annotation.ElementType;
  3. import java.lang.annotation.Retention;
  4. import java.lang.annotation.RetentionPolicy;
  5. import java.lang.annotation.Target;
  6. /**
  7. * @Description:定义注解
  8. * @ClassName: ZxfResource
  9. * @Project: spring-aop
  10. * @Author: zxf
  11. * @Date: 2011-6-7
  12. */
  13. // 在运行时执行
  14. @Retention(RetentionPolicy.RUNTIME)
  15. // 注解适用地方(字段和方法)
  16. @Target({ ElementType.FIELD, ElementType.METHOD })
  17. public @interface ZxfResource {
  18. //注解的name属性
  19. public String name() default "";
  20. }

2、带有注解的服务类

  1. package com.yt.annotation;
  2. /**
  3. * @Description: 带有注解的服务
  4. * @ClassName: UserDaoImpl
  5. * @Project: spring-aop
  6. * @Author: zxf
  7. * @Date: 2011-6-7
  8. */
  9. public class UserServiceImpl {
  10. public UserDaoImpl userDao;
  11. public User1DaoImpl user1Dao;
  12. // 字段上的注解,可以配置name属性
  13. @ZxfResource
  14. public User2DaoImpl user2Dao;
  15. // set方法上的注解,带有name属性
  16. @ZxfResource(name = "userDao")
  17. public void setUserDao(UserDaoImpl userDao) {
  18. this.userDao = userDao;
  19. }
  20. // set方法上的注解,没有配置name属性
  21. @ZxfResource
  22. public void setUser1Dao(User1DaoImpl user1Dao) {
  23. this.user1Dao = user1Dao;
  24. }
  25. public void show() {
  26. userDao.show();
  27. user1Dao.show1();
  28. user2Dao.show2();
  29. System.out.println("这里是Service方法........");
  30. }
  31. }

3、要注入的DAO

  1. package com.yt.annotation;
  2. /**
  3. * @Description: 要注入的DAo类
  4. * @ClassName: UserDaoImpl
  5. * @Project: spring-aop
  6. * @Author: zxf
  7. * @Date: 2011-6-7
  8. */
  9. public class UserDaoImpl {
  10. String name ;
  11. public void show(){
  12. System.out.println("这里是dao方法........");
  13. }
  14. }
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans>
  3. <bean id = "userDao" class="com.yt.annotation.UserDaoImpl" />
  4. <bean id = "user1Dao" class="com.yt.annotation.User1DaoImpl" />
  5. <bean id = "user2Dao" class="com.yt.annotation.User2DaoImpl" />
  6. <bean id = "userService" class = "com.yt.annotation.UserServiceImpl" />
  7. </beans>

4、注解处理器

  1. package com.yt.annotation;
  2. import java.beans.Introspector;
  3. import java.beans.PropertyDescriptor;
  4. import java.lang.reflect.Field;
  5. import java.lang.reflect.Method;
  6. import java.util.ArrayList;
  7. import java.util.HashMap;
  8. import java.util.Iterator;
  9. import java.util.List;
  10. import java.util.Map;
  11. import org.apache.log4j.Logger;
  12. import org.dom4j.Document;
  13. import org.dom4j.DocumentException;
  14. import org.dom4j.Element;
  15. import org.dom4j.io.SAXReader;
  16. /**
  17. * @Description: spring中的注解原理
  18. * @ClassName: ClassPathXMLApplicationContext
  19. * @Project: spring-aop
  20. * @Author: zxf
  21. * @Date: 2011-6-3
  22. */
  23. public class ClassPathXMLApplicationContext {
  24. Logger log = Logger.getLogger(ClassPathXMLApplicationContext.class);
  25. List<BeanDefine> beanList = new ArrayList<BeanDefine>();
  26. Map<String, Object> sigletions = new HashMap<String, Object>();
  27. public ClassPathXMLApplicationContext(String fileName) {
  28. //读取配置文件中管理的bean
  29. this.readXML(fileName);
  30. //实例化bean
  31. this.instancesBean();
  32. //注解处理器
  33. this.annotationInject();
  34. }
  35. /**
  36. * 读取Bean配置文件
  37. * @param fileName
  38. * @return
  39. */
  40. @SuppressWarnings("unchecked")
  41. public void readXML(String fileName) {
  42. Document document = null;
  43. SAXReader saxReader = new SAXReader();
  44. try {
  45. ClassLoader classLoader =
  46. Thread.currentThread().getContextClassLoader();
  47. document = saxReader.read(classLoader.getResourceAsStream(fileName));
  48. Element beans = document.getRootElement();
  49. for (Iterator<Element> beansList = beans.elementIterator();
  50. beansList.hasNext();) {
  51. Element element = beansList.next();
  52. BeanDefine bean = new BeanDefine(
  53. element.attributeValue("id"),
  54. element.attributeValue("class"));
  55. beanList.add(bean);
  56. }
  57. } catch (DocumentException e) {
  58. log.info("读取配置文件出错....");
  59. }
  60. }
  61. /**
  62. * 实例化Bean
  63. */
  64. public void instancesBean() {
  65. for (BeanDefine bean : beanList) {
  66. try {
  67. sigletions.put(bean.getId(),
  68. Class.forName(bean.getClassName()).newInstance());
  69. } catch (Exception e) {
  70. log.info("实例化Bean出错...");
  71. }
  72. }
  73. }
  74. /**
  75. * 注解处理器
  76. * 如果注解ZxfResource配置了name属性,则根据name所指定的名称获取要注入的实例引用,
  77. * 如果注解ZxfResource;没有配置name属性,则根据属性所属类型来扫描配置文件获取要
  78. * 注入的实例引用
  79. *
  80. */
  81. public void annotationInject(){
  82. for(String beanName:sigletions.keySet()){
  83. Object bean = sigletions.get(beanName);
  84. if(bean!=null){
  85. this.propertyAnnotation(bean);
  86. this.fieldAnnotation(bean);
  87. }
  88. }
  89. }
  90. /**
  91. * 处理在set方法加入的注解
  92. * @param bean 处理的bean
  93. */
  94. public void propertyAnnotation(Object bean){
  95. try {
  96. //获取其属性的描述
  97. PropertyDescriptor[] ps =
  98. Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();
  99. for(PropertyDescriptor proderdesc : ps){
  100. //获取所有set方法
  101. Method setter = proderdesc.getWriteMethod();
  102. //判断set方法是否定义了注解
  103. if(setter!=null && setter.isAnnotationPresent(ZxfResource.class)){
  104. //获取当前注解,并判断name属性是否为空
  105. ZxfResource resource = setter.getAnnotation(ZxfResource.class);
  106. String name ="";
  107. Object value = null;
  108. if(resource.name()!=null&&!"".equals(resource.name())){
  109. //获取注解的name属性的内容
  110. name = resource.name();
  111. value = sigletions.get(name);
  112. }else{ //如果当前注解没有指定name属性,则根据类型进行匹配
  113. for(String key : sigletions.keySet()){
  114. //判断当前属性所属的类型是否在配置文件中存在
  115. if(proderdesc.getPropertyType().isAssignableFrom(sigletions.get(key).getClass())){
  116. //获取类型匹配的实例对象
  117. value = sigletions.get(key);
  118. break;
  119. }
  120. }
  121. }
  122. //允许访问private方法
  123. setter.setAccessible(true);
  124. //把引用对象注入属性
  125. setter.invoke(bean, value);
  126. }
  127. }
  128. } catch (Exception e) {
  129. log.info("set方法注解解析异常..........");
  130. }
  131. }
  132. /**
  133. * 处理在字段上的注解
  134. * @param bean 处理的bean
  135. */
  136. public void fieldAnnotation(Object bean){
  137. try {
  138. //获取其全部的字段描述
  139. Field[] fields = bean.getClass().getFields();
  140. for(Field f : fields){
  141. if(f!=null && f.isAnnotationPresent(ZxfResource.class)){
  142. ZxfResource resource = f.getAnnotation(ZxfResource.class);
  143. String name ="";
  144. Object value = null;
  145. if(resource.name()!=null&&!"".equals(resource.name())){
  146. name = resource.name();
  147. value = sigletions.get(name);
  148. }else{
  149. for(String key : sigletions.keySet()){
  150. //判断当前属性所属的类型是否在配置文件中存在
  151. if(f.getType().isAssignableFrom(sigletions.get(key).getClass())){
  152. //获取类型匹配的实例对象
  153. value = sigletions.get(key);
  154. break;
  155. }
  156. }
  157. }
  158. //允许访问private字段
  159. f.setAccessible(true);
  160. //把引用对象注入属性
  161. f.set(bean, value);
  162. }
  163. }
  164. } catch (Exception e) {
  165. log.info("字段注解解析异常..........");
  166. }
  167. }
  168. /**
  169. * 获取Map中的对应的bean实例
  170. * @param beanId
  171. * @return
  172. */
  173. public Object getBean(String beanId) {
  174. return sigletions.get(beanId);
  175. }
  176. public static void main(String[] args) {
  177. ClassPathXMLApplicationContext path = new ClassPathXMLApplicationContext(
  178. "configAnnotation.xml");
  179. UserServiceImpl userService =(UserServiceImpl)path.getBean("userService");
  180. userService.show();
  181. }
  182. }
个人分类: spring

Java注解的基本概念和原理及其简单实用的更多相关文章

  1. SpringInAction--自动化装配(显示装配之 java注解配置)

    Spring在配置时候有三种方案可选 1.在xml中进行显示配置 2.在java中进行显示配置 3.隐式的Bean发现机制和自动装配 今天学习的 第二种—— 在java中进行显示配置 场景: 尽管在很 ...

  2. Java中的泛型 (上) - 基本概念和原理

    本节我们主要来介绍泛型的基本概念和原理 后续章节我们会介绍各种容器类,容器类可以说是日常程序开发中天天用到的,没有容器类,难以想象能开发什么真正有用的程序.而容器类是基于泛型的,不理解泛型,我们就难以 ...

  3. Java线程:概念与原理

    Java线程:概念与原理 一.操作系统中线程和进程的概念 现在的操作系统是多任务操作系统.多线程是实现多任务的一种方式. 进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程 ...

  4. Java IO学习笔记:概念与原理

    Java IO学习笔记:概念与原理   一.概念   Java中对文件的操作是以流的方式进行的.流是Java内存中的一组有序数据序列.Java将数据从源(文件.内存.键盘.网络)读入到内存 中,形成了 ...

  5. 认识下java注解的实现原理

    1,什么是注解 注解也叫元数据,例如常见的@Override和@Deprecated,注解是JDK1.5版本开始引入的一个特性,用于对代码进行说明,可以对包.类.接口.字段.方法参数.局部变量等进行注 ...

  6. Java编程的逻辑 (35) - 泛型 (上) - 基本概念和原理

    本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http:/ ...

  7. Java 注解的概念与种类

    Java 注解的概念与种类 一,什么是注解 注解和XML文件都是常用的,对web项目进行配置性描述的方式. 举个最简单的例子,对于一个Servlet,比如LoginServlet,采用如下方式: @W ...

  8. java@ 注解原理与使用

    Java反射 java反射机制的定义: 在运行转态时(动态的)时. 对于任意一个类,都能够知道这个类的所有属性和方法 对于任意一个对象,都能够知道调用它的任意属性和方法 Class对象 java中用对 ...

  9. Java注解处理器(转)

    Java中的注解(Annotation)是一个很神奇的东西,特别现在有很多Android库都是使用注解的方式来实现的.一直想详细了解一下其中的原理.很有幸阅读到一篇详细解释编写注解处理器的文章.本文的 ...

随机推荐

  1. Js 分别取一个数的百位,十位,个位

    <!DOCTYPE HTML> <html lang="en-US"> <head> <meta charset="UTF-8& ...

  2. vue中在页面渲染完之后获取元素(否则动态渲染的元素获取不到)

    两种方法: 方法一: 使用$nextTick,在异步获得数据之后再获取元素: 方法二: 在then之后再获取该元素: 问题2:vue中监听改变数组的方法: let idx =; this.listIn ...

  3. 数据格式转换(一)PDF转换技术

         PDF(Portable Document Format)文件格式是Adobe公司开发的电子文件格式. 这样的文件格式与操作系统平台无关.这一特点使它成为在Internet上进行电子文档发行 ...

  4. 你不知道的JavaScript(下卷) (Kyle Simpson 著)

    第一部分 起步上路 第1章 深入编程 1.1 代码 1.2 表达式 1.3 实践 1.3.1 输出 1.3.2 输入 1.4 运算符 1.5 值与类型 1.6 代码注释 1.7 变量 1.8 块 1. ...

  5. http1.1 和 http2 的协议对比测试

    http1.1 和 http2 的协议对比测试 http 协议发展了很多年,目前最为流行的是 http 2. 发现有些网站很流行的网站用的 http1.1, 询问后原来是因为有特殊用途. https: ...

  6. 寻找“最好”(4)——不等约束和KKT条件

    不等约束 上篇文章介绍了如何在等式约束下使用拉格朗日乘子法,然而真实的世界哪有那么多等式约束?我们碰到的大多数问题都是不等约束.对于不等约束的优化问题,可以这样描述: 其中f(x)是目标函数,g(x) ...

  7. [转]Spring IOC父子容器简介

    通过HierarchicalBeanFactory接口,Spring的IoC容器可以建立父子层级关联的容器体系,子容器可以访问父容器中的Bean,但父容器不能访问子容器的Bean.在容器内,Bean的 ...

  8. kafka 中的术语

    出处:https://tech.meituan.com/2015/01/13/kafka-fs-design-theory.html table th:first-of-type { width: 7 ...

  9. HanLP二元核心词典详细解析

    本文分析:HanLP版本1.5.3中二元核心词典的存储与查找.当词典文件没有被缓存时,会从文本文件CoreNatureDictionary.ngram.txt中解析出来存储到TreeMap中,然后构造 ...

  10. Java通过webservice接口获取天气信息

    通过SOAP请求的方式获取天气信息并解析返回的XML文件. 参考: http://www.webxml.com.cn/WebServices/WeatherWS.asmx import java.io ...