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

使用注解,简单模拟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<String, Object> ioc;

	static {
		try {
			// 初始化 IOC 容器
			ioc = new HashMap<String, Object>();

			// 反射获得 Class 对象
			Class<?> 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<?> 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<?> 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<CLASS<RUNTIME)

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

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

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

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

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

时间:2020-07-07

深入理解java的spring-ioc的使用

spring-ioc的使用 IOC容器在很多框架里都在使用,而在spring里它被应用的最大广泛,在框架层面上,很多功能都使用了ioc技术,下面我们看一下ioc的使用方法. 把服务注册到ioc容器 使用属性注入反射对应类型的实例 多态情况下,使用名称反射类型的实例 把服务注册到ioc容器 @Bean注册组件 使用@Bean注解进行类型的注册,默认你的ioc容器里类型为bean的返回值,名称为bean所有的方法名,与你的包名称没有直接关系,如果你的接口有多种实现,在注册时可以使用@Bean("li

用java的spring实现一个简单的IOC容器示例代码

要想深入的理解IOC的技术原理,没有什么能比的上我们自己实现它.这次我们一起实现一个简单IOC容器.让大家更容易理解Spring IOC的基本原理. 这里会涉及到一些java反射的知识,如果有不了解的,可以自己去找些资料看看. 注意 在上一篇文章,我说,启动IOC容器时,Spring会将xml文件里面配置的bean扫描并实例化,其实这种说法不太准确,所以我在这里更正一下,xml文件里面配置的非单利模式的bean,会在第一次调用的时候被初始化,而不是启动容器的时候初始化.但是我们这次要做的例子是容

java获取包下被指定注解的类过程解析

方案一: 采用reflections 框架(此框架依赖com.google.guava) 1.reflections框架地址:https://github.com/ronmamo/reflections 2.项目依赖 <dependency> <groupId>org.reflections</groupId> <artifactId>reflections</artifactId> <version>0.9.11</versi

Spring学习笔记1之IOC详解尽量使用注解以及java代码

在实战中学习Spring,本系列的最终目的是完成一个实现用户注册登录功能的项目. 预想的基本流程如下: 1.用户网站注册,填写用户名.密码.email.手机号信息,后台存入数据库后返回ok.(学习IOC,mybatis,SpringMVC的基础知识,表单数据验证,文件上传等) 2.服务器异步发送邮件给注册用户.(学习消息队列) 3.用户登录.(学习缓存.Spring Security) 4.其他. 边学习边总结,不定时更新.项目环境为Intellij + Spring4. 一.准备工作. 1.m

Java对象转json JsonFormat注解

写在前面,首先,我用的java转json序列化的工具是java开源的jackson. 今天在做后端接口的时候,发现获取的json对象中少了几个属性,因为其他的接口都能得到正确的json,所以很快就找到了问题所在,先上代码 public class ChargeDto implements Serializable { private static final long serialVersionUID = -4617215025083571608L; protected Integer cId;

深入理解Java的Spring框架中的IOC容器

Spring IOC的原型 spring框架的基础核心和起点毫无疑问就是IOC,IOC作为spring容器提供的核心技术,成功完成了依赖的反转:从主类的对依赖的主动管理反转为了spring容器对依赖的全局控制. 这样做的好处是什么呢? 当然就是所谓的"解耦"了,可以使得程序的各模块之间的关系更为独立,只需要spring控制这些模块之间的依赖关系并在容器启动和初始化的过程中将依据这些依赖关系创建.管理和维护这些模块就好,如果需要改变模块间的依赖关系的话,甚至都不需要改变程序代码,只需要将

浅析Java的Spring框架中IOC容器容器的应用

Spring容器是Spring框架的核心.容器将创建对象,它们连接在一起,配置它们,并从创建到销毁管理他们的整个生命周期.在Spring容器使用依赖注入(DI)来管理组成应用程序的组件.这些对象被称为Spring Beans. 容器获得其上的哪些对象进行实例化,配置和组装通过阅读提供的配置元数据的说明.配置元数据可以通过XML,Java注释或Java代码来表示.下面的图是Spring如何工作的高层次图. Spring IoC容器是利用Java的POJO类和配置元数据的产生完全配置和可执行的系统或

Java注解@Transactional事务类内调用不生效问题及解决办法

@Transactional 内部调用例子

bootstrap折叠调用collapse()后data-parent不生效的快速解决办法

今天做的项目,用到了bootstrap的折叠功能,这个功能需要只展开一个折叠框,点击一个就会自动隐藏另一个,初始按照API做了一下,发现一切运行正常,但是测试的同事提了一个bug,说切换到其他模块后再切换回来,发现原先展开的折叠框没有折叠起来–即恢复原样.于是又去修改代码,回来的时候对所有折叠框调用: .collapse(‘hide’)方法. $(".love .collapse").collapse(‘hide’); 调用之后发现,点击连接苗,data-parent失效了,也就是可

vue mounted 调用两次的完美解决办法

开发中发现其中一个页面moutned调用了两次,而其他页面正常,表示很懵逼,然后查找原因,终于找到了,其实归根到底是要知道mounted的调用机制问题: 情况:在这个页面中出现了mounted 加载了两次的情况: 方法:排除法 首先把 this.$store.commit() 方法注释掉,发现就好了,只加载一次 初步判断是commit  方法导致的 二  验证判断是否正确,不使用commit 方法,该用直接改变变量状态的方法,发现又加载了两次: 再次判断,不是由于commit引起的 三   猜

docker容器调用yum报错的解决办法

dockerfile里或者在容器里执行yum,报错,找不到源(invalid baseurl xxx),但是宿主机上执行yum是没问题的啊,为什么? 因为不论是dockerfile使用RUN关键字执行yum还是直接进入到容器里面执行yum,它们都是使用的docker镜像里面的源(CentOS是在路径/etc/yum.repo.d/CentOS-Base.repo),所以你要把宿主机上的同路径下的源拷贝到容器里面,然后docker commit一个新的"基础镜像",这个时候使用docke

java 打印一字符串,并在main()方法内调用它

这个是写的Java的第一个程序. 这个就是java 语言的基本框架了的吧 package com.itheima; /** * 1. 编写一个方法(名字自定,但要符合Java编码规范),方法内打印一字符串,并在main()方法内调用它. * @author 281167413@qq.com */ public class Test1 { public static void main(String[] args) { System.out.println("My first station! i

Java如何基于ProcessBuilder类调用外部程序

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

这篇文章主要介绍了Java如何基于ProcessBuilder类调用外部程序,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1. demo1 @Test public void testProcessBuilder() { ProcessBuilder processBuilder = new ProcessBuilder(); // processBuilder.command("ping","127.0.0.1"

Java中JDBC事务与JTA分布式事务总结与区别

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

Java事务的类型有三种:JDBC事务.JTA(Java Transaction API)事务.容器事务.常见的容器事务如Spring事务,容器事务主要是J2EE应用服务器提供的,容器事务大多是基于JTA完成,这是一个基于JNDI的,相当复杂的API实现.所以本文暂不讨论容器事务.本文主要介绍J2EE开发中两个比较基本的事务:JDBC事务和JTA事务. JDBC事务 JDBC的一切行为包括事务是基于一个Connection的,在JDBC中是通过Connection对象进行事务管理.在JDBC中,

浅谈Spring中@Transactional事务回滚及示例(附源码

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

一.使用场景举例 在了解@Transactional怎么用之前我们必须要先知道@Transactional有什么用.下面举个栗子:比如一个部门里面有很多成员,这两者分别保存在部门表和成员表里面,在删除某个部门的时候,假设我们默认删除对应的成员.但是在执行的时候可能会出现这种情况,我们先删除部门,再删除成员,但是部门删除成功了,删除成员的时候出异常了.这时候我们希望如果成员删除失败了,之前删除的部门也取消删除.这种场景就可以使用@Transactional事物回滚. 二.checked异常和unc

详解Java注解教程及自定义注解

Java注解提供了关于代码的一些信息,但并不直接作用于它所注解的代码内容.在这个教程当中,我们将学习Java的注解,如何定制注解,注解的使用以及如何通过反射解析注解. Java1.5引入了注解,当前许多java框架中大量使用注解,如Hibernate.Jersey.Spring.注解作为程序的元数据嵌入到程序当中.注解可以被一些解析工具或者是编译工具进行解析.我们也可以声明注解在编译过程或执行时产生作用. 在使用注解之前,程序源数据只是通过java注释和javadoc,但是注解提供的功能要远远超

Java注解Annotation解析

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

概述 Java在1.5版本引入注解Annotation,又称Java标注,注解是一种语法元数据,可以被直接使用到源代码中,类/方法/变量/参数/包名等都可以被注解.和Javadoc标签不同,编译器在生成class文件时候能够保留注解代码,同时,可能为了在程序运行过程中(run-time)可以使用注解,Java虚拟机会把注解保留,这样就可以通过反射获取注解Annotation的相关信息. 内置注解 其实我们平时会经常遇见注解,例如@Override.@Deprecated等等,这些都是JDK中内置

深入理解Java注解类型(@Annotation)

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

Java注解是在JDK5时引入的新特性,鉴于目前大部分框架(如spring)都使用了注解简化代码并提高编码的效率,因此掌握并深入理解注解对于一个Java工程师是来说是很有必要的事.本篇我们将通过以下几个角度来分析注解的相关知识点 理解Java注解 实际上Java注解与普通修饰符(public.static.void等)的使用方式并没有多大区别,下面的例子是常见的注解: public class AnnotationDemo { //@Test注解修饰方法A @Test public static

原文 

https://www.zhangshengrong.com/p/w4N7DmqAXr/

本站部分文章源于互联网,本着传播知识、有益学习和研究的目的进行的转载,为网友免费提供。如有著作权人或出版方提出异议,本站将立即删除。如果您对文章转载有任何疑问请告之我们,以便我们及时纠正。

PS:推荐一个微信公众号: askHarries 或者qq群:474807195,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

转载请注明原文出处:Harries Blog™ » 使用Java注解模拟spring ioc容器过程解析

赞 (0)
分享到:更多 ()

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址