Spring源码简易手写实现(学习过程记录)(四)
2021/10/27 17:12:01
本文主要是介绍Spring源码简易手写实现(学习过程记录)(四),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
4.1Aware回调模拟实现
在createBean的时候,我们想在加了Component注解的类里面加一个字段beanName,该字段存储bean对象的name属性
spring会提供一个接口BeanNameAware来实现
package com.rainwood.spring; public interface BeanNameAware { void setBeanName(String name); }
我们在UserService类里可以继承该接口重写setBeanName方法
package com.rainwood.liming.service; import com.rainwood.spring.*; @Component("userService") //@Scope("prototype") public class UserService implements BeanNameAware{ @Autowired private OrderService orderService; private String beanName; public void test() { System.out.println(orderService); System.out.println(beanName); } @Override public void setBeanName(String name) { beanName = name; } }
设想如果没有setBeanName方法的话,在自动注入时候,仅有一个beanName字段是无法将Bean的name属性传进来赋给beanName
我们这里利用set方法,在spring容器createBean方法中调用setBean方法就可以实现将beanName传入。
public Object createBean(String beanName, BeanDefination beanDefination) { Class clazz = beanDefination.getClazz(); try { //首先看getDeclaredConstructor(Class<?>... parameterTypes) //这个方法会返回制定参数类型的所有构造器,包括public的和非public的,当然也包括private的。 //getDeclaredConstructors()的返回结果就没有参数类型的过滤了。 Object instance = clazz.getDeclaredConstructor().newInstance(); //依赖注入 //getDeclaredFields():获得某个类的所有声明的字段,即包括public、private和proteced,但是不包括父类的申明字段。 for (Field declaredField : clazz.getDeclaredFields()) { if(declaredField.isAnnotationPresent(Autowired.class)) { //spring在依赖注入时候会去是spring容器池里去根据类型和名字来找对应的bean //这里我们简化用名字来找 Object bean = getBean(declaredField.getName()); declaredField.setAccessible(true);//功能是启用或禁用安全检查 declaredField.set(instance, bean); } } //Aware回调 //判断instance是否实现了BeanNameAware接口,如果实现了就调用setBeanName将当前bean的名字beanName传进去 if(instance instanceof BeanNameAware) { ((BeanNameAware)instance).setBeanName(beanName); } return instance; } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } return null; }
我们和之前不同,我们在createBean时候,再加一个参数beanName传入createBean方法,
//Aware回调 //判断instance是否实现了BeanNameAware接口,如果实现了就调用setBeanName将当前bean的名字beanName传进去 if(instance instanceof BeanNameAware) { ((BeanNameAware)instance).setBeanName(beanName); }
检验instance对象是否是继承了BeanNameAware接口,如果继承了,就可以利用重写的setBeanName方法将beanName注入进去
4.2初始化模拟实现
和Aware回调类似,我们需要一个InitializingBean接口,该接口有afterPropertiesSet方法
package com.rainwood.spring; public interface InitializingBean { void afterPropertiesSet() throws Exception; }
让UserService继承InitializingBean
package com.rainwood.liming.service; import com.rainwood.spring.*; @Component("userService") //@Scope("prototype") public class UserService implements BeanNameAware, InitializingBean { @Autowired private OrderService orderService; private String beanName; public void test() { System.out.println(orderService); System.out.println(beanName); } @Override public void setBeanName(String name) { beanName = name; } //初始化时候调用这个方法想做啥就做啥 @Override public void afterPropertiesSet() throws Exception { System.out.println("初始化"); } }
同样的在createBean的时候
//初始化 if(instance instanceof InitializingBean) { try { ((InitializingBean)instance).afterPropertiesSet(); } catch (Exception e) { e.printStackTrace(); } }
继续判断instance是否继承了InitializingBean接口
继承了的话就调用afterPropertiesSet方法进行各种初始化操作
这篇关于Spring源码简易手写实现(学习过程记录)(四)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-01后台管理开发学习:新手入门指南
- 2024-11-01后台管理系统开发学习:新手入门教程
- 2024-11-01后台开发学习:从入门到实践的简单教程
- 2024-11-01后台综合解决方案学习:从入门到初级实战教程
- 2024-11-01接口模块封装学习入门教程
- 2024-11-01请求动作封装学习:新手入门教程
- 2024-11-01登录鉴权入门:新手必读指南
- 2024-11-01动态面包屑入门:轻松掌握导航设计技巧
- 2024-11-01动态权限入门:新手必读指南
- 2024-11-01动态主题处理入门:新手必读指南