本文只是用于记录个人在学习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