Java注解

https://www.atatech.org/articles/52027

 

浅析 Java 注解

     问题缘起是在看别人代码时偶然看到 @interface 的应用,看的一知半解。我自己对注解这一块并不是很熟悉,一直以来都停留在用的层面,今天借着问题对注解这块稍微深入一下,收集整理了一些自认为有价值的内容,以供用时翻阅。

    关于 java 注解的概念介绍,找到了一篇介绍详尽的文档:
转自:http://www.cnblogs.com/peida/archive/2013/04/26/3038503.html

     标准注解我们平时经常会用到,但通过 @interface 定义的自定义注解用的比较少,相对来说使用比较多得是 @Autowired、@Value、@Resource 这类 Spring 注解,这类注解都是 RUNTIME 运行时注解,标准注解中除了 @Override 外也都是运行时注解,@Override 是 SOURCE 注解,当 @RetentionPolicy 不指定时默认是 CLASS 注解,CLASS 注解相对使用比较少,比较:http://stackoverflow.com/questions/5971234/retentionpolicy-class-vs-runtime
    以下通过模拟 @Resource 的实现案例简单回顾下注解的使用。
    首先自定运行时注解 @ZxfResource, 指定其适用于字段属性和方法

// 在运行时执行
@Retention(RetentionPolicy.RUNTIME)
// 注解适用地方 (字段和方法)
@Target({ElementType.FIELD, ElementType.METHOD})
public @interface ZxfResource {
<span class="hljs-comment">//注解的name属性</span>
<span class="hljs-keyword">public</span> String name() default <span class="hljs-string">""</span>;

}

    定义用户类 UserDaoImpl

public class UserDaoImpl {
String name ;

<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">show</span>()</span>{
	System.<span class="hljs-keyword">out</span>.println(<span class="hljs-string">"这里是dao方法........"</span>);
}

}

定义用户服务类UserServiceImpl

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 方法........");
	}
}

     编写 Spring bean 的 xml 文件

<?xml version="1.0" encoding="UTF-8"?>  
<beans>  
    <bean id = "userDao" class="com.taobao.test.UserDaoImpl" />  
    <bean id = "user1Dao" class="com.taobao.test.User1DaoImpl" />  
    <bean id = "user2Dao" class="com.taobao.test.User2DaoImpl" />  
    <bean id = "userService" class = "com.taobao.test.UserServiceImpl" />  
</beans>  

     Springbean 可以通过简单的 id 和包路径定义,因此可以定义 springbean 定义类

public class BeanDefine {
<span class="hljs-keyword">public</span> <span class="hljs-title class_">String</span> id;
<span class="hljs-keyword">public</span> <span class="hljs-title class_">String</span> className;

<span class="hljs-keyword">public</span> <span class="hljs-title class_">BeanDefine</span>(<span class="hljs-title class_">String</span> id, <span class="hljs-title class_">String</span> className) {
	<span class="hljs-variable language_">this</span>.<span class="hljs-property">id</span> = id;
	<span class="hljs-variable language_">this</span>.<span class="hljs-property">className</span> = className;
}

<span class="hljs-keyword">public</span> <span class="hljs-title class_">String</span> <span class="hljs-title function_">getId</span>(<span class="hljs-params"></span>) {
	<span class="hljs-keyword">return</span> id;
}

<span class="hljs-keyword">public</span> <span class="hljs-built_in">void</span> <span class="hljs-title function_">setId</span>(<span class="hljs-params"><span class="hljs-built_in">String</span> id</span>) {
	<span class="hljs-variable language_">this</span>.<span class="hljs-property">id</span> = id;
}

<span class="hljs-keyword">public</span> <span class="hljs-title class_">String</span> <span class="hljs-title function_">getClassName</span>(<span class="hljs-params"></span>) {
	<span class="hljs-keyword">return</span> className;
}

<span class="hljs-keyword">public</span> <span class="hljs-built_in">void</span> <span class="hljs-title function_">setClassName</span>(<span class="hljs-params"><span class="hljs-built_in">String</span> className</span>) {
	<span class="hljs-variable language_">this</span>.<span class="hljs-property">className</span> = className;
}

}

     模拟 Spring 加载 bean 的过程

public class ClassPathXMLApplicationContext {
<span class="hljs-title class_">Logger</span> log = <span class="hljs-title class_">Logger</span>.<span class="hljs-title function_">getLogger</span>(<span class="hljs-title class_">ClassPathXMLApplicationContext</span>.<span class="hljs-property">class</span>);

<span class="hljs-title class_">List</span>&lt;<span class="hljs-title class_">BeanDefine</span>&gt; beanList = <span class="hljs-keyword">new</span> <span class="hljs-title class_">ArrayList</span>&lt;<span class="hljs-title class_">BeanDefine</span>&gt;();
<span class="hljs-title class_">Map</span>&lt;<span class="hljs-title class_">String</span>, <span class="hljs-title class_">Object</span>&gt; sigletions = <span class="hljs-keyword">new</span> <span class="hljs-title class_">HashMap</span>&lt;<span class="hljs-title class_">String</span>, <span class="hljs-title class_">Object</span>&gt;();

<span class="hljs-keyword">public</span> <span class="hljs-title class_">ClassPathXMLApplicationContext</span>(<span class="hljs-title class_">String</span> fileName) {
	<span class="hljs-comment">//读取配置文件中管理的bean</span>
	<span class="hljs-variable language_">this</span>.<span class="hljs-title function_">readXML</span>(fileName);
	<span class="hljs-comment">//实例化bean</span>
	<span class="hljs-variable language_">this</span>.<span class="hljs-title function_">instancesBean</span>();
	<span class="hljs-comment">//注解处理器</span>
	<span class="hljs-variable language_">this</span>.<span class="hljs-title function_">annotationInject</span>();
}

<span class="hljs-comment">/**
 * 读取Bean配置文件
 * <span class="hljs-doctag">@param</span> <span class="hljs-variable">fileName</span>
 * <span class="hljs-doctag">@return</span>
 */</span>
<span class="hljs-meta">@SuppressWarnings</span>(<span class="hljs-string">"unchecked"</span>)
<span class="hljs-keyword">public</span> <span class="hljs-built_in">void</span> <span class="hljs-title function_">readXML</span>(<span class="hljs-params"><span class="hljs-built_in">String</span> fileName</span>) {
	<span class="hljs-title class_">Document</span> <span class="hljs-variable language_">document</span> = <span class="hljs-literal">null</span>;
	<span class="hljs-title class_">SAXReader</span> saxReader = <span class="hljs-keyword">new</span> <span class="hljs-title class_">SAXReader</span>();
	<span class="hljs-keyword">try</span> {
		<span class="hljs-title class_">ClassLoader</span> classLoader = <span class="hljs-title class_">Thread</span>.<span class="hljs-title function_">currentThread</span>().<span class="hljs-title function_">getContextClassLoader</span>();
		<span class="hljs-variable language_">document</span> = saxReader.<span class="hljs-title function_">read</span>(classLoader.<span class="hljs-title function_">getResourceAsStream</span>(fileName));
		<span class="hljs-title class_">Element</span> beans = <span class="hljs-variable language_">document</span>.<span class="hljs-title function_">getRootElement</span>();
		<span class="hljs-keyword">for</span> (<span class="hljs-title class_">Iterator</span>&lt;<span class="hljs-title class_">Element</span>&gt; beansList = beans.<span class="hljs-title function_">elementIterator</span>(); beansList.<span class="hljs-title function_">hasNext</span>();) {
			<span class="hljs-title class_">Element</span> element = beansList.<span class="hljs-title function_">next</span>();
			<span class="hljs-title class_">BeanDefine</span> bean = <span class="hljs-keyword">new</span> <span class="hljs-title class_">BeanDefine</span>(
					element.<span class="hljs-title function_">attributeValue</span>(<span class="hljs-string">"id"</span>),
					element.<span class="hljs-title function_">attributeValue</span>(<span class="hljs-string">"class"</span>));
			beanList.<span class="hljs-title function_">add</span>(bean);
		}
	} <span class="hljs-keyword">catch</span> (<span class="hljs-title class_">DocumentException</span> e) {
		log.<span class="hljs-title function_">info</span>(<span class="hljs-string">"读取配置文件出错...."</span>);
	}
}

<span class="hljs-comment">/**
 * 实例化Bean
 */</span>
<span class="hljs-keyword">public</span> <span class="hljs-built_in">void</span> <span class="hljs-title function_">instancesBean</span>(<span class="hljs-params"></span>) {
	<span class="hljs-keyword">for</span> (<span class="hljs-title class_">BeanDefine</span> bean : beanList) {
		<span class="hljs-keyword">try</span> {
			sigletions.<span class="hljs-title function_">put</span>(bean.<span class="hljs-title function_">getId</span>(), <span class="hljs-title class_">Class</span>.<span class="hljs-title function_">forName</span>(bean.<span class="hljs-title function_">getClassName</span>()).<span class="hljs-title function_">newInstance</span>());
		} <span class="hljs-keyword">catch</span> (<span class="hljs-title class_">Exception</span> e) {
			log.<span class="hljs-title function_">info</span>(<span class="hljs-string">"实例化Bean出错..."</span>);
		}
	}
}

<span class="hljs-comment">/**
 * 注解处理器
 * 如果注解ZxfResource配置了name属性,则根据name所指定的名称获取要注入的实例引用,如果注解ZxfResource
 * 没有配置name属性,则根据属性所属类型来扫描配置文件获取要注入的实例引用
 * 
 */</span>
<span class="hljs-keyword">public</span> <span class="hljs-built_in">void</span> <span class="hljs-title function_">annotationInject</span>(<span class="hljs-params"></span>){
	<span class="hljs-keyword">for</span>(<span class="hljs-title class_">String</span> <span class="hljs-attr">beanName</span>:sigletions.<span class="hljs-title function_">keySet</span>()){
		<span class="hljs-title class_">Object</span> bean = sigletions.<span class="hljs-title function_">get</span>(beanName);
		<span class="hljs-keyword">if</span>(bean!=<span class="hljs-literal">null</span>){
			<span class="hljs-variable language_">this</span>.<span class="hljs-title function_">propertyAnnotation</span>(bean);
			<span class="hljs-variable language_">this</span>.<span class="hljs-title function_">fieldAnnotation</span>(bean);
		}
	}
}

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

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

<span class="hljs-comment">/**
 * 获取Map中的对应的bean实例
 * <span class="hljs-doctag">@param</span> <span class="hljs-variable">beanId</span>
 * <span class="hljs-doctag">@return</span>
 */</span>
<span class="hljs-keyword">public</span> <span class="hljs-title class_">Object</span> <span class="hljs-title function_">getBean</span>(<span class="hljs-params"><span class="hljs-built_in">String</span> beanId</span>) {
	<span class="hljs-keyword">return</span> sigletions.<span class="hljs-title function_">get</span>(beanId);
}


<span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-built_in">void</span> <span class="hljs-title function_">main</span>(<span class="hljs-params"><span class="hljs-built_in">String</span>[] args</span>) {
	<span class="hljs-title class_">ClassPathXMLApplicationContext</span> path = <span class="hljs-keyword">new</span> <span class="hljs-title class_">ClassPathXMLApplicationContext</span>(<span class="hljs-string">"springbeans-test.xml"</span>);
	<span class="hljs-title class_">UserServiceImpl</span> userService =(<span class="hljs-title class_">UserServiceImpl</span>)path.<span class="hljs-title function_">getBean</span>(<span class="hljs-string">"userService"</span>);
	userService.<span class="hljs-title function_">show</span>();
}

}
调试即可清晰认识@Resource注解在Spring bean加载过程中的使用过程。

 以上模拟 @Resource 注解使用转自:http://zxf-noimp.iteye.com/blog/1071765