文章内容输出来源:拉勾教育Java高薪训练营
相关文章
Spring的IOC
IOC:Inversion of Control,控制反转
什么是控制
对象的创建、销毁的控制权
什么是反转
- 传统方式下,对象需要由开发者自己写New代码去创建,控制权掌握在开发者手里
- 反转就是把开发者的这个权利移交出去,交由Spring的IOC容器去实例化、管理。开发者想要什么对象,直接找容器拿
手写IOC功能
- 定义配置文件beans.xml,在配置文件中通过bean标签声明需要在IOC容器管理的类
- 配置文件的格式
<?xml version="1.0" encoding="utf-8" ?>
<beans>
<bean id="唯一标识,也是bean的名称" class="全限定类名">
<property name="属性名称" ref="属性注入的Bean,对应配置的bean名称"/>
</bean>
</beans>
- 定义管理Bean的工厂
BeanFactory
,这个工厂有以下的功能
- 定义一个Bean容器,HashMap结构,key是Bean名称,value是对应的类实例
//Bean容器
private static Map<String, Object> beanMap = new HashMap();
- 工厂创建时即去获取所有的Bean对象,放到容器中管理,并对外提供获取Bean的方法
- 解析beans.xml,获取所有的bean节点
- 通过反射技术,根据bean节点的class属性生成对象,放到Bean容器中
- 获取bean节点的property子节点,进行属性注值(从bean容器中获取相应的Bean对象)
//工厂创建时即去构造Bean容器
static {
loadBeans();
}
//加载Bean的方法
private static void loadBeans() {
//1.读取bean配置文件
InputStream resourceAsStream = BeanFactory.class.getClassLoader().getResourceAsStream("beans.xml");
//通过dom4j工具进行解析
SAXReader reader = new SAXReader();
try {
Document document = reader.read(resourceAsStream);
Element rootElement = document.getRootElement();
//获取到所有的bean节点
List<Element> beanElements = rootElement.selectNodes("//bean");
Map<String, Map<String, String>> propertyMap = new HashMap();
for (Element beanElement : beanElements) {
String id = beanElement.attributeValue("id");
String clazz = beanElement.attributeValue("class");
//通过反射技术创建类对象,放到Bean容器中
Class<?> aClass = Class.forName(clazz);
Object o = aClass.newInstance();
beanMap.put(id, o);
//获取bean节点的属性节点
List<Element> propertyElements = beanElement.selectNodes("//property");
//因为一个类可能有多个属性,所以这里也定义一个map属性来存储属性名称以及对应需要注入的对象的Bean名称
Map<String, String> map = new HashMap<String, String>();
for (Element propertyElement : propertyElements) {
String name = propertyElement.attributeValue("name");
String ref = propertyElement.attributeValue("ref");
map.put(name, ref);
}
//将获取到的属性数据,与bean对应起来,放到一个map中
if(map.size() > 0){
propertyMap.put(id, map);
}
}
//当所有Bean都实例化,放到了容器中后,再对Bean中的属性进行注入赋值
Iterator<Map.Entry<String, Map<String, String>>> beanIterator = propertyMap.entrySet().iterator();
while (beanIterator.hasNext()) {
Map.Entry<String, Map<String, String>> beanEntry = beanIterator.next();
//从容器中拿对应的Bean对象
Object o1 = beanMap.get(beanEntry.getKey());
//获取Bean的所有方法
Method[] methods = o1.getClass().getMethods();
//获取属性的迭代器
Iterator<Map.Entry<String, String>> propertyIterator = beanEntry.getValue().entrySet().iterator();
while (propertyIterator.hasNext()) {
Map.Entry<String, String> propertyEntry = propertyIterator.next();
//从容器中拿到属性引用的Bean对象
Object o2 = beanMap.get(propertyEntry.getValue());
//通过属性的setter方法进行赋值
for (Method method : methods) {
if (method.getName().equalsIgnoreCase("set" + propertyIterator.getValue())) {
method.invoke(o1, o2);
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
- 对外提供获取Bean对象的方法,从Bean容器中拿到相应对象
public static Object getBean(String beanName) {
return beanMap.get(beanName);
}
- 测试
- 在配置文件中bean
<!--帐户DAO-->
<bean id="accountDao" class="com.yyh.dao.impl.AccountDaoImpl"/>
<!--转账业务Service-->
<bean id="transferService" class="com.yyh.service.impl.TransferServiceImpl">
<property name="accountDao" ref="accountDao"/>
</bean>
- 在
TransferService
的转账业务实现类中,实现转账功能
public class TransferServiceImpl implements TransferService {
private AccountDao accountDao;
public void transfer(String fromCardNumber, String toCardNumber, int money) throws SQLException {
AccountEntity fromAccount = accountDao.selectOneByCardNumber(fromCardNumber);
AccountEntity toAccount = accountDao.selectOneByCardNumber(toCardNumber);
accountDao.updateMoneyByCardNumber(fromCardNumber, fromAccount.getMoney() - money);
int a = 1 / 0;
accountDao.updateMoneyByCardNumber(toCardNumber, toAccount.getMoney() + money);
}
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
}
- 在转账测试类
TransferTest
,调用转账的业务方法
public class TransferTest {
private TransferService transferService = (TransferService) BeanFactory.getBean("transferService");
@Test
public void testTransfer() throws SQLException {
transferService.transfer("123456", "123457", 100);
}
}