依赖注入是Spring中一个极其重要的概念。
本文通过JDK的注解和反射机制来完成在Spring中完成依赖注入的功能。
预备知识,注解,反射机制
完成一个注解我们通常需要三个步骤1,定义注解,2,使用注解,3,解析注解
下面我们通过实例来解释注解的使用
定义注解
package cn.tang.demos.spring;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD) //注解用在什么地方,method,field,class,type
@Retention(RetentionPolicy.RUNTIME)//注解用在什么级别,Source,class,runtime
public @interface Autoware {
String description() default "类似spring的自动装载";//注解元素的默认值
}
使用注解
package cn.tang.demos.spring;
public class Bean {
@Autoware(description="数据访问接口")
private MysqlDao dao;
public void testAdd(){
dao.add();
}
public MysqlDao getDao() {
return dao;
}
public void setDao(MysqlDao dao) {
this.dao = dao;
}
}
解析注解,下面代码包括了依赖注入的内容
package cn.tang.demos.spring;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class DITest {
/**
* 依赖注入的测试类,假设已经从xml配置文件中读取出来了两个Bean的类名
*/
private static final String daoClassStr = "cn.tang.demos.spring.MysqlDao";
private static final String beanClassStr = "cn.tang.demos.spring.Bean";
public static void main(String[] args) {
try {
test();// 为了能让代码更加直观,没有分别处理所有类型的异常,也没有多余的判断
} catch (Exception e) {
e.printStackTrace();
}
}
@SuppressWarnings("unchecked")
public static void test() throws Exception {
// 根据类名得到类类型
Class daoClass = Class.forName(daoClassStr);
// 根据类得到该类的构造方法
Constructor daoCon = daoClass.getDeclaredConstructors()[0];
// 调用构造方法得到类的一个实例
MysqlDao dao = (MysqlDao) daoCon.newInstance();
// 根据类名得到类类型
Class beanClass = Class.forName(beanClassStr);
// 根据类得到该类的构造方法
Constructor beanCon = beanClass.getDeclaredConstructors()[0];
// 调用构造方法得到类的一个实例
Object beanObject = beanCon.newInstance();
// 遍历所有的属性
for (Field f : beanClass.getDeclaredFields()) {
// 获取有注入类型的注解
Autoware an = (Autoware) f.getAnnotation(Autoware.class);
// 根据属性得到声明属性的类型 f.getGenericType()
if (an != null) {
// 输出注解的描述内容
System.out.println("annotation description : "
+ an.description());
// 得到与该属性的set方法,这也是为什么spring中的属性需要set方法
String setMethodName = "set"
+ f.getName().substring(0, 1).toUpperCase()
+ f.getName().substring(1);
//得到该方法
Method m = beanClass.getDeclaredMethod(setMethodName,
new Class[] { (Class) f.getGenericType() });
if (m != null) {
//反射机制调用该方法,注入DAO到bean中
m.invoke(beanObject, dao);
}
}
}
//现在我们得到了一个注入了dao的bean了,我们调用bean中的方法
((Bean) beanObject).testAdd();
}
}