热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

使用Java注解模拟springioc容器过程解析

这篇文章主要介绍了使用Java注解模拟springioc容器过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

使用注解,简单模拟spring ioc容器。通过注解给对象属性注入值。

项目结构

annotation 包,用于存放自定义注解

Component 注解表示该类为组件类,并需要声明名字

package priv.haidnor.annotation;

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

/**
 * 组件
 */
@Target(value = ElementType.TYPE)
@Retention(value = RetentionPolicy.RUNTIME)
public @interface Component {
	String name();
}

Value 注解用于给类的属性赋值

package priv.haidnor.annotation;

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

/**
 * 字段值
 */
@Target(value = ElementType.FIELD)
@Retention(value = RetentionPolicy.RUNTIME)
public @interface Value {
	String value();
}

ioc 包

package priv.haidnor.ioc;

import priv.haidnor.annotation.Component;
import priv.haidnor.annotation.Value;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

public class ApplicationContext {

	/**
	 * IOC 控制反转容器,在加载类的时候创建 HashMap , 并存入指定对象
	 */
	private static Map ioc;

	static {
		try {
			// 初始化 IOC 容器
			ioc = new HashMap();

			// 反射获得 Class 对象
			Class<&#63;> clazz = Class.forName("priv.haidnor.pojo.Person");

			// 获取指定注解
			Component compOnentClass= clazz.getAnnotation(Component.class);

			// 获取指定注解的值
			String key = componentClass.name();

			// 通过反射创建对象
			Object object = clazz.newInstance();
			ioc.put(key, object);

			// 获取 Java Bean 所有的字段
			Field[] fields = clazz.getDeclaredFields();

			for (Field field : fields) {
				// 字段类型
				Class<&#63;> type = field.getType();

				// 根据字段名生成 set 方法
				String filedName = field.getName();
				String methodName = produceSetMethodName(filedName);

				// 获得 Value 注解
				Value valueAnnotation = field.getAnnotation(Value.class);

				// 获得注解的值
				String theValue = valueAnnotation.value();

				// 构造 Method 对象
				Method method = clazz.getDeclaredMethod(methodName, field.getType());

				// 将注解参数转换类型
				Object value = typeConversion(field.getType(), theValue);

				// 执行 set 方法
				method.invoke(object, value);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 类型转换。将 String 字符串转换为指定数据类型类型的值
	 * @param typeClass 字段类型
	 * @param value 注解值
	 * @return 字符串转换为指定数据类型类型的值
	 */
	private static Object typeConversion(Class<&#63;> typeClass, String value) {
		if (typeClass == int.class || typeClass == Integer.class) {
			if (value == null) {
				return 0;
			}
			return Integer.valueOf(value);
		} else if (typeClass == short.class) {
			if (value == null) {
				return 0;
			}
			return Short.valueOf(value);
		} else if (typeClass == byte.class) {
			if (value == null) {
				return 0;
			}
			return Short.valueOf(value);
		} else if (typeClass == double.class) {
			if (value == null) {
				return 0;
			}
			return Double.valueOf(value);
		} else if (typeClass == long.class) {
			if (value == null) {
				return 0;
			}
			return Long.valueOf(value);
		} else if (typeClass == String.class) {
			if (value == null) {
				return "";
			}
			return value;
		} else if (typeClass == Boolean.class) {
			if (value == null) {
				return false;
			}
			return Boolean.valueOf(value);
		} else if (typeClass == BigDecimal.class) {
			if (value == null) {
				return new BigDecimal(0);
			}
			return new BigDecimal(value + "");
		} else {
			return typeClass.cast(value);
		}
	}

	/**
	 * 拼接字符串,生成 set 方法名
	 * @param filedName 字段名
	 * @return set方法名,例如传入"name",则返回"setName"
	 */
	private static String produceSetMethodName(String filedName) {
		return "set" + filedName.substring(0, 1).toUpperCase() + filedName.substring(1);
	}

	/**
	 * 从容器中获得指定对象
	 * @param name 对象名称
	 * @return IOC 容器中的对象
	 */
	public static Object getBean(String name) {
		return ioc.get(name);
	}
}

pojo 包

package priv.haidnor.pojo;

import priv.haidnor.annotation.Component;
import priv.haidnor.annotation.Value;

@Component(name = "man")
public class Person {

	@Value("张三")
	private String name;

	@Value("男")
	private String gender;

	@Value("中国")
	private String country;

	@Value("23")
	private Integer age;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getGender() {
		return gender;
	}

	public void setGender(String gender) {
		this.gender = gender;
	}

	public String getCountry() {
		return country;
	}

	public void setCountry(String country) {
		this.country = country;
	}

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}

	@Override
	public String toString() {
		return "Person{" +
				"name='" + name + '\'' +
				", gender='" + gender + '\'' +
				", country='" + country + '\'' +
				", age=" + age +
				'}';
	}
}

测试类

import priv.haidnor.ioc.ApplicationContext;
import priv.haidnor.pojo.Person;

/**
 * 测试类
 */
public class Demo {
	public static void main(String[] args) {
		Person person = (Person) ApplicationContext.getBean("man");
		System.out.println(person);
	}
}

运行程序后,控制台输出对象信息,可以看到从ioc容器中拿出的对象已经成功被注解赋值

备注

内置注解

@Override:定义在java.lang.Override中,此注释只适用于修辞方法,表示一个方法声明打算重写超类中的另一个方法声明.

@Deprecated:定义在java.lang.Deprecated中,此注释可以用于修辞方法,属性,类,表示不鼓励程序员使用这样的元素,通常是因为它很危险或者存在更好的选择.

@SuppressWarnings:定义在java.lang.SuppressWarnings中,用来抑制编译时的警告信息.口与前两个注释有所不同,你需要添加一个参数才能正确使用,这些参数都是已经定义好了的,我们选择性的使用就好了.

  • @SuppressWarnings ("all")
  • @SuppressWarnings ("unchecked")
  • @SuppressWarnings (value={"unchecked","deprecation"})
  • 等等……

4个元注解

元注解的作用就是负责注解其他注解,Java定义了4个标准的meta-annotation类型,他们被用来提供对其他annotation类型作说明.
这些类型和它们所支持的类在java.lang.annotation包中可以找到

@Target:用于描述注解的使用范围(即:作用域,被描述的注解可以用在什么地方)

@Target(value = {ElementType.TYPE,ElementType.CONSTRUCTOR})
@Target(value = ElementType.TYPE)
@Target(ElementType.TYPE)

类,接口(包括注释类型)或枚举声明
  TYPE

字段声明(包括枚举常量)
  FIELD

方法声明
  METHOD

形式参数声明
  PARAMETER

构造声明
  CONSTRUCTOR

局部变量声明
  LOCAL_VARIABLE

注解类型声明
  ANNOTATION_TYPE

包声明
  PACKAGE

类型参数声明 @since 1.8
  TYPE_PARAMETER

使用类型 @since 1.8
  TYPE_USE

@Retention:表示需要在什么级别保存该注释信息,用于描述注解的生命周期 (SOURCE

@Retention(value = RetentionPolicy.CLASS)
@Retention(RetentionPolicy.CLASS)

注解将被编译阶段丢弃
  SOURCE
注解将由编译器记录在类文件中,但VM不必在运行时保留它们。这是默认行为。
  CLASS
注解由编译器记录在类文件中,并在运行时由VM保留,因此可以通过反射方式读取它们
  RUNTIME

@Document:说明该注解将被包含在javadoc中

@lnherited:说明子类可以继承父类中的该注解

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


推荐阅读
  • Web开发框架概览:Java与JavaScript技术及框架综述
    Web开发涉及服务器端和客户端的协同工作。在服务器端,Java是一种优秀的编程语言,适用于构建各种功能模块,如通过Servlet实现特定服务。客户端则主要依赖HTML进行内容展示,同时借助JavaScript增强交互性和动态效果。此外,现代Web开发还广泛使用各种框架和库,如Spring Boot、React和Vue.js,以提高开发效率和应用性能。 ... [详细]
  • 如何在方法上应用@ConfigurationProperties注解进行属性绑定 ... [详细]
  • 在《Cocos2d-x学习笔记:基础概念解析与内存管理机制深入探讨》中,详细介绍了Cocos2d-x的基础概念,并深入分析了其内存管理机制。特别是针对Boost库引入的智能指针管理方法进行了详细的讲解,例如在处理鱼的运动过程中,可以通过编写自定义函数来动态计算角度变化,利用CallFunc回调机制实现高效的游戏逻辑控制。此外,文章还探讨了如何通过智能指针优化资源管理和避免内存泄漏,为开发者提供了实用的编程技巧和最佳实践。 ... [详细]
  • 深入解析Struts、Spring与Hibernate三大框架的面试要点与技巧 ... [详细]
  • 阿里巴巴终面技术挑战:如何利用 UDP 实现 TCP 功能?
    在阿里巴巴的技术面试中,技术总监曾提出一道关于如何利用 UDP 实现 TCP 功能的问题。当时回答得不够理想,因此事后进行了详细总结。通过与总监的进一步交流,了解到这是一道常见的阿里面试题。面试官的主要目的是考察应聘者对 UDP 和 TCP 在原理上的差异的理解,以及如何通过 UDP 实现类似 TCP 的可靠传输机制。 ... [详细]
  • 视频编码涉及多个关键参数,如比特率、帧率和采样率等。比特率(Bit Rate)是指单位时间内视频或音频文件的数据传输量,通常以千比特每秒(Kbps)为单位。这些参数对视频质量和文件大小有重要影响。帧率(Frame Rate)表示每秒钟显示的图像帧数,而采样率(Sample Rate)则指每秒从连续信号中提取并形成离散信号的次数。了解这些基础概念有助于更好地优化视频编码效果。 ... [详细]
  • OpenAI首席执行官Sam Altman展望:人工智能的未来发展方向与挑战
    OpenAI首席执行官Sam Altman展望:人工智能的未来发展方向与挑战 ... [详细]
  • 如何撰写适应变化的高效代码:策略与实践
    编写高质量且适应变化的代码是每位程序员的追求。优质代码的关键在于其可维护性和可扩展性。本文将从面向对象编程的角度出发,探讨实现这一目标的具体策略与实践方法,帮助开发者提升代码效率和灵活性。 ... [详细]
  • 提升 Kubernetes 集群管理效率的七大专业工具
    Kubernetes 在云原生环境中的应用日益广泛,然而集群管理的复杂性也随之增加。为了提高管理效率,本文推荐了七款专业工具,这些工具不仅能够简化日常操作,还能提升系统的稳定性和安全性。从自动化部署到监控和故障排查,这些工具覆盖了集群管理的各个方面,帮助管理员更好地应对挑战。 ... [详细]
  • 《Spring in Action 第4版:全面解析与实战指南》
    《Spring in Action 第4版:全面解析与实战指南》不仅详细介绍了Spring框架的核心优势,如简洁易测试、低耦合特性,还深入探讨了其轻量级和最小侵入性的设计原则。书中强调了声明式编程的优势,并通过基于约定的方法简化开发流程。此外,Spring的模板机制有效减少了重复代码,而依赖注入功能则由容器自动管理,确保了应用的灵活性和可维护性。 ... [详细]
  • Spring框架的核心组件与架构解析 ... [详细]
  • 本文作为探讨PHP依赖注入容器系列文章的开篇,将首先通过具体示例详细阐述依赖注入的基本概念及其重要性,为后续深入解析容器的实现奠定基础。 ... [详细]
  • Python应用实例大揭秘:七大令人惊叹的高阶技巧展示
    2020年,Python无疑成为了最炙手可热的编程语言,其影响力已远远超出程序员的范畴。从初学者到资深从业者,甚至小学生,都在纷纷加入Python的学习热潮中。凭借其低门槛、易上手和强大的功能,Python正逐渐成为各行业不可或缺的工具。本文将揭示七个令人惊叹的Python高级应用技巧,帮助读者进一步提升编程水平。 ... [详细]
  • 工作8年后薪资从1万跃升至7万,网友惊叹:本科学历实属难得
    一位本科毕业生在工作8年后,凭借扎实的技术能力和不断的学习提升,成功将月薪从1万元提高到7万元,引发了网友们的广泛赞叹。这一成就不仅体现了个人的努力与坚持,也反映了当前技术领域对高素质人才的迫切需求。 ... [详细]
  • B站服务器故障影响豆瓣评分?别担心,阿里巴巴架构师分享预防策略与技术方案
    13日晚上,在视频观看高峰时段,B站出现了服务器故障,引发网友在各大平台上的广泛吐槽。这一事件导致了连锁反应,大量用户纷纷涌入A站、豆瓣和晋江等平台,给这些网站带来了突如其来的流量压力。为了防止类似问题的发生,阿里巴巴架构师分享了一系列预防策略和技术方案,包括负载均衡、弹性伸缩和容灾备份等措施,以确保系统的稳定性和可靠性。 ... [详细]
author-avatar
kongxujimo
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有