教你如何建立註解和淺析註解原理
前言:
註解在目前而言最主流的應用:代替配置檔案
關於配置檔案與註解開發的優缺點:
註解優點:開發效率高 成本低
註解缺點:耦合性大 並且不利於後期維護
常見的註解舉例:
@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方法獲取實際型別的例項。