Spring 的控制反轉:把對象的建立、初始化、銷燬等工做交給Spring 容器來作,有spring容器控制對象的生命週期java
applicationContext.xml程序員
beans --->spring 容器中的類web
alias—>取別名spring
無論有繼承關係(無論有幾層)先把當前類加載到虛擬機中才能建立對象,而在加載過程當中,靜態代碼塊(static )就一塊執行了。因此express
如今子類靜態代碼快賦值,在父類中(@before)接受並使用該值編程
不管兩個類之間有什麼繼承關係,今天代碼塊比方法先執行。tomcat
--------------------------------------------------------------------------------------------------------------------------------------------------------安全
在默認狀況下,Spring建立bean是單例模式,屬性是共享的(線程安全問題)服務器
bean scope屬性--->singleton(單例,共享,默認)通常狀況下,把數據存放在方法中的變量中,儘可能別放在類的屬性中\prototype(多例) 當一個bean是多例模式下,lazy-init爲false或者default無效app
init-method
* 該方法是由spring容器執行
* 在構造函數以後執行
* 若是在構造函數以後,在調用方法以前要作一些工做,能夠在init方法中完成
destroy-method
* 若是該bean是單例,則在spring容器關閉或者銷燬的時候,執行該方法
* 若是該bean是多例,則spring容器不負責銷燬
說明:要想讓spring容器控制bean的生命週期,那麼該bean必須是單例
若是該bean是多例,該bean中還有資源,關閉資源的操做由程序員完成
在啓動spring容器的時候,spring容器配置文件中的類就已經建立完成對象了
lazy-init
default false
true 在context.getBean的時候纔要建立對象
* 優勢
若是該bean中有大數據存在,則何時context.getBean,何時建立對象
能夠防止數據過早的停留在內存中,作到了懶加載
* 缺點
若是spring配置文件中,該bean的配置有錯誤,那麼在tomcat容器啓動的時候,發現不了
false 在啓動spring容器的時候建立對象
* 優勢
若是在啓動tomcat時要啓動spring容器,
那麼若是spring容器會錯誤,這個時候tomcat容器不會正常啓動
* 缺點
若是存在大量的數據,會過早的停留在內存中
DI(依賴注入):給屬性賦值 person類中name;
eg、
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="person" class="cn.itcast.spring0909.di.xml.set.Person">
<!--
property就是表明屬性
在spring中基本類型(包裝類型和String)均可以用value來賦值
引用類型用ref賦值
-->
<property name="pid" value="5"></property>
<property name="pname" value="王二麻子"></property>
<property name="student">
<ref bean="student"/>
</property>
<property name="lists">
<list>
<value>list1</value>
<value>list2</value>
<ref bean="student"/>
</list>
</property>
<property name="sets">
<set>
<value>set1</value>
<value>set2</value>
<ref bean="student"/>
</set>
</property>
<property name="map">
<map>
<entry key="map1">
<value>map1</value>
</entry>
<entry key="map2">
<value>map2</value>
</entry>
<entry key="map3">
<ref bean="student"/>
</entry>
</map>
</property>
<property name="properties">
<props>
<prop key="prop1">
prop1
</prop>
</props>
</property>
</bean>
<bean id="student" class="cn.itcast.spring0909.di.xml.set.Student"></bean>
</beans>
構造函數:
<bean id="person" class="cn.itcast.spring0909.di.xml.constructor.Person">
<!--
構造函數的參數
index 第幾個參數,下標從0開始
type 參數的類型
ref 若是類型是引用類型,賦值
value 若是類型是基本類型,賦值
說明:
只能指定一個構造函數
-->
<constructor-arg index="0" type="java.lang.String" value="幹露露"></constructor-arg>
<constructor-arg index="1" ref="student"></constructor-arg>
</bean>
IOC和DI作了什麼事情:
一、建立對象
二、爲對象的屬性賦值
意義在於:能夠在一個類引用一個接口,而給接口賦值的工做交給spring容器來作,程序員只需在配置文件做相應的配置就行了,這樣客戶端就能夠徹底的面向接口的編程。
----------------------------------------------------------------------------------------------------------------------------------------------
annotation
@Resource註解
原理
* * 啓動spring容器,而且加載配置文件
* * 會爲student和person兩個類建立對象
* * 當解析到<context:annotation-config></context:annotation-config>
* 會啓動依賴注入的註解解析器
* * 會在歸入spring管理的bean的範圍內查找看哪些bean的屬性上有@Resource註解
* * 若是@Resource註解的name屬性的值爲"",則會把註解所在的屬性的名稱和spring容器中bean的id進行匹配
* 若是匹配成功,則把id對應的對象賦值給該屬性,若是匹配不成功,則按照類型進行匹配,若是再匹配不成功,則報錯
* * 若是@Resource註解的name屬性的值不爲"",會把name屬性的值和spring容器中bean的id作匹配,若是匹配
* 成功,則賦值,若是匹配不成功 ,則直接報錯
* 說明:
* 註解只能用於引用類型,若是一個類中有基本數據類型(long int String),而且基本類型使用Spring的形式賦值的,這個時候,該類必須用xml進行賦值(在javaweb中不多直接賦值,大多數都是從服務器獲取值)
@component註解
原理
* * 啓動spring容器,加載配置文件
* * spring容器解析到
* <context:component-scan base-package="cn.itcast.spring0909.scan"></context:component-scan>
* * spring容器會在指定的包及子包中查找類上是否有@Component
* * 若是@Component註解沒有寫任何屬性
* @Component
* public class Person{
*
* }
* ==
* <bean id="person" class="..Person">
* 若是@Component("aa")
* @Component
* public class Person{
*
* }
* ==
* <bean id="aa" class="..Person">
* * 在歸入spring管理的bean的範圍內查找@Resource註解
* * 執行@Resource註解的過程
* 說明:
* xml效率比較高,可是書寫比較麻煩
* 註解效率比較低,書寫比較簡單
-------------------------------------------------------------------------------------------------------------------------------------
<!--
abstract
spring容器不會爲該類建立對象
-->
<bean id="person" class="cn.itcast.spring0909.extend.Person" abstract="true">
<property name="name" value="王二麻子的哥"></property>
</bean>
--------------------------------------------------
<bean id="person" class="cn.itcast.spring0909.extend.Person" abstract="true">
<property name="name" value="王二麻子的哥"></property>
</bean>
<!--
parent
讓子類擁有父類的屬性的值
-->
<bean id="student" class="cn.itcast.spring0909.extend.Student" parent="person">
</bean>
代理模式、動態代理 (invoke)
package cn.itcast.salary.jdkproxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * 一、把日誌、安全性框架、權限導入進去 * 二、把目標類導入進去 * 三、上述兩類經過構造函數賦值 * @author Administrator * */ public class SalaryInterceptor implements InvocationHandler{ private Logger logger; private Security security; private Privilege privilege; private Object target; public SalaryInterceptor(Logger logger,Security security,Privilege privilege,Object target){ this.logger = logger; this.security = security; this.privilege = privilege; this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // TODO Auto-generated method stub System.out.println("aaaaaa"); this.logger.logging(); this.security.security(); if("admin".equals(this.privilege.getAccess())){ //調用目標類的目標方法 method.invoke(this.target, args); }else{ System.out.println("您沒有該權限"); } System.out.println("bbbbbb"); return null; } }
public void test(){ Logger logger = new Logger(); Privilege privilege = new Privilege(); privilege.setAccess("admin"); Security security = new Security(); SalaryManager target = new SalaryManagerImpl(); SalaryInterceptor interceptor = new SalaryInterceptor(logger, security, privilege, target); /** * 一、目標類的類加載器 * 二、目標類的全部的接口 * 三、攔截器 */ SalaryManager proxy = (SalaryManager) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), interceptor); proxy.showSalary();//代理對象的代理方法 }
---------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------
AOP
說明:
* 切面
日誌、安全性的框架、權限的檢查等,總之和業務邏輯沒有關係的均可以看作切面
* 通知
切面中的方法
* 切入點
只有符合切入點,才能把通知和目標方法結合在一塊兒
* 鏈接點
客戶端調用的方法
* 代理對象的方法=通知+目標方法
* aop:作到了代碼塊的重用
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> <!-- 一、引入AOP的命名空間 二、目標類 三、切面 四、攔截器 由spring內部實現 五、aop的配置 --> <bean id="personDao" class="cn.itcast.spring0909.aop.xml.PersonDaoImpl"></bean> <bean id="transaction" class="cn.itcast.spring0909.aop.xml.Transaction"></bean> <!-- aop的配置 --> <aop:config> <!-- 切入點表達式 expression 肯定哪一個類能夠生成代理對象 id 惟一標識 --> <aop:pointcut expression="execution(* cn.itcast.spring0909.aop.xml.PersonDaoImpl.*(..))" id="perform"/> <!-- 切面 --> <aop:aspect ref="transaction"> <!-- 前置通知 --> <aop:before method="beginTransaction" pointcut-ref="perform"/> <aop:after-returning method="commit" pointcut-ref="perform"/> </aop:aspect> </aop:config> </beans>
------------------------------------------------------------------------------------------------------
<aop:config> <!-- 切入點表達式 expression 肯定哪一個類能夠生成代理對象 id 惟一標識 --> <aop:pointcut expression="execution(* cn.itcast.spring0909.aop.xml.PersonDaoImpl.*(..))" id="perform"/> <!-- 切面 --> <aop:aspect ref="transaction"> <!-- 前置通知 * 在目標方法執行以前 * --> <!-- <aop:before method="beginTransaction" pointcut-ref="perform"/> --> <!-- 後置通知 * 在目標方法執行以後 * 能夠根據returning獲取目標方法的返回值 * 若是目標方法遇到異常,該通知不執行 --> <!-- <aop:after-returning method="commit" pointcut-ref="perform" returning="val"/> --> <!-- 前置通知和後置通知只能在目標方法文中添加內容,可是控制不了目標方法的執行 --> <!-- 最終通知 * 在目標方法執行以後 * 不管目標方法是否遇到異常,都執行 * 常常作一些關閉資源 --> <!-- <aop:after method="finallyMethod" pointcut-ref="perform"/> --> <!-- 異常通知 目的就是爲了獲取目標方法拋出的異常 --> <aop:after-throwing method="exceptionMethod" throwing="ex" pointcut-ref="perform"/> <!-- 環繞通知 能控制目標方法的執行 --> <aop:around method="aroundMethod" pointcut-ref="perform"/> </aop:aspect> </aop:config>
AOP總結:
* 原理
* * 加載配置文件,啓動spring容器
* * spring容器爲bean建立對象
* * 解析aop的配置,會解析切入點表達式
* * 看歸入spring管理的那個類和切入點表達式匹配,若是匹配則會爲該類建立代理對象
* * 代理對象的方法體的造成就是目標方法+通知
* * 客戶端在context.getBean時,若是該bean有代理對象,則返回代理對象,若是沒有代理對象則返回原來的對象
* 說明:
* 若是目標類實現了接口,則spring容器會採用jdkproxy,若是目標類沒有實現接口,則spring容器會採用
* cglibproxy
---------------------------------------------------------------------------------------------------------------------------------------------
Struts2
問題:
* action是單例仍是多例?怎麼樣證實?
Action是多例的,在構造函數中輸出一句話,若是請求好幾回,只輸出一次,單例
若是請求不少次,輸出不少次,多例
* struts2有三個類
ActionContext
ServletActionContext 創建struts2與servlet的通訊的橋樑
ActionInvocation struts2總的上下文
* struts2的數據都在值棧中,怎麼樣保證數據的安全性?值棧的生命週期是什麼?
由於ValueStack在ActionContext中,而ActionContext在ThreadLoad中,因此能夠保證數據的安全性
值棧的生命週期是一次請求,當前的action,actioncontext,valuestack的生命週期是一致的
--------------------------------------------------------------------------------------------------------