前言:
注解在目前而言最主流的应用:代替配置文件
关于配置文件与注解开发的优缺点:
注解优点:开发效率高 成本低
注解缺点:耦合性大 并且不利于后期维护
常见的注解举例:
@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方法获取实际类型的实例。