1. 程式人生 > >教你如何建立註解和淺析註解原理

教你如何建立註解和淺析註解原理

前言:

註解在目前而言最主流的應用:代替配置檔案

關於配置檔案與註解開發的優缺點:

註解優點:開發效率高 成本低 

註解缺點:耦合性大 並且不利於後期維護

常見的註解舉例:

@Override:告知編譯器此方法是覆蓋父類的

@Deprecated:標註過時

@SuppressWarnings:壓制警告

注意:不同的註解只能在不同的位置使用(方法上、欄位上、類上)

1.自定義註解:

註解是給機器看的,註釋是給程式設計師看的,這是兩者的區別。現在各大框架都在使用註解,而我們程式設計師需要做的就是知道如何使用註解,而對其底層原理卻不清楚,今天看了一段視訊,現在淺談一下註解的使用。

2.註解的使用:

  大體分為三部分: 定義註解、使用註解、解析註解。在框架中定義與解析框架都已經為我們做好了。

(1)定義註解:定義一個簡單的註解:

package com.annoation;

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

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnoation {

	//定義註解的屬性,這不是方法
	 String name();//必選註解
	int value() default 20;//有屬性就是可選註解
}

定義前面的@Target,與@Retention又稱為元註解,限制定義的註解的特性:

@Target定義註解使用的位置,

@Retention:限定註解的可見範圍:值有

(2)使用註解

package com.annoation;

public class UseMyAnnotion {
@MyAnnoation(name="zhidao")
	public void show(String str)
	{
		System.err.print(str);
	}
}

(3)解析註解:這裡使用了底層的對映原理

package com.annoation;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class MyAnnationRun {

	/** 
	 * @Title: main 
	 * @Description: TODO 
	 * @param args void
	 * @author mars
	 * @throws NoSuchMethodException 
	 * @throws SecurityException 
	 * @throws InvocationTargetException 
	 * @throws IllegalAccessException 
	 * @throws IllegalArgumentException 
	 * @date 2018-10-18上午11:06:56
	 */
	public static void main(String[] args) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException  {
		//獲取位元組碼物件
		Class clazz=UseMyAnnotion.class;
		Method method = clazz.getMethod("show", String.class);
		//獲取方法上的註解
		MyAnnoation annotation = method.getAnnotation(MyAnnoation.class);
		//獲取註解屬性值
		System.err.println(annotation.name()+"\t"+annotation.value());
	}

}

3.分析註解

現在springboot比較流行,就簡單分析一下springboot整合MyBatis中的@MapperScan註解吧

這是我的專案啟動類

package com.boot.mybatis;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
  @MapperScan("com.boot.mybatis.mapper")  
public class MybatisApplicaiton {
	public static void main(String[] args) {
		SpringApplication.run(MybatisApplicaiton.class, args);
	}
}

點進去看一下@MapperScan的原始碼:

 * @author Michael Lanyon
 * @author Eduardo Macarron
 *
 * @since 1.2.0
 * @see MapperScannerRegistrar
 * @see MapperFactoryBean
 * @version $Id$
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MapperScannerRegistrar.class)
public @interface MapperScan {

  /**

可以發現該註解上邊還有

@Retention(RetentionPolicy.RUNTIME)   定義該註解的可見範圍 @Target(ElementType.TYPE)            定義該註解的的元素型別 @Documented                           javadoc文件生成工具的使用 @Import(MapperScannerRegistrar.class)   類似於之前xml配置中的import標籤,可以用於依賴第三方包中bean的配置和載入 在4.2之前只支援匯入配置類 在4.2,@Import註解支援匯入普通的java類,並將其宣告成一個bean

在這裡@Import註解起到了至關重要的作用,我們可以將MapperScannerRegistrar加上斷點可以發現,專案啟動過程中會被攔截,說明專案啟動過程中會執行該類,執行過程如下:

簡述一下,執行流程就是首先根據標註的@MapperScan 獲取basePackage或者根據@Mapper獲取所在packages,之後通過 ClassPathMapperScanner去掃描包,獲取所有Mapper介面類的BeanDefinition,之後具體配置,設定beanClass為MapperFactoryBean,設定MapperFactoryBean的構造器引數為實際的Mapper介面類,通過ClassPathBeanDefinitionScanner父類進行bean註冊,自動注入的時候,就會呼叫MapperFactoryBean的getObject方法獲取實際型別的例項。