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

网友投稿 330 2022-12-02


使用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.hahttp://idnor.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> 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) {

cVdRTwzIAT 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

注解类型http://声明

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:说明子类可以继承父类中的该注解

@Retention(value = RetentionPolicy.CLASS)

@Retention(RetentionPolicy.CLASS)

注解将被编译阶段丢弃

SOURCE

注解将由编译器记录在类文件中,但VM不必在运行时保留它们。这是默认行为。

CLASS

注解由编译器记录在类文件中,并在运行时由VM保留,因此可以通过反射方式读取它们

RUNTIME

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

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


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Springmvc自定义异常处理器实现流程解析
下一篇:windows环境下java开发工具maven的安装教程图解
相关文章

 发表评论

暂时没有评论,来抢沙发吧~