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 {
}