1. 程式人生 > >Spring註解原理的詳細剖析與實現

Spring註解原理的詳細剖析與實現

一、註解的基本概念和原理及其簡單實用

註解(Annotation)提供了一種安全的類似註釋的機制,為我們在程式碼中新增資訊提供了一種形式化得方法,使我們可以在稍後某個時刻方便的使用這些資料(通過解析註解來使用這些資料),用來將任何的資訊或者元資料與程式元素(類、方法、成員變數等)進行關聯。其實就是更加直觀更加明瞭的說明,這些說明資訊與程式業務邏輯沒有關係,並且是供指定的工具或框架使用的。Annotation像一種修飾符一樣,應用於包、型別、構造方法、方法、成員變數、引數及本地變數的申明語句中。

Annotation其實是一種介面。通過java的反射機制相關的API來訪問Annotation資訊。相關類(框架或工具中的類)根據這些資訊來決定如何使用該程式元素或改變它們的行為。Java語言直譯器在工作時會忽略這些Annotation,因此在JVM中這些Annotation是“不起作用”的,只能通過配套的工具才能對這些Annotation型別的資訊進行訪問和處理。

Annotation和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 允許子類繼承父類中的註解


@Target(ElementType.METHOD) 
@Retention(RetentionPolicy.RUNTIME) 
@Documented 
@Inherited

下面的示例來簡單的講述spring註解原理:

本例實現了在set方法上和在欄位屬性上註解的處理解析。

1、定義註解

Java程式碼  收藏程式碼
  1. package com.yt.annotation;  
  2. import java.lang.annotation.ElementType;  
  3. import java.lang.annotation.Retention;  
  4. import java.lang.annotation.RetentionPolicy;  
  5. import java.lang.annotation.Target;  
  6. /** 
  7.  * @Description:定義註解 
  8.  * @ClassName: ZxfResource 
  9.  * @Project: spring-aop 
  10.  * @Author: zxf 
  11.  * @Date: 2011-6-7 
  12.  */  
  13. // 在執行時執行  
  14. @Retention(RetentionPolicy.RUNTIME)  
  15. // 註解適用地方(欄位和方法)  
  16. @Target({ ElementType.FIELD, ElementType.METHOD })  
  17. public @interface ZxfResource {  
  18.     //註解的name屬性  
  19.     public String name() default "";  
  20. }  

 2、帶有註解的服務類

Java程式碼  收藏程式碼
  1. package com.yt.annotation;  
  2. /** 
  3.  * @Description: 帶有註解的服務 
  4.  * @ClassName: UserDaoImpl 
  5.  * @Project: spring-aop 
  6.  * @Author: zxf 
  7.  * @Date: 2011-6-7 
  8.  */  
  9. public class UserServiceImpl {  
  10.     public UserDaoImpl userDao;  
  11.     public User1DaoImpl user1Dao;  
  12.     // 欄位上的註解,可以配置name屬性  
  13.     @ZxfResource  
  14.     public User2DaoImpl user2Dao;  
  15.     // set方法上的註解,帶有name屬性  
  16.     @ZxfResource(name = "userDao")  
  17.     public void setUserDao(UserDaoImpl userDao) {  
  18.         this.userDao = userDao;  
  19.     }  
  20.     // set方法上的註解,沒有配置name屬性  
  21.     @ZxfResource  
  22.     public void setUser1Dao(User1DaoImpl user1Dao) {  
  23.         this.user1Dao = user1Dao;  
  24.     }  
  25.     public void show() {  
  26.         userDao.show();  
  27.         user1Dao.show1();  
  28.         user2Dao.show2();  
  29.         System.out.println("這裡是Service方法........");  
  30.     }  
  31. }  

 3、要注入的DAO

Java程式碼  收藏程式碼
  1. package com.yt.annotation;  
  2. /** 
  3.  * @Description: 要注入的DAo類 
  4.  * @ClassName: UserDaoImpl 
  5.  * @Project: spring-aop 
  6.  * @Author: zxf 
  7.  * @Date: 2011-6-7 
  8.  */  
  9. public class UserDaoImpl {  
  10.     String name ;  
  11.     public void show(){  
  12.         System.out.println("這裡是dao方法........");  
  13.     }  
  14. }  
Xml程式碼  收藏程式碼
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans>  
  3.     <bean id = "userDao" class="com.yt.annotation.UserDaoImpl" />  
  4.     <bean id = "user1Dao" class="com.yt.annotation.User1DaoImpl" />  
  5.     <bean id = "user2Dao" class="com.yt.annotation.User2DaoImpl" />  
  6.     <bean id = "userService" class = "com.yt.annotation.UserServiceImpl" />  
  7. </beans>  

 4、註解處理器

Java程式碼  收藏程式碼
  1. package com.yt.annotation;  
  2. import java.beans.Introspector;  
  3. import java.beans.PropertyDescriptor;  
  4. import java.lang.reflect.Field;  
  5. import java.lang.reflect.Method;  
  6. import java.util.ArrayList;  
  7. import java.util.HashMap;  
  8. import java.util.Iterator;  
  9. import java.util.List;  
  10. import java.util.Map;  
  11. import org.apache.log4j.Logger;  
  12. import org.dom4j.Document;  
  13. import org.dom4j.DocumentException;  
  14. import org.dom4j.Element;  
  15. import org.dom4j.io.SAXReader;  
  16. /** 
  17.  * @Description: spring中的註解原理 
  18.  * @ClassName: ClassPathXMLApplicationContext 
  19.  * @Project: spring-aop 
  20.  * @Author: zxf 
  21.  * @Date: 2011-6-3 
  22.  */  
  23. public class ClassPathXMLApplicationContext {  
  24.     Logger log = Logger.getLogger(ClassPathXMLApplicationContext.class);  
  25.     List<BeanDefine> beanList = new ArrayList<BeanDefine>();  
  26.     Map<String, Object> sigletions = new HashMap<String, Object>();  
  27.     public ClassPathXMLApplicationContext(String fileName) {  
  28.         //讀取配置檔案中管理的bean  
  29.         this.readXML(fileName);  
  30.         //例項化bean  
  31.         this.instancesBean();  
  32.         //註解處理器  
  33.         this.annotationInject();  
  34.     }  
  35.     /** 
  36.      * 讀取Bean配置檔案 
  37.      * @param fileName 
  38.      * @return 
  39.      */  
  40.     @SuppressWarnings("unchecked")  
  41.     public void readXML(String fileName) {  
  42.         Document document = null;  
  43.         SAXReader saxReader = new SAXReader();  
  44.         try {  
  45.             ClassLoader classLoader =   
  46.                 Thread.currentThread().getContextClassLoader();  
  47.             document = saxReader.read(classLoader.getResourceAsStream(fileName));  
  48.             Element beans = document.getRootElement();  
  49.             for (Iterator<Element> beansList = beans.elementIterator();   
  50.                 beansList.hasNext();) {  
  51.                 Element element = beansList.next();  
  52.                 BeanDefine bean = new BeanDefine(  
  53.                         element.attributeValue("id"),  
  54.                         element.attributeValue("class"));  
  55.                 beanList.add(bean);  
  56.             }  
  57.         } catch (DocumentException e) {  
  58.             log.info("讀取配置檔案出錯....");  
  59.         }  
  60.     }  
  61.     /** 
  62.      * 例項化Bean 
  63.      */  
  64.     public void instancesBean() {  
  65.         for (BeanDefine bean : beanList) {  
  66.             try {  
  67.                 sigletions.put(bean.getId(),   
  68.                         Class.forName(bean.getClassName()).newInstance());  
  69.             } catch (Exception e) {  
  70.                 log.info("例項化Bean出錯...");  
  71.             }  
  72.         }  
  73.     }  
  74.     /** 
  75.      * 註解處理器 
  76.      * 如果註解ZxfResource配置了name屬性,則根據name所指定的名稱獲取要注入的例項引用, 
  77.      * 如果註解ZxfResource;沒有配置name屬性,則根據屬性所屬型別來掃描配置檔案獲取要 
  78.      * 注入的例項引用 
  79.      *  
  80.      */  
  81.     public void annotationInject(){  
  82.         for(String beanName:sigletions.keySet()){  
  83.             Object bean = sigletions.get(beanName);  
  84.             if(bean!=null){  
  85.                 this.propertyAnnotation(bean);  
  86.                 this.fieldAnnotation(bean);  
  87.             }  
  88.         }  
  89.     }  
  90.     /** 
  91.      * 處理在set方法加入的註解 
  92.      * @param bean 處理的bean 
  93.      */  
  94.     public void propertyAnnotation(Object bean){  
  95.         try {  
  96.             //獲取其屬性的描述  
  97.             PropertyDescriptor[] ps =   
  98.                 Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();  
  99.             for(PropertyDescriptor proderdesc : ps){  
  100.                 //獲取所有set方法  
  101.                 Method setter = proderdesc.getWriteMethod();  
  102.                 //判斷set方法是否定義了註解  
  103.                 if(setter!=null && setter.isAnnotationPresent(ZxfResource.class)){  
  104.                     //獲取當前註解,並判斷name屬性是否為空  
  105.                     ZxfResource resource = setter.getAnnotation(ZxfResource.class);  
  106.                     String name ="";  
  107.                     Object value = null;  
  108.                     if(resource.name()!=

    相關推薦

    Spring註解原理詳細剖析實現

    一、註解的基本概念和原理及其簡單實用 註解(Annotation)提供了一種安全的類似註釋的機制,為我們在程式碼中新增資訊提供了一種形式化得方法,使我們可以在稍後某個時刻方便的使用這些資料(通過解析註解來使用這些資料),用來將任何的資訊或者元資料與程式元素(類、方法、成員變

    【機器學習】演算法原理詳細推導實現(一):線性迴歸

    【機器學習】演算法原理詳細推導與實現(一):線性迴歸 今天我們這裡要講第一個有監督學習演算法,他可以用於一個迴歸任務,這個演算法叫做 線性迴歸 房價預測 假設存在如下 m 組房價資料: 面積(m^2) 價格(萬元) 82.35 193 65.00 213 114.20 255 75.

    【機器學習】演算法原理詳細推導實現(二):邏輯迴歸

    【機器學習】演算法原理詳細推導與實現(二):邏輯迴歸 在上一篇演算法中,線性迴歸實際上是 連續型 的結果,即 \(y\in R\) ,而邏輯迴歸的 \(y\) 是離散型,只能取兩個值 \(y\in \{0,1\}\),這可以用來處理一些分類的問題。 logistic函式 我們可能會遇到一些分類問題,例如想要劃

    【機器學習】演算法原理詳細推導實現(三):樸素貝葉斯

    【機器學習】演算法原理詳細推導與實現(三):樸素貝葉斯 在上一篇演算法中,邏輯迴歸作為一種二分類的分類器,一般的迴歸模型也是是判別模型,也就根據特徵值來求結果概率。形式化表示為 \(p(y|x;\theta)\),在引數 \(\theta\) 確定的情況下,求解條件概率 \(p(y|x)\) 。通俗的解釋為:

    【機器學習】演算法原理詳細推導實現(四):支援向量機(上)

    【機器學習】演算法原理詳細推導與實現(四):支援向量機(上) 在之前的文章中,包括線性迴歸和邏輯迴歸,都是以線性分界線進行分割劃分種類的。而本次介紹一種很強的分類器【支援向量機】,它適用於線性和非線性分界線的分類方法。 函式間隔概念 為了更好的理解非線性分界線,區別兩種分界線對於分類的直觀理解,第一種直觀理解

    【機器學習】演算法原理詳細推導實現(五):支援向量機(下)

    【機器學習】演算法原理詳細推導與實現(五):支援向量機(下) 上一章節介紹了支援向量機的生成和求解方式,能夠根據訓練集依次得出\(\omega\)、\(b\)的計算方式,但是如何求解需要用到核函式,將在這一章詳細推導實現。 核函式 在講核函式之前,要對上一章節得到的結果列舉出來。之前需要優化的凸函式為: \[

    【機器學習】演算法原理詳細推導實現(六):k-means演算法

    【機器學習】演算法原理詳細推導與實現(六):k-means演算法 之前幾個章節都是介紹有監督學習,這個章節介紹無監督學習,這是一個被稱為k-means的聚類演算法,也叫做k均值聚類演算法。 聚類演算法 在講監督學習的時候,通常會畫這樣一張圖: 這時候需要用logistic迴歸或者SVM將這些資料分成正負兩

    【機器學習】演算法原理詳細推導實現(七):決策樹演算法

    # 【機器學習】演算法原理詳細推導與實現(七):決策樹演算法 在之前的文章中,對於介紹的分類演算法有[邏輯迴歸演算法](https://www.cnblogs.com/TTyb/p/10976291.html)和[樸素貝葉斯演算法](https://www.cnblogs.com/TTyb/p/109890

    Atitit spring註解事務的demo程式碼說明 目錄 1.1. Spring框架中,要如何實現事務?有一個註解,@EnableTransactionManagement 1 1.2. 事務管理

    Atitit spring註解事務的demo與程式碼說明 目錄 1.1. Spring框架中,要如何實現事務?有一個註解,@EnableTransactionManagement 1 1.2. 事務管理  99.99999%都是使用了xml來配置的 1 1.3.

    Spring IoC 容器的設計實現原理

    上一篇文章講解的是IOC的原理,這一篇文章主要講解Spring IoC 容器的設計與實現原理   1.spring的IOC容器 在 Spring IoC 容器的設計中,容器有兩個系列,可以看成是容器的具體表現形式: BeanFactory 簡單容器:實現了容器的基本

    Spring方法注入的使用實現原理

    # 一、前言   這幾天為了更詳細地瞭解``Spring``,我開始閱讀``Spring``的官方文件。說實話,之前很少閱讀官方文件,就算是讀,也是讀別人翻譯好的。但是最近由於準備春招,需要了解很多知識點的細節,網上幾乎搜尋不到,只能硬著頭皮去讀官方文件。雖然我讀的這個``Spring`

    AES加密演算法的詳細介紹實現

    #include <stdio.h> #include <stdlib.h> #include <string.h> #include "aes.h" /** * S盒 */ static const int S[16][16] = { 0x63, 0

    Skip List(跳躍表)原理詳解實現

    #include<stdio.h>  #include<stdlib.h>      #define MAX_LEVEL 10 //最大層數      //節點  typedef  struct nodeStructure  {      int key;      int value

    spring boot 原理、demo 打包執行

    Spring  Boot的背景,我們為什麼要用它,它能給我們帶來什麼遍便利?         回首我們以前使用Spring框架的時候,我們需要首先在(如果你使用Maven的話)pom檔案中增加對相關

    隨機森林 演算法原理詳解實現步驟

    #include <cv.h> // opencv general include file #include <ml.h> // opencv machine learning include file #include <stdio.h>

    Spring Security原理學習--簡介示例(一)

    一、簡介 Spring Security 提供了基於javaEE的企業應有個你軟體全面的安全服務。這裡特別強調支援使用SPring框架構件的專案,Spring框架是企業軟體開發javaEE方案的領導者。如果你還沒有使用Spring來開發企業應用程式,我們熱忱的鼓

    讀書筆記——新一代高效視訊編碼H.265HEVC原理、標準實現

    1.視訊編碼標準 視訊編碼標準只是規定了編碼碼流的語法語義和解碼器,只要求視訊編碼後的碼流符合標準的語法結構,解碼器就可以根據碼流的語法語義進行正常解碼。因此,符合某個視訊編碼標準的編碼器是有很大自由度的,只要編碼後的碼流符合標準的規定即可。

    動態規劃之揹包問題原理詳細推導及其實現

    貪心演算法:(1)      給定n個物品,物品價值分別為P1,P2,…,Pn,物品重量分別W1,W2, …, Wn,揹包容量為M。每種物品可部分裝入到揹包中。輸出X1,X2,…,Xn,0<Xi<1, 使得

    高效能的分散式記憶體快取伺服器系統——memcached核心原理詳細剖析

    memcached是什麼? 許多Web應用都將資料儲存到RDBMS中,應用伺服器從中讀取資料並在瀏覽器中顯示。 但隨著資料量的增大、訪問的集中,就會出現RDBMS的負擔加重、資料庫響應惡化、 網站顯示延遲等重大影響。 這時就該memcached

    決策樹相關演算法——Bagging之基於CART的隨機森林詳細說明實現

    1 前言 1.1 本篇部落格主要記錄的是基於CART決策樹實現的隨機森林演算法,主要是從以下四個方面介紹: CART決策樹的構建思想;整合學習中的Bagging思想;基於CART決策樹的隨機森林程式碼實現;隨機森林不易過擬合的分析。(其中不易過擬合併不是說隨機