servlet-api:(学习一些servlet关于初始化的api):
之前就说过,HttpServlet的一个父类,GenericServlet里有初始化方法
我们可以看到这两个init基本上没什么内容,我们可以在demo01重写init方法,让我们的代码在初始化的时候就可以完成一些操作,比如初始化的时候给一些参数赋值
问题来了,我使用这个方法,获取到的值应该设置在哪里?
1.通过xml文件配置初始化赋值:
通过<init-param>标签赋值
此时在之前的方法名中填写hello就可以获得world了
获取成功
而且可以设置多个键值对标签初始化的时候赋值
2.通过注解初始化赋值:
我们点击@webservlet可以看到里面有个urlpatterns和initparams
urlpatterns就是之前我们配置文件里的对应关系,也变相说明了,可以多个servlt-mapping对应一个servlet
initparams就可以写我们想要初始化时赋的值
同样的我们也可以在初始化的时候获取servletcontext(servlet上下文)的值
1.通过xml文件配置初始化赋值:
总结:
业务层(service层)引入:
经过对比,我们发现我们的fruit系统还没有业务对象,所以现在我们需要把service层也加入到系统架构中
现在对于我们的fruit系统现在都有哪些功能?
所以相对应的
接口:
实现类:
所以现在就是fruitcontroller调用fruitservice,fruitservice调用fruitDAO
所以现在的fruitcontroller就不用new fruitDAO了,需要修改
测试:一切功能正常,已经完成分层
IOC(实现依赖注入控制反转):
首先,什么样的系统是一个好系统呢?
我们现在的层与层就是存在依赖的,我们的controller依赖service,servive依赖dao,这样子就不是特别好,我们现在想实现如果把service删除,对controller没有影响,现在是不可能实现的,现在唯一想删除不报错的办法就是设置为null,但是设置为null系统就无法运行。我们的IOC就可以帮我们实现即使设置为null,也可以有我们需要的对象去new和使用
ioc是如何操作的?
我们之前使用了配置文件,通过请求的路径获取了对应实例化的对象,如果我们设置一个容器,让我们所有的需要被使用的对象在系统初始化的时候就new好放在容器中,谁使用谁就直接从容器中获取就可以了
编写配置文件:
专门写一个方法用于获取配置文件对应的实例化对象和id存入Map中(和之前控制器代码类似):
接口:
实现类:
现在看起来结构就和之前的很相似了,所以我们可以原来获取对应对象的功能直接在这边实现,所以原本控制器里的new Hashmap()和放入容器的代码就不用了
直接剪切放过来
所以现在叫controllerBeanClass就不合适了,现在这个代码适用范围为三层全包
那之前删除的控制器代码报错,我们就在初始化的时候new classpathxml对象并且调用getBean就好了
自己的疑问:如果这样子,那我们的io和控制器耦合度不久增高了吗?
如何连接层与层之间的关系?
我们之前已经把new对象设置为null了,层次关系断开了,那我该怎么样让他们使用的时候再次连接起来呢——通过配置文件
已知我们的service需要DAO这个属性
已知我们的controller需要service这个属性
我们的配置文件标签<property>就是干这个的
<property>有两个值
name:对应的是当前bean标签对应的对象里,所需要的对象名称
ref:对应的是当前bean容器里引用其他bea的id值
也就是
到现在,service和DAO的依赖关系建立成功
那么同理,controller和service的依赖关系应该为
现在的ref对应的id应该就是
设置bean与bean之间的依赖关系:
我们在xml文件里只是描述了bean之间的依赖关系,如何在代码之中设置呢?
我们还可以进行for循环,如果我当前的element的子节点里有<property>就通过它的ref反射对应新的对象
如何判断子节点个数呢?
第一个:
第二个:
第三个:
该如何获取?
首先获取当前property的name和ref
String propertyName = propertyElement.getAttribute("name");
String propertyRef = propertyElement.getAttribute("ref");
以当前bean标签为
举例
1.首先找到与当前propertyref对应的实例,也就是fruitserviveimpl
Object refObj = beanMap.get(propertyRef);
2.再找到当前标签对应的实例,也就是fruitcontroller
Object beanObj = beanMap.get(beanId);
3.找到当前beanObj对应的类
Class beanClazz = beanObj.getClass();
4.找到在当前类中与propertyName对应的已经定义好的同名参数,并且设置强制访问
propertyName:
当前类:
当前类中的同名参数:
Field propertyField = beanClazz.getDeclaredField(propertyName);
propertyField.setAccessible(true);
5.给当前对象(beanObj)设置我们想设置的refObj的值
propertyField.set(beanObj,refObj);
ClassPathXmlApplicationContext完整代码:
public class ClassPathXmlApplicationContext implements BeanFactory{
//首先一定要有容器来接收数据
private Map<String,Object> beanMap = new HashMap<>();
public ClassPathXmlApplicationContext(){
try {
//获取文件流
InputStream inputStream = getClass().getClassLoader().getResourceAsStream("applicationContext.xml");
//创建DocumentBuilderFactory对象
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
//创建documentBuilder对象
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
//创建document对象
Document document = documentBuilder.parse(inputStream);
//利用document对象里的方法获取xml文件里所有bean标签并且生成一个集合
NodeList beanNodeList = document.getElementsByTagName("bean");
System.out.println(beanNodeList);
for (int i = 0;i <beanNodeList.getLength();i++){
Node beanNode = beanNodeList.item(i);
if (beanNode.getNodeType()== Node.ELEMENT_NODE){
Element beanElement = (Element) beanNode;
String beanId = beanElement.getAttribute("id");
String className = beanElement.getAttribute("class");
Class beanClass = Class.forName(className);
//创建bean实例
Object beanObj = beanClass.newInstance();
//把bean实例对象保存到map容器中
beanMap.put(beanId, beanObj);
//System.out.println(beanMap);
//注意:bean和bean的依赖关系还没有设置
}
}
//组装bean之中的依赖关系
for (int i = 0;i <beanNodeList.getLength();i++) {
Node beanNode = beanNodeList.item(i);
if (beanNode.getNodeType() == Node.ELEMENT_NODE) {
//拿到当前bean标签
Element beanElement = (Element) beanNode;
//获取当前bean对象的id
String beanId = beanElement.getAttribute("id");
//获取当前子节点集合
NodeList beanChildNodeList = beanElement.getChildNodes();
//对子节点集合进行遍历,如果有property,就对ref和name进行处理
for (int j = 0; j < beanChildNodeList.getLength(); j++) {
//拿到其中一个结点
Node beanChildNode = beanChildNodeList.item(j);
//进行判断是不是property
if (beanChildNode.getNodeType()==Node.ELEMENT_NODE && "property".equals(beanChildNode.getNodeName())){
//如果是property进行强制转换
Element propertyElement = (Element) beanChildNode;
//取出当前property的name和ref
String propertyName = propertyElement.getAttribute("name");
String propertyRef = propertyElement.getAttribute("ref");
System.out.println(propertyName);
System.out.println(propertyRef);
//找到propertyRef对应的实例
Object refObj = beanMap.get(propertyRef);
//把refObj设置到当前bean标签的property的name对应的参数上
Object beanObj = beanMap.get(beanId);
//找到当前beanObj对应的类
Class beanClazz = beanObj.getClass();
//找到在当前类中与propertyName对应的已经定义好的同名参数
Field propertyField = beanClazz.getDeclaredField(propertyName);
//设置强制访问
propertyField.setAccessible(true);
//给当前对象(beanObj)设置我们想设置的refObj的值
propertyField.set(beanObj,refObj);
}
}
}
}
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
@Override
public Object getBean(String id) {
return beanMap.get(id);
}
}
实现依赖关系为精华
测试:功能一切正常
好耶!!!!!!!!!!!!!!!!!!!!
总结: