spring项目中我们经常使用到spring的一个注解@Autowired,这个注解是用于实现spring的特性,IOC(Inversion of Control)控制反转和DI依赖注入,spring将项目中的实体进行集中管理,然后通过@Autowired注解作为标识,以自动注入的方式来给实体注入属性,这些操作都是基于java反射机制来实现的。
因为前段时间学习了反射的一些知识,遂尝试使用反射知识来简单实现@Autowired的注入功能。
自定义注入注解@CustomAutowired
用于标识需要被注入的属性
import java.lang.annotation.*;
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CustomAutowired {
}
User
需要被注入的类,User有个私有属性name
public class User {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Company
被注入User实例对象的Company
public class Company {
@CustomAutowired
private User user;
public void getUserName(){
System.out.println(user.getName());
}
}
MainTest
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class MainTest {
public static void main(String[] args) {
try {
//获取Company的Class
Class companyClass = Company.class;
//新建compant对象实例
Object company = companyClass.newInstance();
//获取Company中所有的字段
Field[] fields = companyClass.getDeclaredFields();
//开始循环
for (int i = 0; i < fields.length; i++) {
//获取字段
Field tempField = fields[i];
//获取字段上的注解
Annotation[] annotations = tempField.getAnnotations();
//循环注解
for (int j = 0; j < annotations.length; j++) {
//获取字段上注解的类型
Class tempAnnotationClass = annotations[j].annotationType();
//判断如果注解的类型是自定义的注入注解
if(tempAnnotationClass == CustomAutowired.class){
//获取字段的类型
Class fieldClass = tempField.getType();
//新建字段的实例对象
Object fieldObject = fieldClass.newInstance();
//如果字段类型是我新建的User的类型的话
if(fieldClass == User.class){
//获取User类中的name属性字段
Field nameField = fieldClass.getDeclaredField("name");
//因为User里的name字段是private的,所以要先设置访问权限为true
nameField.setAccessible(true);
//然后再给name字段设值
nameField.set(fieldObject,"呆某人");
//Company中的User字段也是private,所以也需要设置权限
tempField.setAccessible(true);
//最后给company实例对象中的user字段赋值
tempField.set(company,fieldObject);
}
}
}
}
//获取Company中的所有方法
Method[] methods = companyClass.getMethods();
//开始循环
for (int i = 0; i < methods.length; i++) {
//找到方法名是getUserName的方法
if("getUserName".equals(methods[i].getName())){
//进行调用
methods[i].invoke(company,null);
}
}
}catch (Exception e){
e.printStackTrace();
}
}
}
首先获取到Company类对象,然后创建Company对象实例,然后获取到Company中的字段数组,开始循环字段数组,如果该字段上有@CustomAutowired注解,则实例化该字段,如果该字段是User类的话,获取它的name字段,然后给name字段赋值,再将实例化后的User对象赋值给Company对象中的User字段,这样就达到了属性注入的效果。最后循环Company中的方法,调用getUserName方法,输出结果。这就是我通过反射机制来简单实现的注入的功能。
运行结果