本文只是用于记录个人在学习annotation过程中的心德,所以知识面不太完善。
1、注解的基本概念
包、类型、构造方法、方法、成员变量、参数及本地变量的标记。
程序后续可以利用java的反射机制来了解各种元素是否有何标记,针对不同的标记,作出相应的操作。
总而言之,annotation并没有那么玄乎,并不是打个标记就会帮你做什么事情,这个要做的事情还是要在后续配套的反射函数来自己实现。
2、spring注解的原理
以前看到spring的各种注解、xml配置就可以实现很多的东西,对新手而言是很难理解的,但其实只要懂了java的注解原理,这些都是很简单的。就好像spring 在xml里面配置了
以下便以一个读取xml中配置的注解例子来理解一下原理(这个例子我是照搬zxf的,这个原博主我找不到了,因为看的都是别人转载的,我觉得这个例子很好,所以就照搬过来了)
1、定义注解
package
com.yulam.myannotation.annotation
;
import
java.lang.annotation.ElementType
;
import
java.lang.annotation.
Retention
;
import
java.lang.annotation.RetentionPolicy
;
import
java.lang.annotation.
Target
;
/**
*
@author:
5yl
* email:
massyulin@gmail.com
* time : 2018/1/24 下午10:49
*/
// 在运行时执行
@Retention
(RetentionPolicy.
RUNTIME
)
// 注解适用地方(字段和方法)
@Target
({ ElementType.
FIELD
,
ElementType.
METHOD
})
public
@
interface
ZxfResource
{
//注解的name属性
public
String
name
()
default
""
;
}
2、 带有注解的服务类
ublic 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、要注入的类
其中2、3类我就不一一列出来了,但是会放上源码
package com.yulam.myannotation.dao
;
/**
*
@author:
5yl
* email:
massyulin@gmail.com
* time : 2018/1/24 下午10:53
*/
public class
name
;
public void
show(){
out.println(
"这里是dao方法........")
;
}
4、xml文件
<?
xml version
="1.0"
encoding
="UTF-8"
?>
<beans>
<!--这里的class记得改,不然后面反射找不到 -->
<bean
id
= "userDao"
class
="com.yulam.myannotation.dao.UserDaoImpl"
/>
<bean
id
= "user1Dao"
class
="com.yulam.myannotation.dao.User1DaoImpl"
/>
<bean
id
= "user2Dao"
class
="com.yulam.myannotation.dao.User2DaoImpl"
/>
<bean
id
= "userService"
class
= "com.yulam.myannotation.service.UserServiceImpl"
/>
</beans>
5、与注解配套的处理器
其中有定义一个BeanDefine,这个只是简单的pojo,只有id、className两个属性用于装载xml解析出来的bean
package com.yulam.myannotation.service
;
import com.yulam.myannotation.annotation.
ZxfResource
;
import com.yulam.myannotation.pojo.BeanDefine
;
import lombok.extern.slf4j.
Slf4j
;
import org.dom4j.Document
;
import org.dom4j.DocumentException
;
import org.dom4j.Element
;
import org.dom4j.io.SAXReader
;
import java.beans.Introspector
;
import java.beans.PropertyDescriptor
;
import java.lang.reflect.Field
;
import java.lang.reflect.Method
;
import java.util.*
;
/**
*
@author:
5yl
* email:
massyulin@gmail.com
* time : 2018/1/25 上午9:29
*/
@Slf4j
public class
// 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) {
null;
SAXReader saxReader =
new SAXReader()
;
try
ClassLoader classLoader =
currentThread().getContextClassLoader()
;
document = saxReader.read(classLoader.getResourceAsStream(fileName))
;
Element beans = document.getRootElement()
;
for (Iterator<Element> beansList = beans.elementIterator()
;
beansList.hasNext()
;) {
;
BeanDefine bean =
new
"id")
,
element.attributeValue(
"class"))
;
beanList.add(bean)
;
catch
log.info(
"读取配置文件出错....")
;
}
/**
* 实例化Bean
*/
public void
instancesBean() {
for (BeanDefine bean :
beanList) {
try
sigletions.put(bean.getId()
,
Class.
forName(bean.getClassName()).newInstance())
;
}
catch
log.info(
"实例化Bean出错...")
;
}
}
/**
* 注解处理器
* 如果注解ZxfResource配置了name属性,则根据name所指定的名称获取要注入的实例引用,
* 如果注解ZxfResource;没有配置name属性,则根据属性所属类型来扫描配置文件获取要
* 注入的实例引用
*
*/
public void
annotationInject(){
for(String beanName:
sigletions.keySet()){
sigletions.get(beanName)
;
if(bean!=
null){
this.propertyAnnotation(bean)
;
this.fieldAnnotation(bean)
;
}
}
/**
* 处理在set方法加入的注解
*
@param
bean
处理的bean
*/
public void
propertyAnnotation(Object bean){
try
//获取其属性的描述
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
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())){
;
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
log.info(
"字段注解解析异常..........")
;
}
/**
* 获取Map中的对应的bean实例
*
@param
beanId
*
@return
*/
public Object
getBean(String beanId) {
return
sigletions.get(beanId)
;
}
6、运行函数
package com.yulam.myannotation.service
;
import static org.junit.Assert.*
;
public class
public static void
main(String[] args) {
new
"configAnnotation.xml")
;
UserServiceImpl userService =(UserServiceImpl)path.getBean(
"userService")
;
userService.show()
;
}
结果:
这里是dao方法........
这里是dao1111方法........
这里是dao22222方法........
这里是Service方法........
Process finished with exit code 0