java web project--learning through building 3
Tue, Jan 12, 2021
3-minute read
a full-stack web application for users to understand java web system
dispatcherServlet 引入
用 dispatcherServelet 控制 controller, 把反射放到父类
核心控制器统一获取参数
mvc service 和 dao 详细区分
mvc ioc 耦合问题
+ 耦合/依赖注入
在软件系统中,层与层之间是存在依赖的。我们也称之为耦合。
我们系统架构或者是设计的一个原则是: 高内聚低耦合。
层内部的组成应该是高度聚合的,而层与层之间的关系应该是低耦合的,最理想的情况 0 耦合(就是没有耦合)
public class FruitController {
private FruitService fruitService = new FruitServiceImpl() ;
private String update(Integer fid , String fname , Integer price , Integer fcount , String remark ){
}
- step 1:
private FruitService fruitService = null ;
- 解决空指针问题:
1. 配置 3 个 bean,对应 3 个组件
<beans>
<bean id="fruitDAO" class="com.atguigu.fruit.dao.impl.FruitDAOImpl"/>
<bean id="fruitService" class="com.atguigu.fruit.service.impl.FruitServiceImpl">
<!-- property标签用来表示属性;name表示属性名;ref表示引用其他bean的id值-->
<property name="fruitDAO" ref="fruitDAO"/>
</bean>
<bean id="fruit" class="com.atguigu.fruit.controllers.FruitController">
<property name="fruitService" ref="fruitService"/>
</bean>
</beans>
2. 配置 bean 工厂,实现根据 id 获得一个类的功能
public interface BeanFactory {
Object getBean(String id);
}
3. 配置方法实现 bean 工厂
public class ClassPathXmlApplicationContext implements BeanFactory {
private Map<String,Object> beanMap = new HashMap<>();
public ClassPathXmlApplicationContext(){
try {
InputStream inputStream = getClass().getClassLoader().getResourceAsStream("applicationContext.xml");
//1.创建DocumentBuilderFactory
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
//2.创建DocumentBuilder对象
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder() ;
//3.创建Document对象
Document document = documentBuilder.parse(inputStream);
//4.获取所有的bean节点
NodeList beanNodeList = document.getElementsByTagName("bean");
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) ;
//到目前为止,此处需要注意的是,bean和bean之间的依赖关系还没有设置
}
}
//5.组装bean之间的依赖关系
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");
NodeList beanChildNodeList = beanElement.getChildNodes();
for (int j = 0; j < beanChildNodeList.getLength() ; j++) {
Node beanChildNode = beanChildNodeList.item(j);
if(beanChildNode.getNodeType()==Node.ELEMENT_NODE && "property".equals(beanChildNode.getNodeName())){
Element propertyElement = (Element) beanChildNode;
String propertyName = propertyElement.getAttribute("name");
String propertyRef = propertyElement.getAttribute("ref");
//1) 找到propertyRef对应的实例
Object refObj = beanMap.get(propertyRef);
//2) 将refObj设置到当前bean对应的实例的property属性上去
Object beanObj = beanMap.get(beanId);
Class beanClazz = beanObj.getClass();
Field propertyField = beanClazz.getDeclaredField(propertyName);
propertyField.setAccessible(true);
propertyField.set(beanObj,refObj);
}
}
}
}
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
@Override
public Object getBean(String id) {
return beanMap.get(id);
}
}
IOC - 控制反转 / DI - 依赖注入
控制反转
- 之前在 Servlet 中,我们创建 service 对象 , FruitService fruitService = new FruitServiceImpl(); 这句话如果出现在 servlet 中的某个方法内部,那么这个 fruitService 的作用域(生命周期)应该就是这个方法级别;(需要大量的创建销毁过程)
如果这句话出现在 servlet 的类中,也就是说 fruitService 是一个成员变量,那么这个 fruitService 的作用域(生命周期)应该就是这个 servlet 实例级别 (不需要大量的创建销毁过程,但生命周期扩大,有线程不安全问题)
- 之后我们在 applicationContext.xml 中定义了这个 fruitService。然后通过解析 XML,产生 fruitService 实例,存放在 beanMap 中,这个 beanMap 在一个 BeanFactory 中因此,我们转移(改变)了之前的 service 实例、dao 实例等等他们的生命周期。控制权从程序员转移到 BeanFactory。这个现象我们称之为控制反转
依赖注入
-
之前我们在控制层出现代码:FruitService fruitService = new FruitServiceImpl();那么,控制层和 service 层存在耦合。
-
之后,我们将代码修改成 FruitService fruitService = null ; 然后,在配置文件中配置:
<bean id="fruit" class="FruitController">
<property name="fruitService" ref="fruitService"/>
</bean>