標籤:style http java 使用 os strong
就在前不久,一個資深JAVA經理兼HR跟我說,做Java web的,一定要會Spring,不止是會用,還要深入進去,看看它的實現原理,以及是怎麼編寫的,對此我表示鴨梨很大,內部結構,原理啥都只能先放著一遍,先來看看Spring是怎麼做的。
IOC?DI?這是個咩啊!
關於控制反轉或者說依賴注入到底是個什麼意思,這裡就不多加說明了,Spring in Action專業度爆脖主的距離怕有該書作者到脖主的地理位置那麼遠,還是直接來看看是怎麼做的吧
public class DbInfoServlet extends HttpServlet{
public void service(HttpServletRequest request,HttpServletResponse response)
throws ServletException,java.io.IOException{
request.setCharacterEncoding("GBK");
DbInfo dbinfo = new DbInfo();
String result = dbinfo.queryModelInfo();
response.setContentType("text/html;charset=UTF-8");
response.setHeader("Cache-Control", "no-cache");
PrintStream out = new PrintStream(response.getOutputStream());
out.println(result);
}
}
這是上篇中的一個servlet應用,對於類DbInfo 的使用,通過new一個新執行個體來實現。
public class ModelInfoControl implements Controller {
private ModelInfoService modelInfoService;
@Override
public ModelAndView handleRequest(HttpServletRequest request,HttpServletResponse response)
throws ServletException,java.io.IOException{
request.setCharacterEncoding("GBK");
String result = modelInfoService.queryModelInfo();
response.setContentType("text/html;charset=UTF-8");
response.setHeader("Cache-Control", "no-cache");
PrintStream out = new PrintStream(response.getOutputStream());
out.println(result);
out.flush();
out.close();
return null;
}
public void setModelInfoService(ModelInfoService modelInfoService) {
this.modelInfoService = modelInfoService;
}
}
雖然命名略有不同,但是不影響看出差別,這裡ModelInfoService類執行個體modelInfoService,沒有使用new關鍵字去建立,而且在下方,多出了一個他的set方法。
這是如何?的,我們呼應一下標題,在這裡,建立被調用者執行個體的工作不在由調用者完成,而是在外部實現後注入調用者,所以說,這裡控制反轉了或者說,這裡依賴注入,那麼。新的問題出現了,現在,控制反轉到誰頭上了,依賴於誰去注入?
容器
暫時讓我們忘掉之前的MyProject,忘掉上面的對於依賴注入的說明,來看一個Spring的簡單應用:
定義兩個介面,斧子和人
public interface Axe {
public String chop();
}
public interface Person {
public void useAxe();
}
定義斧子的實作類別
public class StoneAxe implements Axe {
@Override
public String chop() {
// TODO Auto-generated method stub
return "石斧砍柴好慢";
}
}
以及人的實作類別
public class Chinese{
private Axe axe;
public void setAxe(Axe axe) {
this.axe = axe;
}
public Axe getAxe() {
return axe;
}
}
最後測試Spring
public class SpringTest {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml");
Chinese p = ctx.getBean("chinese",Chinese.class);
System.out.println(p.getAxe().chop());
}
}
輸出:石斧砍柴好慢
但是,等等,這是怎麼一回事,Chinese裡明明是個介面的axe,是怎麼變成StoneAxe的執行個體的!
我們先關注一下chinese執行個體p的建立。
ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml");
Chinese p = ctx.getBean("chinese",Chinese.class);
想到什麼沒,雖然跟上面的方式不太一樣,但是顯然這裡的p也沒通過new關鍵字建立,而是通過一個叫ctx的ApplicationContext執行個體建立,而ctx,顯然藉助了資料檔案bean.xml來實現自身的執行個體化。
我們來看一下bean.xml。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="chinese" class="sun.service.Chinese">
<property name="axe" ref="stoneAxe"/>
</bean>
<bean id="stoneAxe" class="sun.service.StoneAxe"/>
</beans>
這裡定義了兩個bean Chinese chinese和StoneAxe stoneAxe,而chinese的參數axe是stoneAxe的一個實現。
這下就好理解了,p是ctx所擷取的bean chinese,這個Chinese類的執行個體中,屬性axe為bean stoneAxe,看到這裡,前面的問題也就呼之欲出了,ApplicationContext類作為了各個Spring執行個體中被調用執行個體的控制和注入者,我們將其稱呼為容器,裝納bean的容器。
Spring的Web應用,Spring MVC
扯遠了點,還是回到項目中來,添加容器設定檔applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
</beans>
並在web.xml裡對其進行配置
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
定義介面ModelInfoDao和實作類別ModelInfoDaoImpl
public interface ModelInfoDao {
//擷取模組資訊
String queryModelInfo();
}
public class ModelInfoDaoImpl implements ModelInfoDao {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
public String queryModelInfo(){
String result = "";
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl", "Leon", "orcl");
stmt = conn.createStatement();
rs = stmt.executeQuery("select * from t_model_info");
while(rs.next()){
result =rs.getString("info");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
if(conn != null) {
conn.close();
conn = null;
}
} catch (SQLException e) {
e.printStackTrace();
}
}
return result;
}
}
註冊ModelInfoDaoImpl 的執行個體bean modelInfoDao。
<bean id="modelInfoDao" class="dao.ModelInfoDaoImpl"/>
定義介面ModelInfoService和實作類別ModelInfoServiceImpl
public interface ModelInfoService {
String queryModelInfo();
}
public class ModelInfoServiceImpl implements ModelInfoService {
private ModelInfoDao modelInfo;
@Override
public String queryModelInfo() {
String result = modelInfo.queryModelInfo();
return result;
}
public void setDbInfo(ModelInfoDao dbInfo) {
this.modelInfo = dbInfo;
}
public ModelInfoDao getModelInfo() {
return modelInfo;
}
public void setModelInfo(ModelInfoDao modelInfo) {
this.modelInfo = modelInfo;
}
}
註冊ModelInfoServiceImpl的執行個體bean modelInfoServiceImpl,並將bean modelInfoDao作為參數modelInfo注入其中。
<bean id="modelInfoService" class="service.ModelInfoServiceImpl">
<property name="modelInfo" ref="modelInfoDao" />
</bean>
OK,這裡,bean的準備都已經做好,只需等候召喚了。
話說,召喚個皮卡丘都要靠精靈球網路控制,前台請求呢
控制器
正如其命名,DispatcherServlet類來作為前置控制器,通過攔截接受前台匹配的請求請求,將其調度到指定的控制器中。
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
這裡還需要為其添加設定檔,用來指定請求與控制器的關係
注意,這裡設定檔命名規則為”servlet-name” + ”-servlet.xml”,存放在WEB-INF下(可通過配置修改命名與存放路徑),如此處為dispatcher-servlet.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
</beans>
添加控制器ModelInfoControl
public class ModelInfoControl implements Controller {
private ModelInfoService modelInfoService;
@Override
public ModelAndView handleRequest(HttpServletRequest request,HttpServletResponse response) throws ServletException,java.io.IOException{
request.setCharacterEncoding("GBK");
String result = modelInfoService.queryModelInfo();
response.setContentType("text/html;charset=UTF-8");
response.setHeader("Cache-Control", "no-cache");
PrintStream out = new PrintStream(response.getOutputStream());
out.println(result);
out.flush();
out.close();
return null;
}
public void setModelInfoService(
ModelInfoService modelInfoService) {
this.modelInfoService = modelInfoService;
}
}
並將其在dispatcher-servlet.xml中註冊,並將bean modelInfoService作為參數執行個體注入
<bean name="/modelInfo.htm" class="control.ModelInfoControl">
<property name="modelInfoService">
<ref bean="modelInfoService"/>
</property>
</bean>
修改前台頁面請求,這次我們不請求servlet了,我們走Spring這條路
"./dbInfoServlet" —> "modelInfo.htm"
執行項目,看到醒目的首頁兩個字,開心~