千寻

道路很长, 开始了就别停下!

0%

Spring注解原理的详细剖析与实现

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

注解(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。

  • 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 允许子类继承父类中的注解

1
2
3
4
@Target(ElementType.METHOD) 
@Retention(RetentionPolicy.RUNTIME) 
@Documented 
@Inherited

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

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

1、定义注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.yt.annotation;  

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* @Description:定义注解
* @ClassName: ZxfResource
* @Project: spring-aop
* @Author: zxf
* @Date: 2011-6-7
*/
// 在运行时执行
@Retention(RetentionPolicy.RUNTIME)
// 注解适用地方(字段和方法)
@Target({ ElementType.FIELD, ElementType.METHOD })
public @interface ZxfResource {

//注解的name属性
public String name() default "";
}

2、带有注解的服务类

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
32
33
34
35
36
37
package com.yt.annotation;  

/**
* @Description: 带有注解的服务
* @ClassName: UserDaoImpl
* @Project: spring-aop
* @Author: zxf
* @Date: 2011-6-7
*/
public class UserServiceImpl {

public UserDaoImpl userDao;
public User1DaoImpl user1Dao;

// 字段上的注解,可以配置name属性
@ZxfResource
public User2DaoImpl user2Dao;

// set方法上的注解,带有name属性
@ZxfResource(name = "userDao")
public void setUserDao(UserDaoImpl userDao) {
this.userDao = userDao;
}

// set方法上的注解,没有配置name属性
@ZxfResource
public void setUser1Dao(User1DaoImpl user1Dao) {
this.user1Dao = user1Dao;
}

public void show() {
userDao.show();
user1Dao.show1();
user2Dao.show2();
System.out.println("这里是Service方法........");
}
}

3、要注入的DAO

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.yt.annotation;  

/**
* @Description: 要注入的DAo类
* @ClassName: UserDaoImpl
* @Project: spring-aop
* @Author: zxf
* @Date: 2011-6-7
*/
public class UserDaoImpl {

String name ;

public void show(){
System.out.println("这里是dao方法........");
}
}
1
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8"?>  
<beans>
<bean id = "userDao" class="com.yt.annotation.UserDaoImpl" />
<bean id = "user1Dao" class="com.yt.annotation.User1DaoImpl" />
<bean id = "user2Dao" class="com.yt.annotation.User2DaoImpl" />
<bean id = "userService" class = "com.yt.annotation.UserServiceImpl" />
</beans>

4、注解处理器

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
package com.yt.annotation;  

import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

/**
* @Description: spring中的注解原理
* @ClassName: ClassPathXMLApplicationContext
* @Project: spring-aop
* @Author: zxf
* @Date: 2011-6-3
*/
public class ClassPathXMLApplicationContext {

Logger log = Logger.getLogger(ClassPathXMLApplicationContext.class);

List<BeanDefine> beanList = new ArrayList<BeanDefine>();
Map<String, Object> sigletions = new HashMap<String, Object>();

public ClassPathXMLApplicationContext(String fileName) {
//读取配置文件中管理的bean
this.readXML(fileName);
//实例化bean
this.instancesBean();
//注解处理器
this.annotationInject();
}

/**
* 读取Bean配置文件
* @param fileName
* @return
*/
@SuppressWarnings("unchecked")
public void readXML(String fileName) {
Document document = null;
SAXReader saxReader = new SAXReader();
try {
ClassLoader classLoader =
Thread.currentThread().getContextClassLoader();
document = saxReader.read(classLoader.getResourceAsStream(fileName));
Element beans = document.getRootElement();
for (Iterator<Element> beansList = beans.elementIterator();
beansList.hasNext();) {
Element element = beansList.next();
BeanDefine bean = new BeanDefine(
element.attributeValue("id"),
element.attributeValue("class"));
beanList.add(bean);
}
} catch (DocumentException e) {
log.info("读取配置文件出错....");
}
}

/**
* 实例化Bean
*/
public void instancesBean() {
for (BeanDefine bean : beanList) {
try {
sigletions.put(bean.getId(),
Class.forName(bean.getClassName()).newInstance());
} catch (Exception e) {
log.info("实例化Bean出错...");
}
}
}

/**
* 注解处理器
* 如果注解ZxfResource配置了name属性,则根据name所指定的名称获取要注入的实例引用,
* 如果注解ZxfResource;没有配置name属性,则根据属性所属类型来扫描配置文件获取要
* 注入的实例引用
*
*/
public void annotationInject(){
for(String beanName:sigletions.keySet()){
Object bean = sigletions.get(beanName);
if(bean!=null){
this.propertyAnnotation(bean);
this.fieldAnnotation(bean);
}
}
}

/**
* 处理在set方法加入的注解
* @param bean 处理的bean
*/
public void propertyAnnotation(Object bean){
try {
//获取其属性的描述
PropertyDescriptor[] ps =
Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();
for(PropertyDescriptor proderdesc : ps){
//获取所有set方法
Method setter = proderdesc.getWriteMethod();
//判断set方法是否定义了注解
if(setter!=null && setter.isAnnotationPresent(ZxfResource.class)){
//获取当前注解,并判断name属性是否为空
ZxfResource resource = setter.getAnnotation(ZxfResource.class);
String name ="";
Object value = null;
if(resource.name()!=null&&!"".equals(resource.name())){
//获取注解的name属性的内容
name = resource.name();
value = sigletions.get(name);
}else{ //如果当前注解没有指定name属性,则根据类型进行匹配
for(String key : sigletions.keySet()){
//判断当前属性所属的类型是否在配置文件中存在
if(proderdesc.getPropertyType().isAssignableFrom(sigletions.get(key).getClass())){
//获取类型匹配的实例对象
value = sigletions.get(key);
break;
}
}
}
//允许访问private方法
setter.setAccessible(true);
//把引用对象注入属性
setter.invoke(bean, value);
}
}
} catch (Exception e) {
log.info("set方法注解解析异常..........");
}
}

/**
* 处理在字段上的注解
* @param bean 处理的bean
*/
public void fieldAnnotation(Object bean){
try {
//获取其全部的字段描述
Field[] fields = bean.getClass().getFields();
for(Field f : fields){
if(f!=null && f.isAnnotationPresent(ZxfResource.class)){
ZxfResource resource = f.getAnnotation(ZxfResource.class);
String name ="";
Object value = null;
if(resource.name()!=null&&!"".equals(resource.name())){
name = resource.name();
value = sigletions.get(name);
}else{
for(String key : sigletions.keySet()){
//判断当前属性所属的类型是否在配置文件中存在
if(f.getType().isAssignableFrom(sigletions.get(key).getClass())){
//获取类型匹配的实例对象
value = sigletions.get(key);
break;
}
}
}
//允许访问private字段
f.setAccessible(true);
//把引用对象注入属性
f.set(bean, value);
}
}
} catch (Exception e) {
log.info("字段注解解析异常..........");
}
}

/**
* 获取Map中的对应的bean实例
* @param beanId
* @return
*/
public Object getBean(String beanId) {
return sigletions.get(beanId);
}


public static void main(String[] args) {
ClassPathXMLApplicationContext path = new ClassPathXMLApplicationContext(
"configAnnotation.xml");
UserServiceImpl userService =(UserServiceImpl)path.getBean("userService");
userService.show();
}
}