<>基本上每一句代码我都加上了注释,希望有所帮助
<>BeanDefinition,里面有beanName和beanClass,到时候可以封装到这个类里面
@Data @AllArgsConstructor @NoArgsConstructor public class BeanDefinition {
private String beanName; private Class beanClass; }
<>最重要的类MyAnnotationConfigApplicationContext
在他的这个构造函数里,我们首先先根据他传入的包的名字,把这个包里面的所有类都扫描一次
Set<BeanDefinition> beanDefinitions = findBeanDefinitions(pack);
<>findBeanDefinitions函数
首先他要扫描包下面的所有类,然后得到这些类以后,我要去遍历一下,找到添加了注解的类,如果我添加了这个注解的话,返回的值就不是null(Component
componentAnnotation =
clazz.getAnnotation(Component.class)),接下来的话,判断一下有没有自定义的beanName吧,如果没有的话,我就给他改一下
//这样子说明我直接就写了component注解而已,后面没给出名字,那我就给他搞个名字 //名字的话,我把全类名前面的干掉
//再把Account改成account这样子,比较规范 if ("".equals(beanName)){ String packageName =
clazz.getPackage().getName(); packageName += "."; String clazzName = clazz.
getName(); clazzName = clazzName.replaceAll(packageName,""); beanName =
clazzName.substring(0,1).toLowerCase()+clazzName.substring(1); }
现在我可以把beanName和得到的类封装成前面写下的BeanDefinition了,然后放进集合里面,为什么要集合呢,因为要去重.
//beanDefinitions集合放入通过封装的BeanDefinition对象
//BeanDefinition里面的field有bean的名字和类,现在封装好放进集合 //之所以选择set,是因为要去重,有一个就足够了
beanDefinitions.add(new BeanDefinition(beanName,clazz));
<>下面是完整的该函数代码
public Set<BeanDefinition> findBeanDefinitions(String pack){ Set<BeanDefinition
> beanDefinitions = new HashSet<>(); //获取包下面的所有类 Set<Class<?>> classes = MyTools
.getClasses(pack); //遍历这些类,找到添加了注解的类 Iterator<Class<?>> iterator = classes.
iterator(); while (iterator.hasNext()){ Class<?> clazz = iterator.next();
//返回对应注解的Class对象 Component componentAnnotation = clazz.getAnnotation(Component.
class); if (componentAnnotation!=null){ //获取component注解的值 String beanName =
componentAnnotation.value(); //这样子说明我直接就写了component注解而已,后面没给出名字,那我就给他搞个名字
//名字的话,我把全类名前面的干掉 //再把Account改成account这样子,比较规范 if ("".equals(beanName)){ String
packageName= clazz.getPackage().getName(); packageName += "."; String clazzName
= clazz.getName(); clazzName = clazzName.replaceAll(packageName,""); beanName =
clazzName.substring(0,1).toLowerCase()+clazzName.substring(1); }
//beanDefinitions集合放入通过封装的BeanDefinition对象
//BeanDefinition里面的field有bean的名字和类,现在封装好放进集合 //之所以选择set,是因为要去重,有一个就足够了
beanDefinitions.add(new BeanDefinition(beanName,clazz)); } } return
beanDefinitions; }
找到所有bean放进集合以后,下一步要做的呢,就是放进ioc容器里面,ioc容器这里用的是
private Map<String,Object> ioc = new HashMap<>();
接下来从集合里面拿出我的BeanDefinition,然后分别拿出beanName和beanCLass,通过类对象的getConstructor()方法获得构造器(Constructor)对象并调用其newInstance()方法创建对象。
Object object = clazz.getConstructor().newInstance();
clazz.getDeclaredFields()拿到所有的字段,遍历所有的字段,老样子判断添加了@Value注解的字段
拿到字段名字以后去制作set方法
String value = valueAnnotation.value(); //拿到字段名字 String fieldName =
declaredField.getName(); //要去做这个字段的set方法 String methodName = "set" +fieldName.
substring(0,1).toUpperCase()+fieldName.substring(1); Method method = clazz.
getMethod(methodName,declaredField.getType());
要完成类型赋值的话,得转一下类型,不然的话到时候直接就报错了,类型不匹配
switch (declaredField.getType().getName()) { case "java.lang.Integer": val =
Integer.parseInt(value); break; case "java.lang.String": val = value; break;
case "java.lang.Float": val = Float.parseFloat(value); break; }
method.invoke(“要调用的方法的名字所隶属的对象实体”,方法的参数值);
method.invoke(object,val);
搞定之后放进ioc容器了,用beanName去对应
ioc.put(beanName,object);
<>该函数的代码
public void createBean(Set<BeanDefinition> beanDefinitions){ Iterator<
BeanDefinition> iterator = beanDefinitions.iterator(); while (iterator.hasNext()
) { BeanDefinition beanDefinition = iterator.next(); //从我封装好的对象里面我拿出我的类 Class
clazz= beanDefinition.getBeanClass(); //从我封装好的对象里面拿出我的beanName String beanName =
beanDefinition.getBeanName(); try {
//通过类对象的getConstructor()方法获得构造器(Constructor)对象并调用其newInstance()方法创建对象 Object
object= clazz.getConstructor().newInstance(); //获取此类中的所有字段 Field[]
declaredFields= clazz.getDeclaredFields(); for (Field declaredField :
declaredFields) { //getAnnotation(),如果不是这样的注解,就返回null Value valueAnnotation =
declaredField.getAnnotation(Value.class); if (valueAnnotation!=null){ String
value= valueAnnotation.value(); //拿到字段名字 String fieldName = declaredField.
getName(); //要去做这个字段的set方法 String methodName = "set" +fieldName.substring(0,1).
toUpperCase()+fieldName.substring(1); Method method = clazz.getMethod(methodName
,declaredField.getType()); //完成数据类型转换 Object val = null; //拿到数据类型的名字,来完成类型赋值
switch (declaredField.getType().getName()) { case "java.lang.Integer": val =
Integer.parseInt(value); break; case "java.lang.String": val = value; break;
case "java.lang.Float": val = Float.parseFloat(value); break; } //传入值
//method.invoke("要调用的方法的名字所隶属的对象实体",方法的参数值); method.invoke(object,val); } }
//搞定之后放进ioc容器了 ioc.put(beanName,object); } catch (InstantiationException e) { e.
printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); }
catch (InvocationTargetException e) { e.printStackTrace(); } catch (
NoSuchMethodException e) { e.printStackTrace(); } } }
<>轮到自动装载了
老样子,传过去的还是集合,遍历一次所有的字段,看看有没有@Authwired注解的,看看是不是为null
AutoWired annotation = declaredField.getAnnotation(AutoWired.class);
如果找到了,那就是添加了这个注解的,那我还得再找一下里面有没有@Qualifier注解的
Qualifier qualifier = declaredField.getAnnotation(Qualifier.class);
如果有的话,那我就得通过这个bean的名字去ioc容器拿出来
接下来拿到字段名字和方法等等这些
String beanName = qualifier.value(); //通过bean的名字去ioc容器里面把bean拿出来
//ioc容器我用的是hashMap Object bean = getBean(beanName); //拿字段名 String fieldName =
declaredField.getName(); String methodName = "set" + fieldName.substring(0,1).
toUpperCase() + fieldName.substring(1); Method method = clazz.getMethod(
methodName, declaredField.getType());
//method.invoke("要调用的方法的名字所隶属的对象实体",方法的参数值); //把另外一个bean传入,不然的话打印出来是null的 method
.invoke(object,bean);
<>该函数的完全代码
public void autowireObject(Set<BeanDefinition> beanDefinitions){ Iterator<
BeanDefinition> iterator = beanDefinitions.iterator(); while (iterator.hasNext()
){ BeanDefinition beanDefinition = iterator.next();
//因为我的这个beanDefinition对象里面,有一个beanName和一个BeanClass(放类的) Class clazz =
beanDefinition.getBeanClass(); //拿出这个类的所有字段 Field[] declaredFields = clazz.
getDeclaredFields(); for (Field declaredField : declaredFields) {
//看看这个字段有没有AutoWired这个注解 AutoWired annotation = declaredField.getAnnotation(
AutoWired.class); if (annotation!=null){ //看看有没有Qualifier这种自定义名字的注解 Qualifier
qualifier= declaredField.getAnnotation(Qualifier.class); if (qualifier!=null){
//我用Qualifier自定义名字了 //byName try { String beanName = qualifier.value();
//通过bean的名字去ioc容器里面把bean拿出来 //ioc容器我用的是hashMap Object bean = getBean(beanName);
//拿字段名 String fieldName = declaredField.getName(); String methodName = "set" +
fieldName.substring(0,1).toUpperCase() + fieldName.substring(1); Method method =
clazz.getMethod(methodName, declaredField.getType()); Object object = getBean(
beanDefinition.getBeanName()); //传入值
//method.invoke("要调用的方法的名字所隶属的对象实体",方法的参数值); //把另外一个bean传入,不然的话打印出来是null的 method
.invoke(object,bean); } catch (NoSuchMethodException e) { e.printStackTrace(); }
catch (IllegalAccessException e) { e.printStackTrace(); } catch (
InvocationTargetException e) { e.printStackTrace(); } }else{ //byType } } } } }
<>该类的完全代码
```java public class MyAnnotationConfigApplicationContext { private Map<String,
Object> ioc = new HashMap<>(); public MyAnnotationConfigApplicationContext(
String pack){ //遍历包,返回所有的目标类 Set<BeanDefinition> beanDefinitions =
findBeanDefinitions(pack); Iterator<BeanDefinition> iterator = beanDefinitions.
iterator(); //根据原材料来创建Bean createBean(beanDefinitions); //自动装载 autowireObject(
beanDefinitions); } public void autowireObject(Set<BeanDefinition>
beanDefinitions){ Iterator<BeanDefinition> iterator = beanDefinitions.iterator()
; while (iterator.hasNext()){ BeanDefinition beanDefinition = iterator.next();
//因为我的这个beanDefinition对象里面,有一个beanName和一个BeanClass(放类的) Class clazz =
beanDefinition.getBeanClass(); //拿出这个类的所有字段 Field[] declaredFields = clazz.
getDeclaredFields(); for (Field declaredField : declaredFields) {
//看看这个字段有没有AutoWired这个注解 AutoWired annotation = declaredField.getAnnotation(
AutoWired.class); if (annotation!=null){ //看看有没有Qualifier这种自定义名字的注解 Qualifier
qualifier= declaredField.getAnnotation(Qualifier.class); if (qualifier!=null){
//我用Qualifier自定义名字了 //byName try { String beanName = qualifier.value();
//通过bean的名字去ioc容器里面把bean拿出来 //ioc容器我用的是hashMap Object bean = getBean(beanName);
//拿字段名 String fieldName = declaredField.getName(); String methodName = "set" +
fieldName.substring(0,1).toUpperCase() + fieldName.substring(1); Method method =
clazz.getMethod(methodName, declaredField.getType()); Object object = getBean(
beanDefinition.getBeanName()); //传入值
//method.invoke("要调用的方法的名字所隶属的对象实体",方法的参数值); //把另外一个bean传入,不然的话打印出来是null的 method
.invoke(object,bean); } catch (NoSuchMethodException e) { e.printStackTrace(); }
catch (IllegalAccessException e) { e.printStackTrace(); } catch (
InvocationTargetException e) { e.printStackTrace(); } }else{ //byType } } } } }
public Object getBean(String beanName){ return ioc.get(beanName); }
//根据集合来创建bean public void createBean(Set<BeanDefinition> beanDefinitions){
Iterator<BeanDefinition> iterator = beanDefinitions.iterator(); while (iterator.
hasNext()) { BeanDefinition beanDefinition = iterator.next(); //从我封装好的对象里面我拿出我的类
Class clazz = beanDefinition.getBeanClass(); //从我封装好的对象里面拿出我的beanName String
beanName= beanDefinition.getBeanName(); try {
//通过类对象的getConstructor()方法获得构造器(Constructor)对象并调用其newInstance()方法创建对象 Object
object= clazz.getConstructor().newInstance(); //获取此类中的所有字段 Field[]
declaredFields= clazz.getDeclaredFields(); for (Field declaredField :
declaredFields) { //getAnnotation(),如果不是这样的注解,就返回null Value valueAnnotation =
declaredField.getAnnotation(Value.class); if (valueAnnotation!=null){ String
value= valueAnnotation.value(); //拿到字段名字 String fieldName = declaredField.
getName(); //要去做这个字段的set方法 String methodName = "set" +fieldName.substring(0,1).
toUpperCase()+fieldName.substring(1); Method method = clazz.getMethod(methodName
,declaredField.getType()); //完成数据类型转换 Object val = null; //拿到数据类型的名字,来完成类型赋值
switch (declaredField.getType().getName()) { case "java.lang.Integer": val =
Integer.parseInt(value); break; case "java.lang.String": val = value; break;
case "java.lang.Float": val = Float.parseFloat(value); break; } //传入值
//method.invoke("要调用的方法的名字所隶属的对象实体",方法的参数值); method.invoke(object,val); } }
//搞定之后放进ioc容器了 ioc.put(beanName,object); } catch (InstantiationException e) { e.
printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); }
catch (InvocationTargetException e) { e.printStackTrace(); } catch (
NoSuchMethodException e) { e.printStackTrace(); } } } public Set<BeanDefinition>
findBeanDefinitions(String pack){ Set<BeanDefinition> beanDefinitions = new
HashSet<>(); //获取包下面的所有类 Set<Class<?>> classes = MyTools.getClasses(pack);
//遍历这些类,找到添加了注解的类 Iterator<Class<?>> iterator = classes.iterator(); while (
iterator.hasNext()){ Class<?> clazz = iterator.next(); //返回对应注解的Class对象
Component componentAnnotation = clazz.getAnnotation(Component.class); if (
componentAnnotation!=null){ //获取component注解的值 String beanName =
componentAnnotation.value(); //这样子说明我直接就写了component注解而已,后面没给出名字,那我就给他搞个名字
//名字的话,我把全类名前面的干掉 //再把Account改成account这样子,比较规范 if ("".equals(beanName)){ String
packageName= clazz.getPackage().getName(); packageName += "."; String clazzName
= clazz.getName(); clazzName = clazzName.replaceAll(packageName,""); beanName =
clazzName.substring(0,1).toLowerCase()+clazzName.substring(1); }
//beanDefinitions集合放入通过封装的BeanDefinition对象
//BeanDefinition里面的field有bean的名字和类,现在封装好放进集合 //之所以选择set,是因为要去重,有一个就足够了
beanDefinitions.add(new BeanDefinition(beanName,clazz)); } } return
beanDefinitions; } } ## 需要的实体类 ```java @Component @Data public class Account {
@Value("1") private Integer id; @Value("张三") private String name; @Value("22")
private Integer age; @AutoWired @Qualifier("myOrder") private Order order; }
@Data @Component("myOrder") public class Order { @Value("jyu") private String
address; }
<>@Component注解
//这种后面是type的,对应的是接口、类、枚举 @Target(ElementType.TYPE)
//runtime,注解不仅被保存到class文件中,就算jvm加载class文件以后,依然存在 @Retention(RetentionPolicy.
RUNTIME) public @interface Component { String value() default ""; }
<>@Value注解
//这种后面对应的是field的,对应的是字段和枚举的常量 @Target(ElementType.FIELD)
//runtime,注解不仅被保存到class文件中,就算jvm加载class文件以后,依然存在 @Retention(RetentionPolicy.
RUNTIME) public @interface Value { String value(); }
<>@Qualifier注解
//这种后面对应的是field的,对应的是字段和枚举的常量 @Target(ElementType.FIELD)
//runtime,注解不仅被保存到class文件中,就算jvm加载class文件以后,依然存在 @Retention(RetentionPolicy.
RUNTIME) public @interface Qualifier { String value(); }
<>@AutoWired注解
//这种后面对应的是field的,对应的是字段和枚举的常量 @Target(ElementType.FIELD)
//runtime,注解不仅被保存到class文件中,就算jvm加载class文件以后,依然存在 @Retention(RetentionPolicy.
RUNTIME) public @interface AutoWired { }