手写Spring
1、回顾反射机制
如何使用反射?
1、调用什么对象
2、调用该对象的的什么方法,
3、需要什么参数,
4、执行该方法并返回什么(可以无返回值)
解决反射需要条件
假定现在要给User对象的age属性赋值
-
1、调用什么对象?==>Class<?> clazz =Class.forName()传入类全路径
Object o = clazz.newInstance() 得到该对象
-
2、调用该对象的的什么方法, 假定是set方法
通过属性名获取该属性名的第一个字母大写,加截取第一个字母的后面所有内容
获取方法名 ==>String methed = “set” + name.toUpperCase().charAt(0) + name.substring(1);
获取该方法==>Method methed1 = clazz.getDeclaredMethod(“方法名”,“参数类型”.Class)
-
3、需要什么参数,
“参数类型”.Class如何获取?==>Field field = clazz.getField(“属性名”);
field.getType()返回该属性的Class
Method methed = clazz.getDeclaredMethod(methed, field.getType());
-
4、执行该方法并返回什么(可以无返回值) methed.invoke()方法
methed .invoke(o, 30);
到此就完成了对User对象的age属性赋值
Class<?> clazz = Class.forName("com.xxxxx.pojo.User");
String name = "age";
//1、获取对象
Object o = clazz.newInstance();
//2、获取方法名 第一个字母转大写 并截取1以后的方法名
String methed = "set" + name.toUpperCase().charAt(0) + name.substring(1);
//3、需要什么参数 方法名+属性的class getField()通过属性名返回field对象 属性名是唯一的
Field field = clazz.getField(name);
//field.getType() 返回值是该对象的Class
Method methed1 = clazz.getDeclaredMethod(methed, field.getType());
//4、无返回值
methed1.invoke(o, 30);
System.out.println(o);
Method dosome = clazz.getDeclaredMethod("dosome");
dosome.invoke(o);
二、准备xml文件解析
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.2.0</version>
</dependency>
三、准备接口
public interface ApplicationContext {
/**
* 通过name 获取bean对象
*
* @param beanName
* @return
*/
Object getBean(String beanName);
}
四、创建实现类
创建对象放在map集合中
//存储bean对象
private Map<String, Object> map = new HashMap<>();
/**
* 提供构造方法、读取xml文件
*/
public ClassPathXmlApplicationContext(String config) {
/*第一步:将所有bean标签中的对象存到map集合中
* */
try {
//dom4j解析xml文件的核心对象
SAXReader reader = new SAXReader();
//获取类路径下的资源 以流的方式获取 指向配置文件config
InputStream resourceAsStream = ClassLoader.getSystemClassLoader().getResourceAsStream(config);
//读取流对象 获取xml文件document
Document document = reader.read(resourceAsStream);
//获取所有的bean标签 //bean
List<Node> nodes = document.selectNodes("//bean");
//遍历bean标签
nodes.forEach(node -> {
//将node向下转型为Element Element继承Branch接口,Branch接口继承Node接口
//向下转型是因为Element方法更加丰富 为了使用Element接口中的方法
Element element = (Element) node;
//element.attributeValue 获取该标签中属性为id的值
String id = element.attributeValue("id");
//获取类路径
String aClass = element.attributeValue("class");
try {
//获取Class
Class<?> clazz = Class.forName(aClass);
//clazz.getDeclaredConstructor获取无参构造方法
Constructor<?> defultCon = clazz.getDeclaredConstructor();
//调用无参构造器实例化对象
Object o = defultCon.newInstance();
//将对象添加到Map集合中
map.put(id, o);
} catch (Exception e) {
e.printStackTrace();
}
});
* */
//遍历bean标签并给属性赋值
nodes.forEach(node -> {
try {
//向下转型 element方法更丰富
Element element = (Element) node;
//获取bean标签中属性为id的value
String id = element.attributeValue("id");
//获取bean标签中属性为class的value 也就是全类名
String aClass = element.attributeValue("class");
//通过类获取到Class对象
Class<?> clazz = Class.forName(aClass);
//element.elements获取该标签下所有名为porperty的标签 返回一个Element list集合
List<Element> porpertys = element.elements("porperty");
//遍历所有的porperty标签
porpertys.forEach(porperty -> {
try {
//获取set方法前的方法名
String name = porperty.attributeValue("name");
//获取参数类型 getDeclaredField()和getField区别
Field field = clazz.getDeclaredField(name);
//方法名等于set+set方法后字母首字母大写+后续的 toUpperCase()转大写.charAt(0)获取首字母 substring(1)截取一个字符串后的所有字符串
String methed = "set" + name.toUpperCase().charAt(0) + name.substring(1);
//获取clazz类的方法
Method declaredMethod = clazz.getDeclaredMethod(methed, field.getType());
//获取porperty标签中属性为value的属性(简单类型)
String value = porperty.attributeValue("value");
//真正要给简单类型赋的值
Object realValue = null;
//获取porperty标签中属性为ref的属性(引用类型)
String ref = porperty.attributeValue("ref");
//如果value不等于null 代表是简单类型
if (value != null) {
//调用set方法(没有返回值)
//我们myspring框架只支持以下类型为简单类型
//byte short int long float double boolean char
//Byte Short Integer Long Float Double Boolean Character
//String
//如果是简单类型 需要对获取到的 String value进行转换 field.getType()获取类型(包含java.lang.*) getSimpleName()获取真正的类型名
String simpleName = field.getType().getSimpleName();
switch (simpleName) {
case "byte":
realValue = Byte.parseByte(value);
break;
case "short":
realValue = Short.parseShort(value);
break;
case "int":
realValue = Integer.parseInt(value);
break;
case "long":
realValue = Long.parseLong(value);
break;
case "float":
realValue = Float.parseFloat(value);
break;
case "double":
realValue = Double.parseDouble(value);
break;
case "boolean":
realValue = Boolean.parseBoolean(value);
break;
case "char":
//如果是char类型 代表只有一个字符
realValue = value.charAt(0);
break;
case "Byte":
realValue = Byte.valueOf(value);
break;
case "Short":
realValue = Short.valueOf(value);
break;
case "Integer":
realValue = Integer.valueOf(value);
break;
case "Long":
realValue = Long.valueOf(value);
break;
case "Float":
realValue = Float.valueOf(value);
break;
case "Double":
realValue = Double.valueOf(value);
break;
case "Boolean":
realValue = Boolean.valueOf(value);
break;
case "Character":
realValue = value.charAt(0);
break;
case "String":
realValue = value;
break;
}
//给属性赋set值
declaredMethod.invoke(map.get(id), realValue);
}
//如果ref不等于null 代表是引用类型 map.get(id)从集合中获取该对象,map.get(ref)给该对象的引用赋值
if (ref != null) {
declaredMethod.invoke(map.get(id), map.get(ref));
}
} catch (Exception e) {
e.printStackTrace();
}
});
} catch (Exception e) {
e.printStackTrace();
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
返回实体类
/**
* 通过id返回bean实例 需要向下转型
*
* @param beanName
* @return
*/
@Override
public Object getBean(String beanName) {
return map.get(beanName);
}
/**
* 通过id和Class返回指定bean实例
*
* @param beanName
* @param tClass
* @param <T>
* @return
*/
public <T> T getBean(String beanName, Class<T> tClass) {
return (T) map.get(beanName);
}
/**
* 根据类型自动匹配 如果有超过一个 直接报错
*
* @param tClass
* @param <T>
* @return
*/
@Override
public <T> T getBean(Class<T> tClass) {
int i = 0;
List<T> list = new ArrayList<>();
for (String key : map.keySet()) {
if (tClass.equals(map.get(key).getClass())) {
i++;
if (i > 1) {
throw new RuntimeException();
}
list.add((T) map.get(key));
}
}
if (!list.isEmpty()) {
return list.get(0);
}
return null;
}
验证程序测试
配置 Xml
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<!--给简单类型赋值-->
<bean id="user" class="com.bijianhua.bean.User">
<porperty name="userName" value="张三"/>
<porperty name="age" value="20"/>
</bean>
<bean id="userServiceBean" class="com.bijianhua.dao.UserService">
<porperty name="userDao" ref="userDaoBean"/>
</bean>
<bean id="userDaoBean" class="com.bijianhua.dao.UserDaoImpl"/>
</beans>
测试程序 UserBean
public class User {
private String userName;
private Integer age;
public void setUserName(String userName) {
this.userName = userName;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"userName='" + userName + '\'' +
", age=" + age +
'}';
}
}
测试程序:UserSerivce
//接口
public interface UserDao {
void save();
}
//实现类
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("数据库保存了信息");
}
}
//具体的Service
public class UserService {
private UserDao userDao;
//提供set方法
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void insert() {
//调用dao中的save方法
userDao.save();
}
}
main方法中测试
简单类型
public static void main(String[] args) {
ApplicationContext ioc=new ClassPathXmlApplicationContext("myspring.xml");
User user = ioc.getBean("user", User.class);
System.out.println(user);
}
打印结果:
User{userName='张三', age=20}
引用类型 以下是自动装配
public static void main(String[] args) {
ApplicationContext ioc=new ClassPathXmlApplicationContext("myspring.xml");
UserService bean = ioc.getBean(UserService.class);
System.out.println(bean);
bean.insert();
}
控制台输出:
com.bijianhua.dao.UserService@6073f712
数据库保存了信息
完结!