由于怕過久了對于配置的一些原理和配置上的細節會忘記,是以記錄下來。
在學習完javase和javaweb的servlet部分知識後,就必須進入到架構的學習,架構可以減少很多繁瑣重複的工作量,提供更強大的功能。
先來學習spring
什麼是IOC
所謂控制反轉,就是把對其他對象的執行個體化和調用,轉給spring容器來做。
看下面代碼:
public class TestIOC {
LoginService loginService = new LoginServiceImpl();
loginService.doLogin("張三","123");
}
上面TestIOC類需要調用LoginService類,直接執行個體化它,這就等于LoginService 的控制在TestIOC手裡。
如果使用spring的IOC控制反轉,那麼代碼如下:
public class TestIOC {
LoginService loginService;
loginService.doLogin("張三","123");
}
這時候執行個體化過程被省略,因為需要的loginService這個執行個體是spring容器通過配置bean檔案在容器中執行個體化了,然後注入到LoginService這個接口成為它的執行個體對象。
是以new LoginServiceImpl()這個執行個體的建立的控制權就從業務邏輯的類中轉移到spring容器中,這就是控制反轉的意思。
IOC的好處就是能夠面向接口程式設計,減少類之間的耦合,這樣每個類都分子產品做自己的事情。同時可以把業務分成很多的子產品,然後使用容器來裝載這些子產品,使得它們共同工作,也友善靈活的添加需要的子產品bean和排除不需要的子產品bean。
什麼是AOP
aop即所謂面向切面程式設計,意思是把你的程式執行過程從上面和下面切開,同時把需要執行的附加内容插入到這個切面中:
public void 普通方法(){
System.out.println("我是好人");
}
如上,如果要在System.out.println(“我是好人”)之前加上判斷,在之後加上确認,如果沒有AOP隻能進入源碼中修改,就像下面這樣:
public void 普通方法(){
doBeforeMethod();
System.out.println("我是好人");
doAfterMethod();
}
但是使用AOP後可以把代碼切出兩個面,一個是在System.out.println(“我是好人”)之前,一個在之後,然後再在切面的位置添加需要的代碼即可,原來的代碼不變:
public void 普通方法(){
System.out.println("我是好人");
}
public void useAOP(){
切面:doBeforeMethod();
調用那個普通方法的代碼...
切面:doAfterMethod();
}
從上面看到,普通方法本身不需要修改,隻需要在AOP中找到切面添加相應方法即可,效果就跟把代碼插進去一樣。
AOP的原理是使用反射,可以用在攔截器(在執行所有内容之前和之後給你執行下某些代碼)。也可以用在資料庫的事務管理中,簡單原理如下:
一個更新操作,需要開啟事務,執行更新,送出和復原三步:
public boolean update() {
conn.setAutoCommit(false);
try{
conn.execute("更新");
conn.commit();
} catch(異常) {
conn.rollback();
}
}
使用AOP的切面程式設計思想,把第一步的conn.setAutoCommit(false)和第三步的conn.commit()+conn.rollback()抽取出來,分别放到執行conn.execute(“更新”)之前和之後的兩個切面中,變成了:
public boolean update() {
conn.execute("更新");
}
public boolean useAOP() {
conn.setAutoCommit(false);
try{
調用那個更新方法的代碼...
conn.commit();
} catch(異常) {
conn.rollback();
}
}
調用那個更新方法的代碼使用的是反射,我們發現update方法隻需要關注業務,事務的開啟和復原已經使用AOP思想配置在容器中了。這樣做的好處就是,如果有非常多個資料庫更新,插入等操作,事務管理的代碼都不用寫了,在容器中配置開啟就可以。
spring的如何初始化bean
一般是在路徑下配置的applicationContext.xml中配置好bean,如下:
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
//看這個bean:
<bean id="demoService" class="com.pack.DemoServiceImpl">
</bean>
</beans>
上面我們在applicationContext.xml的中配置了一個,指定這個bean的id為demoService,具體的類為com.pack.DemoServiceImpl,那麼,ServletContextListener接口的實作類會在spring容器啟動(也就是啟動你的project app)的時候把applicationContext.xml中的所有bean初始化,如同上面IOC部分提到的一樣,不需要自己new一個類執行個體出來,容器會幫我們注入bean執行個體。
到此,有三個疑問沒有解決:
1、 spring容器 去哪裡 調用ServletContextListener接口的實作類
加載applicationContext.xml配置檔案需要注冊一個監聽器,這個監聽器需要實作ServletContextListener接口,其實隻要在我們熟悉的web.xml檔案中配置好:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
ContextLoaderListener就是ServletContextListener接口的實作類,在spring-web.jar包内,spring容器就是根據web.xml中配置的ContextLoaderListener來加載applicationContext.xml配置檔案
2、 ServletContextListener接口的實作類 如何 加載applicationContext.xml
3、 加載之後如何執行個體化和管理bean
ContextLoaderListener會監聽啟動WebApplicationContext,WebApplicationContext會有一系列的動作包括擷取配置檔案applicationContext.xml的内容并且初始化bean等(具體實作不清楚),簡單原理大概如下。
String xmlPath = "WEB-INF\\applicationContext.xml";
//擷取配置檔案的對象等
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
//獲得執行個體
DemoService demoService = (DemoService)applicationContext.getBean("id");