Java的注解机制——Spring自动装配的实现原理
JDK1.5加入了对注解机制的支持,实际上我学习Java的时候就已经使用JDK1.6了,而且除了@Override和@SuppressWarnings(后者还是IDE给生成的……)之外没接触过其他的。
进入公司前的面试,技术人员就问了我关于注解的问题,我就说可以生成chm手册……现在想起来真囧,注释和注解被我搞得完全一样了。
使用注解主要是在需要使用Spring框架的时候,特别是使用SpringMVC。因为这时我们会发现它的强大之处:预处理。
注解实际上相当于一种标记,它允许你在运行时(源码、文档、类文件我们就不讨论了)动态地对拥有该标记的成员进行操作。
实现注解需要三个条件(我们讨论的是类似于Spring自动装配的高级应用):注解声明、使用注解的元素、操作使用注解元素的代码。
首先是注解声明,注解也是一种类型,我们要定义的话也需要编写代码,如下:
1 package annotation; 2 3 import java.lang.annotation.ElementType; 4 import java.lang.annotation.Retention; 5 import java.lang.annotation.RetentionPolicy; 6 import java.lang.annotation.Target; 7 8 /** 9 * 自定义注解,用来配置方法 10 * 11 * @author Johness 12 * 13 */ 14 @Retention(RetentionPolicy.RUNTIME) // 表示注解在运行时依然存在 15 @Target(ElementType.METHOD) // 表示注解可以被使用于方法上 16 public @interface SayHiAnnotation { 17 String paramValue() default "johness"; // 表示我的注解需要一个参数 名为"paramValue" 默认值为"johness" 18 }
然后是使用我们注解的元素:
1 package element; 2 3 import annotation.SayHiAnnotation; 4 5 /** 6 * 要使用SayHiAnnotation的元素所在类 7 * 由于我们定义了只有方法才能使用我们的注解,我们就使用多个方法来进行测试 8 * 9 * @author Johness 10 * 11 */ 12 public class SayHiEmlement { 13 14 // 普通的方法 15 public void SayHiDefault(String name){ 16 System.out.println("Hi, " + name); 17 } 18 19 // 使用注解并传入参数的方法 20 @SayHiAnnotation(paramValue="Jack") 21 public void SayHiAnnotation(String name){ 22 System.out.println("Hi, " + name); 23 } 24 25 // 使用注解并使用默认参数的方法 26 @SayHiAnnotation 27 public void SayHiAnnotationDefault(String name){ 28 System.out.println("Hi, " + name); 29 } 30 }
最后,是我们的操作方法(值得一提的是虽然有一定的规范,但您大可不必去浪费精力,您只需要保证您的操作代码在您希望的时候执行即可):
1 package Main; 2 3 import java.lang.reflect.InvocationTargetException; 4 import java.lang.reflect.Method; 5 6 import element.SayHiEmlement; 7 import annotation.SayHiAnnotation; 8 9 public class AnnotionOperator { 10 public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, ClassNotFoundException { 11 SayHiEmlement element = new SayHiEmlement(); // 初始化一个实例,用于方法调用 12 Method[] methods = SayHiEmlement.class.getDeclaredMethods(); // 获得所有方法 13 14 for (Method method : methods) { 15 SayHiAnnotation annotationTmp = null; 16 if((annotationTmp = method.getAnnotation(SayHiAnnotation.class))!=null) // 检测是否使用了我们的注解 17 method.invoke(element,annotationTmp.paramValue()); // 如果使用了我们的注解,我们就把注解里的"paramValue"参数值作为方法参数来调用方法 18 else 19 method.invoke(element, "Rose"); // 如果没有使用我们的注解,我们就需要使用普通的方式来调用方法了 20 } 21 } 22 }
结果为:Hi, Jack
Hi, johness
Hi, Rose
可以看到,注解是进行预处理的很好方式(这里的预处理和编译原理有区别)!
接下来我们看看Spring是如何使用注解机制完成自动装配的:
首先是为了让Spring为我们自动装配要进行的操作,无外乎两种:继承org.springframework.web.context.support.SpringBeanAutowiringSupport类或者添加@Component/@Controller等注解并(只是使用注解方式需要)在Spring配置文件里声明context:component-scan元素。
我说说继承方式是如何实现自动装配的,我们打开Spring源代码查看SpringBeanAutowiringSupport类。我们会发现以下语句:
1 public SpringBeanAutowiringSupport() { 2 processInjectionBasedOnCurrentContext(this); 3 }
众所周知,Java实例构造时会调用默认父类无参构造方法,Spring正是利用了这一点,让"操作元素的代码"得以执行!(我看到第一眼就震惊了!真是奇思妙想啊。果然,高手都要善于用Java来用Java)
后面的我就不就不多说了,不过还是要纠正一些人的观点:说使用注解的自动装配来完成注入也需要setter。这明显是错误的嘛!我们看Spring注解装配(继承方式)的方法调用顺序: org.springframework.web.context.support.SpringBeanAutowiringSupport#SpringBeanAutowiringSupport=>
org.springframework.web.context.support.SpringBeanAutowiringSupport#processInjectionBasedOnCurrentContext=>
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#processInjection=>
org.springframework.beans.factory.annotation.InjectionMetadata#Injection(继承,方法重写)。最后看看Injection方法的方法体:
1 /** 2 * Either this or {@link #getResourceToInject} needs to be overridden. 3 */ 4 protected void inject(Object target, String requestingBeanName, PropertyValues pvs) throws Throwable { 5 if (this.isField) { 6 Field field = (Field) this.member; 7 ReflectionUtils.makeAccessible(field); 8 field.set(target, getResourceToInject(target, requestingBeanName)); 9 } 10 else { 11 if (checkPropertySkipping(pvs)) { 12 return; 13 } 14 try { 15 Method method = (Method) this.member; 16 ReflectionUtils.makeAccessible(method); 17 method.invoke(target, getResourceToInject(target, requestingBeanName)); 18 } 19 catch (InvocationTargetException ex) { 20 throw ex.getTargetException(); 21 } 22 } 23 }
虽然不完全,但可以基本判定此种自动装配是使用了java放射机制。
欢迎您移步我们的交流群,无聊的时候大家一起打发时间:
或者通过QQ与我联系:
(最后编辑时间2013-04-19 09:52:27)
转载于:https://www.cnblogs.com/Johness/archive/2013/04/17/3026689.html
Java的注解机制——Spring自动装配的实现原理相关推荐
- Spring自动装配(基于注解)
从 Java 5 开始,Java 增加了对注解(Annotation)的支持,它是代码中的一种特殊标记,可以在编译.类加载和运行时被读取,执行相应的处理.开发人员可以通过注解在不改变原有代码和逻辑的情 ...
- spring——Spring自动装配(基于注解)(转载)
从 Java 5 开始,Java 增加了对注解(Annotation)的支持,它是代码中的一种特殊标记,可以在编译.类加载和运行时被读取,执行相应的处理. 开发人员可以通过注解在不改变原有代码和逻辑的 ...
- 【Spring注解系列13】Spring自动装配总结:@Autowired、@Resource、@Qualifier、@Inject
目录 1.@Autowired.@Resource.@Qualifier.@Inject 1).@Autowired 2).@Resource与@Inject 3). @Autowired参数取值 2 ...
- java 自动装配_spring自动装配是什么?spring自动装配方式
Spring是受欢迎的企业级Java应用程序开发框架,数以百万的来自世界各地的开发人员都在使用 Spring 框架创建高性能.易于测试和可重用的代码. 自动装配是Spring框架的重要功能,是使用Sp ...
- spring注解驱动开发-4 Spring 自动装配
Spring 自动装配 前言 Spring 自动装配的几种方式 1.@Autowired @Qualifier("组件id") @Primary 2.@Resource方式 3.@ ...
- Spring自动装配注解
Spring自动装配注解 注解 来源 特点与区别 备注 @Autowired Spring定义 Spring提供自动装配注解 @Autowired详解 @Resource(JSR250) java注解 ...
- Spring自动装配----注解装配----Spring自带的@Autowired注解
Spring自动装配----注解装配----Spring自带的@Autowired注解 父类 package cn.ychx;public interface Person {public void ...
- spring自动装配、注解
spring自动装配 Spring 自动装配 byName 这种模式由属性名称指定自动装配.Spring 容器看作 beans,在 XML 配置文件中 beans 的 auto-wire 属性设置为 ...
- (二)Spring自动装配
Spring自动装配 为了减少XML的配置数量.Spring提供了几种技巧来解决这一问题: 自动装配(autowiring): 有助于减少<property>元素和<constroc ...
最新文章
- springboot设置文件上传大小(tomcat默认1M)
- LVS原理详解(3种工作方式8种调度算法)--老男孩
- 6亿数据秒级查询,ClickHouse太快了!
- 熟练掌握python是什么概念-想要熟练掌握Python元组?你需要了解这10件应知事项...
- java中replace函数
- 链表python笔试题目_python经典面试算法题1.4:如何对链表进行重新排序
- CATALINA_BASE和CATALINA_HOME,多实例tomcat与多版本tomcat运行
- 为什么国内SaaS很难爆发
- 突发!Spring 也沦陷了。。。
- Linux谁访问这个内存,Linux中的直接内存访问
- Java EE体系概述
- RabbitMQ 幂等性概念及业界主流解决方案
- 两年以后重读了一篇文章,写了点东西。
- Maxwell安装与配置
- 原来我们一直在『回家』的路上
- SSM框架-Spring(一)
- c语言文字居中,如何设置select和option的文字居中?
- 修改进程的各种limits的方法
- AutoSAR入门到精通讲解 (AuroSAR-CP描述) 1.1 AutoSAR-CP简介
- 【手把手带你Godot游戏开发】FlappyBird:1.Hello World
热门文章
- 湖南工程学院计算机网络考试,湖南工程学院 计算机网络期末试卷试题
- apache ajax 跨域访问,Apache 实现AJAX跨域请求
- Linux怎么处理binray文件,Linux下如何反汇编arm raw binary文件
- leetcode 344. 反转字符串 541. 反转字符串 II 双指针解
- 机器学习笔记:PCA的简单理解以及应用建议
- kotlin 覆盖属性_Kotlin程序| 方法覆盖的示例
- python 示例_带有示例的Python文件关闭属性
- Java LinkedHashMap getOrDefault()方法与示例
- python关键字和保留字_或带有Python示例的关键字
- Java——匿名内部类实现线程的两种方式