动力节点首页 全国咨询热线:400-8080-105

绑定手机号,登录
手机号

验证码

微信登录
手机号登录
手机号

验证码

微信登录与注册
微信扫码登录与注册

扫码关注微信公众号完成登录与注册
手机号登录
首页 > 文章

Spring注解的实现

07-14 11:00 665浏览
举报 T字号
  • 大字
  • 中字
  • 小字

注解呢,是java本身自带的一个东西,它基于java接口进行实现,是一种特殊的接口类型,通常对于注解来说,三种情况,一个是在编译前就会被丢弃的,一个是编译后留在class中的,另一种是会一直存在,运行的时候注解也会被保留,而框架的注解一般都是第三种。

Class对象,Method对象,Parameter对象,Constructor对象等java反射对象通常都具有getAnnotation方法可以直接获取保留到运行时的注解实例,就像这样:

@Component
class AnnoTest {
}

这样的一个类,有一个component注解,我们可以通过这样:

Component comp = AnnoTest.class.getAnnotation(Component.class);
Annotation[] annotations = AnnoTest.class.getAnnotations();
// 其实还有两个注解的get方法,你可以自己去看,这里不多说。

就直接得到了class上面的注解。

注解和普通接口不一样,他声明的语法比较特别,public @interface 注解名这个样子。为了标识注解的使用范围,你需要使用一些java提供的几个其他注解,这些用来描述注解的注解被称为元注解。

@Retention,保留范围(在源码中存在,还是在字节码里面,还是一直留到运行环境),一般是Runtime,

@Target 注解的作用对象,类型还是字段还是方法,这个注解是写在什么地方的。

@Inherited 是否可以继承此注解,这个注解仅仅在针对类的注解中起效,如果一个类继承了使用了含有他的注解的父类,那么这个类也会拥有父类的那个注解。

@Documented 注解再生成JavaDoc的时候是否会被写入Javadoc。

总之,这样就是有一个注解了,比如这样:

@Retention(RUNTIME)
@Target(ElementType.TYPE) 
public @interface Component {
	/**
	 * 组件名称
	 * @return
	 */
	String name() default "";	
	/**
	 * 组件创建类型
	 * @return
	 */
	Scope scope() default Scope.SINGLE;	
}

这里要特别的说下注解接口的方法:这些方法由返回值,方法名称构成,具体的值是你写注解的时候填进去的,例如上述注解的name,实际上是你在使用注解的时候放在@component(name="xxxx")这里面的那个name,这些方法可以使用default指定一个默认返回值,即,你在使用注解的时候没有填写这个东西,会返回的内容。

接下来,你要用反射的手法拿到这些带有注解的class,method,field之类的,然后get到他们的注解,然后对注解进行处理,无论是aop还是注入,按照你的需要自己实现。

这里有一个例子,这个是仿照spring进行properties文件进行值注入的方法,他通过读取class的configProperties注解得到properties文件的位置,然后注入到bean的字段中。

public Object prcess(Object target, Definition definition, IFactory factory) {
	Class<?> clazz = definition.getClazz();
	ConfigProperties config = clazz.getAnnotation(ConfigProperties.class);
	if (config == null) {
		return target;
	}
	String location = config.value();
	if (!location.startsWith(File.separator)) {
		location = File.separator + location;
	}
		
	URL url = clazz.getResource(location);
	Properties props = new Properties();
	try {
		props.load(url.openStream());
		// 这个只是对properties的封装,就当他是普通properties好了
		PropertiesConfig propsConfig = new PropertiesConfig();
		propsConfig.setProperties(props);
		Set<String> keys = props.stringPropertyNames();
		for (String propName : keys) {
			String fieldName = propName.replace(config.prefix() + ".", "");
			try {
				//按照properties的key,去掉前缀后读取类的字段Field
				Field field = clazz.getDeclaredField(fieldName);
				// 开启操作权限
				field.setAccessible(true);
				// 字段不是string型就需要转换一下
				if (field.getType() != String.class) {
					// 获取类型转换器
					ICovertor covertor = Covertors
					  .getCovertor(String.class, field.getType());
					if (covertor != null) {
						// 转换类型并且注入
						field.set(target, covertor
						  .covert(propsConfig.get(propName)));
					} else {
						// 反向获取类型转换器(这里的转换器接口
						//是双向的,其实这样区分方向转换不是很好,
						//但是我现在没有来得及改他。
						covertor = Covertors
					 	    .getCovertorRev(field.getType(), 
						    String.class);
						// 转换并注入, 其实这里应该判空,
						// 但是当时应该是我忘记了
						field.set(target, covertor.
						 covertRev(propsConfig.get(propName)));
					}
				} else {
					// 类型一致,直接注入
					field.set(target, propsConfig.get(propName));
				}
			} catch (Exception e) {
				// 注入失败也无所谓,无视这个字段下一个注入
			}
		}
	} catch (IOException e) {
		throw new RuntimeException(e);
	}
	return target;
}

注解接口:

@Retention(RUNTIME)
@Target(TYPE)
@Component
public @interface ConfigProperties {
	String value();
	String prefix();
}

动力节点在线课程涵盖零基础入门,高级进阶,在职提升三大主力内容,覆盖Java从入门到就业提升的全体系学习内容。全部Java视频教程免费观看,相关学习资料免费下载!对于火爆技术,每周一定时更新!如果想了解更多相关技术,可以到动力节点在线免费观看Spring框架视频教程学习哦!

0人推荐
共同学习,写下你的评论
0条评论
代码小兵124
程序员代码小兵124

99篇文章贡献336699字

相关课程 更多>

作者相关文章更多>

推荐相关文章更多>

Java面试题及答案整理

提枪策马乘胜追击04-21 20:01

Spring常见面试题

代码小兵92504-17 16:07

Java零基础实战项目——五子棋

代码小兵98804-25 13:57

Java string类详解

杨晶珍05-11 14:54

6道经典算法面试题

杨晶珍05-12 16:39

发评论

举报

0/150

取消