spring總結


一、概述
    1. Spring是一個開源框架,其目的是爲了解決企業應用開發的複雜性.
    2. Spring功能:使用基本的JavaBean代替EJB,並提供更多的企業應用功能.
    3. 簡單說,Spring是一個輕量級的控制反轉(IOC)和麪向切面(AOP)的容器框架.
二、Spring的jar包和配置文件
    1.Spring的jar包
        (1)spring的核心類庫在spring文檔的dist下.
        (2)引入的第三方類庫在spring文檔的lib下.
        (3)常用第三方類庫
            * 如果使用了切面編程(AOP),需要    lib/aspectj/aspectjweaver.jar和aspectjrt.jar
                                    lib/cglib/cglib-nodep-2.1_3.jar
            * 如果使用了@Resource/@PostConstruct/@PreDestroy等註解,需要
                    lib/j2ee/common-annotations.jar
    2.Spring的配置文件
        默認是applicationContext.xml文件.
        但實際工程中,一般建立多個xml文件,在applicationContext.xml中引入.
三、Spring的基本功能
    1.SpringIOC
        * spring的控制反轉:把對象的創建、初始化、銷燬等工作交給spring容器來做,由spring容器控制對象的生命週期.                
        * spring容器的啓動:
            (1)在類路徑下尋找配置文件來實例化容器(常用):
                ApplicationContext ac = new ClassPathXmlApplicationContext(new String[]{"beans.xml"});
                這種方式需要將spring配置文件放到當前項目的classpath路徑下.
            (2)在文件系統路徑下尋找配置文件來實例化容器:
                ApplicationContext ac = new FileSystemXmlApplicationContext(new String[]{"d:\\beans.xml"});
            * 配置文件可以有多個,通過String數組傳入.
    2.別名
        * 使用別名可以達到,在一個地方命名,多個地方使用不同名字的效果.
        <beans>
            <alias name="person" alias="p"/>
            <bean name="person" class="com.liu.domain.Person"/>
        </beans>
    3.Spring容器內部對象的創建
        (1)使用類構造器實例化(默認是無參數的)    
            <bean id="personService" class="com.liu.bean.impl.PersonServiceImpl"/>
        (2)使用靜態工廠方法實例化(簡單工廠模式)
            <bean id="personService" class="com.liu.factory.PersonServiceFactory" factory-method="createPersonService"/>
            工廠類:
                public  class PersonServiceFactory {
                    public static PersonService createPersonService(){
                        return new PersonServiceImpl();
                    }
                }
        (3)注意,初始化bean時機
            * Spring默認在啓動時將所有singleton bean提前進行實例化.即作爲初始化的一部分.
            * ApplicationContext會自動創建並配置所有的singleton bean.
            * Lazy-init="false"時,spring容器將在啓動的時候報錯(可以及時發現錯誤)
            * Lazy-init="true"時,spring容器將在調用該類的時候出錯.
    4.Bean的作用域(scope屬性)
        (1)singleton(默認值)
            * 在每個spring IoC容器中,一個bean定義只有一個對象實例,即是單例的.
            * 默認情況下Bean節點的lazy-init爲false,即容器啓動就初始化bean,如果想延遲,可改爲true
            * 如果相對所有bean都延遲初始化,可以在根節點Beans設置default-lazy-init="true"
                例如:<beans default-lazy-init="true"..>
        (2)prototype
            * 允許bean可以被多次實例化(使用一次就創建一個實例).
            * spring不能對prototype bean的整個生命週期負責,這就意味着清楚prototype作用域的對象
                並釋放任何prototype bean所持有的昂貴資源都是客戶端的責任        
        (3)Request
            在一次Http請求中,一個bean定義對應一個實例;
            即每次Http請求將會有各自的bean實例,它們依據某個bean定義創建而成.
            該作用域僅在基於web的Spring ApplicationContext情形下有效.
        (4)Session
            在一個Http Session中,一個bean定義對應一個實例,該作用域僅在基於web的Spring ApplicationContext情形下有效.
        (5)Global session
            再一個全局的Http Session中,一個bean定義對應一個實例.
            典型情況下,僅在使用portlet context的時候有效.
            該作用域僅在基於web的Spring ApplicationContext情形下有效.
        (6)指定Bean的初始化方法和銷燬方法
             * Spring初始化bean或銷燬bean時,有時需要作一些處理工作,因此spring可以在創建和拆卸bean的時候調用bean的兩個生命週期方.
                  <bean id=“foo” class=“...Foo”
                        init-method=“setup”
                        destory-method=“teardown”/>
            * 當foo被載入到Spring容器中時調用init-method方法.當foo從容器中刪除時調用destory-method(scope = singleton有效)
    5.依賴注入(DI)
        (1)使用構造器注入
            * 通過xml的方式注入:
                A:通過參數的順序:
                    <constructor-arg index="0">
                        <value>張三</value>
                    </constructor-arg>
                    <constructor-arg index="1">
                        <value>56</value>
                    </constructor-arg>
                B:通過參數的類型:
                    <constructor-arg type="java.lang.Integer">
                        <value>56</value>
                    </constructor-arg>
                    <constructor-arg type="java.lang.String">
                        <value>張三</value>
                    </constructor>
        (2)使用屬性setting方法進行注入
            * 通過xml的方式注入:
                A:簡單Bean的注入:
                    簡單Bean包括:包裝類型和String
                        <bean id="personService" class="com.liu.service.impl.PersonServiceImpl">
                            <!-- 基本類型,String類型 -->
                            <property name="age" value="20"/>
                            <property name="name" value="張三"/>
                        </bean>
                B:引用其它Bean
                    <bean id="person" class="com.itcast.bean.Person" />
                    <bean id="personService"  class="com.itcast.bean.impl.PersonServiceImpl">
                        <property name="person" ref="person" />
                    </bean>
        (3)裝配list集合
            <property name="lists">
                <list>
                    <value>list1</value>
                    <value>list2</value>
                </list>
            </property>
        (4)裝配set集合
            <property name="sets">
                <set>
                    <value>set1</value>
                    <value>set2</value>
                </set>
            </property>
        (5)裝配map
            <property name="maps">
                <map>
                    <entry key="01">
                        <value>map01</value>
                    </entry>
                    <entry key="02">
                        <value>map02</value>
                    </entry>
                </map>
            </property>
        (6)裝配Properties
            <property name="props">
                <props>
                    <prop key="01">prop1</prop>
                    <prop key="02">prop2</prop>
                </props>
            </property>
    6.註解注入    
        (1)步驟
            A.在配置文件中,引入context命名空間(星號的)
                <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"
                        xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring- beans-2.5.xsd
                *****   http://www.springframework.org/schema/context
                *****   http://www.springframework.org/schema/context/spring-context-2.5.xsd">
            B.在配置文件中加入context:annotation-config標籤
                <context:annotation-config/>
                此配置隱式註冊了多個對註釋進行解析處理的處理器.
                AutowiredAnnotationBeanPostProcessor,
                CommonAnnotationBeanPostProcessor,
                PersistenceAnnotationBeanPostProcessor,
                RequiredAnnotationBeanPostProcessor
                注:@Resource註解在spring文檔的lib\j2ee\common-annotations.jar    
        (2)@Autowired
            * @Autowired與@Resource區別:
                @Autowired默認按類型裝配
                @Resource默認按名稱裝配,當找不到與名稱匹配的bean時,纔會按類型裝配.
            * @Autowired默認情況下要求依賴對象必須存在,如果允許爲null值,可設置它required屬性爲false
                    @Autowired(required=false)
                    private PersonDao personDao; //用於字段上
                    @Autowired(required=false)
                    public void setPersonDao(PersonDao personDao){ //用於屬性set方法上
                        this.personDao = personDao;
                    }
        (3)@Qualifier
            如果向按名稱裝配,可以結合@Qualifier註解一起使用.
                    @Autowired@Qualifier("personDao")
                    private PersonDao personDao; //用於字段上
                    @Autowired
                    public void setPersonDao(@Qualifier("personDao")PersonDao personDao){
                        this.personDao = personDao;
                    }        
        (4)@Resource
            * 它也可標註在字段或屬性的setter方法上.
            * 如果沒有指定name屬性,會先按照名稱尋找依賴對象,如果找不到,會退回到按類型裝配,而指定了name屬性,則只能按名稱裝配.
        (5)@PostConstruct和@PreDestroy
                @PostConstruct:指定bean的初始化方法.
                @PreDestroy:指定bean的銷燬方法.
    7.掃描注入
        在一個稍大的項目中,通常會有上百個組件,如果這些組件採用xml的bean定義來配置,顯然會增加配置文件的體積,查找及維護起來也不太方便.
        spring2.5爲我們引入了組件自動掃描機制,它可以在類路徑底下尋找標註了@Component、@Service、
        @Controller、@Repository註解的類,並把這些類納入進spring容器中管理.
        (1)    步驟
            * 引入context命名空間,
                和註解注入引入的命名空間是一樣的.
            * 在配置文件中添加context:component-scan標籤
                <context:component-scan base-package="com.liu"/>
                其中base-package爲需要掃描的包(包含子包)
        (2)功能
            @Service 用於標註業務層組件
            @Controller 用於標註控制層組件(如struts中的action)    
            @Repository 用於標註數據訪問組件,即DAO組件
            @Component 泛指組件,當組件不好歸類時,可以用這個註解標註.
    8.spring中的繼承
        Person類:
            public class Person{
                private String sex;
                //..setter,getter方法略
            }        
        student類:
            public class Student extends Person{
                ..
            }
        配置文件:
            <bean id="person" class="com.liu.Person">
                <property name="sex">
                    <value>man</value>
                </property>
            </bean>
            <bean id="student" class="com.liu.Student" parent="person"/>
        配置文件中,parent屬性爲student在容器中繼承person,如果去掉person是不行的.    
四、面向切面編程            
    1.代理模式

        (1)JDK動態代理

  1. import java.lang.reflect.InvocationHandler;  
  2. import java.lang.reflect.Method;  
  3. import java.lang.reflect.Proxy;  
  4.   
  5. public class JDKProxy implements InvocationHandler {  
  6.     private Object targetObject; //代理的目標對象  
  7.   
  8.       
  9.     public Object createProxyInstance(Object targetObject) {  
  10.         this.targetObject = targetObject;  
  11.         //第一個參數設置代碼使用的類加載器,一般採用跟目標類相同的類加載器  
  12.         //第二個參數設置代理類實現的接口跟目標類使用相同的接口  
  13.         //第三個參數設置回調對象,當代理對象的方法被調用時,會調用該參數指定對象的invoke方法  
  14.         return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),  
  15.                 targetObject.getClass().getInterfaces(), this);  
  16.     }  
  17.       
  18.     @Override  
  19.     public Object invoke(Object proxy, Method method, Object[] args)  
  20.             throws Throwable {  
  21.         System.out.println("代理類實例" + proxy.getClass());  
  22.         System.out.println("方法名稱" + method.getName());  
  23.         if(args!=null && args.length>0) { //方法的參數值  
  24.             for(int i=0; i<args.length; i++) {  
  25.                 System.out.println("方法參數值" + args[i].toString());  
  26.             }  
  27.             Object returnvalue = null//定義方法的返回值,沒有返回值時是null  
  28.             returnvalue = method.invoke(this.targetObject, args);//調用目標對象的方法  
  29.             System.out.println("方法的返回值" + returnvalue);  
  30.             return returnvalue;  
  31.         }  
  32.         return null;  
  33.     }  
  34. }  
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class JDKProxy implements InvocationHandler {
	private Object targetObject; //代理的目標對象

	
	public Object createProxyInstance(Object targetObject) {
		this.targetObject = targetObject;
		//第一個參數設置代碼使用的類加載器,一般採用跟目標類相同的類加載器
		//第二個參數設置代理類實現的接口跟目標類使用相同的接口
		//第三個參數設置回調對象,當代理對象的方法被調用時,會調用該參數指定對象的invoke方法
		return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
				targetObject.getClass().getInterfaces(), this);
	}
	
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		System.out.println("代理類實例" + proxy.getClass());
		System.out.println("方法名稱" + method.getName());
		if(args!=null && args.length>0) { //方法的參數值
			for(int i=0; i<args.length; i++) {
				System.out.println("方法參數值" + args[i].toString());
			}
			Object returnvalue = null; //定義方法的返回值,沒有返回值時是null
			returnvalue = method.invoke(this.targetObject, args);//調用目標對象的方法
			System.out.println("方法的返回值" + returnvalue);
			return returnvalue;
		}
		return null;
	}
}

            總結:jdk動態代理必須具備四個條件:目標接口、目標類、攔截器、代理類
                * 因爲利用JDKProxy生成的代理類實現了接口,所以目標類中所有的方法在代理類中都有.
                * 利用JDKProxy方式必須有接口的存在
                * invoke方法中的三個參數可以訪問目標類的被調用方法的API、被調用方法的參數、被調用方法的返回類型.
        (2)CGLIB做代理
            * 用CGlib生成代理類是目標類的子類
            * 用CGlib生成代理類不需要接口
            * 用CGlib生成的代理類重寫了父類的各個方法
            * 攔截器中的intercept方法內容正好就是代理類中的方法體

  1. //代碼示例:需要添加cglib的jar包,可以在spring文檔的lib下找到  
  2. import java.lang.reflect.Method;  
  3. import net.sf.cglib.proxy.Enhancer;  
  4. import net.sf.cglib.proxy.MethodInterceptor;  
  5. import net.sf.cglib.proxy.MethodProxy;  
  6.   
  7. public class CglibProxy implements MethodInterceptor{  
  8.     private Object targetObject; //代理的目標對象  
  9.       
  10.     //創建目標對象的代理對象  
  11.     public Object createProxyInstance(Object targetObject) {  
  12.         this.targetObject = targetObject;  
  13.         Enhancer enhancer = new Enhancer(); //該類用於生成代理對象  
  14.         enhancer.setSuperclass(this.targetObject.getClass()); //設置父類  
  15.         enhancer.setCallback(this); //設置回調對象爲本身  
  16.         return enhancer.create(); //創建代理對象  
  17.     }  
  18.     /* obj 目標對象代理類的實例 
  19.      * method 代理實例上調用父類方法的Method實例 
  20.      * args 傳入到代理實例上方法參數值的對象數組 
  21.      * methodProxy 使用它調用父類的方法 
  22.      */  
  23.     @Override  
  24.     public Object intercept(Object obj, Method method, Object[] args,  
  25.             MethodProxy methodProxy) throws Throwable {  
  26.         System.out.println("代理類" + obj.getClass());  
  27.         System.out.println("方法名稱" + method.getName());  
  28.         if(args!=null && args.length>0) {//方法的參數值  
  29.             for(int i=0; i<args.length; i++) {  
  30.                 System.out.println("方法參數" + args[i]);  
  31.             }  
  32.             Object returnvalue = null;//方法的返回值,無返回類型時,爲null  
  33.             returnvalue = methodProxy.invoke(this.targetObject, args);//調用目標對象的方法  
  34.             System.out.println("方法的返回值" + returnvalue);  
  35.             return returnvalue;  
  36.         }  
  37.         return null;  
  38.     }  
  39. }  
	//代碼示例:需要添加cglib的jar包,可以在spring文檔的lib下找到
	import java.lang.reflect.Method;
	import net.sf.cglib.proxy.Enhancer;
	import net.sf.cglib.proxy.MethodInterceptor;
	import net.sf.cglib.proxy.MethodProxy;
	
	public class CglibProxy implements MethodInterceptor{
		private Object targetObject; //代理的目標對象
		
		//創建目標對象的代理對象
		public Object createProxyInstance(Object targetObject) {
			this.targetObject = targetObject;
			Enhancer enhancer = new Enhancer(); //該類用於生成代理對象
			enhancer.setSuperclass(this.targetObject.getClass()); //設置父類
			enhancer.setCallback(this); //設置回調對象爲本身
			return enhancer.create(); //創建代理對象
		}
		/* obj 目標對象代理類的實例
		 * method 代理實例上調用父類方法的Method實例
		 * args 傳入到代理實例上方法參數值的對象數組
		 * methodProxy 使用它調用父類的方法
		 */
		@Override
		public Object intercept(Object obj, Method method, Object[] args,
				MethodProxy methodProxy) throws Throwable {
			System.out.println("代理類" + obj.getClass());
			System.out.println("方法名稱" + method.getName());
			if(args!=null && args.length>0) {//方法的參數值
				for(int i=0; i<args.length; i++) {
					System.out.println("方法參數" + args[i]);
				}
				Object returnvalue = null;//方法的返回值,無返回類型時,爲null
				returnvalue = methodProxy.invoke(this.targetObject, args);//調用目標對象的方法
				System.out.println("方法的返回值" + returnvalue);
				return returnvalue;
			}
			return null;
		}
	}

        (3)spring的兩種代理方式(默認是jdk動態代理)
            * 若目標對象實現了若干接口,spring使用JDK的java.lang.reflect.Proxy類代理.
                優點:因爲有接口,所以使系統更加鬆耦合
                缺點:爲每一個目標類創建接口
            * 若目標對象沒有實現任何接口,spring使用CGLIB庫生成目標對象的子類
                優點:因爲代理類與目標類是繼承關係,所以不需要有接口的存在.
                缺點:因爲沒有使用接口,所以系統的耦合性相對要差.
    2.AOP編程
        (1)概念
            * Aspect(切面):比如說事務、權限等,與業務邏輯沒有關係的部分.
            * joinpoint(連接點):目標類的目標方法,由客戶端在調用的時候決定
            * Pointcut(切入點):指我們要對那些攔截的方法的定義,被納入spring aop中的目標類的方法
            * Advice(通知):指攔截到joinpoint之後要做的事情就是通知.
                            分爲,前置通知、後置通知、異常通知、最終通知、環繞通知.
            * Target(目標對象):代理的目標對象
            * Weaving(織入)pid=11&gid=1:指把切面應用到目標對象來創建新的代理對象的過程.
                            切面在指定的連接點織入到目標對象.
        (2)對應JDKProxy代理中的概念
                SpringAop        JDKProxy代理
                    目標對象            目標對象
                    切面                攔截器類
                    通知                攔截器類中的方法
                    切入點            被攔截到的目標類中方法的集合
                    連接點            在客戶端調用的方法(目標類目標方法)
                    AOP代理            代理類
                    織入                代理類的代理方法生成的過程
        (3)AOP實現的兩種模式
            * xml形式

  1. <!-- 在spring中配置文件中聲明切面 -->          
  2. <bean id="security" class="com.liu.aop.before.Security" />  
  3.      
  4. <!-- 在spring中配置文件中聲明目標類 -->     
  5. <bean  id="userManager" class="com.liu.aop.before.UserManagerImpl"/>  
  6.   
  7. <!-- 定義切面、切入點、通知-->  
  8. <aop:aspect id="securityid" ref="security">  
  9.     <aop:pointcut id="perform" expression="execution(* com.liu.aop.before.UserManagerImpl.save*(..))"/>  
  10.     <!--定義前置通知-->   
  11.     <aop:before method="checkSecurity" pointcut-ref="perform" />  
  12. </aop:aspect>  
  13.   
  14. <!--定義切入點 ,讓通知攔截到com.liu.aop.before.UserManagerImpl中以save開始的方法  
  15.     * 使用切入點指示符  
  16.         execution : 匹配方法執行的連接點,這是你將會用到的Spring的最主要的切入點指示符。  
  17.     * execution切入點指示符表達式如下:  
  18.         例如:execution("public * com.liu.UserManagerImpl.*(..) throws Exception")  
  19.             execution(  modifiers-pattern?  方法的修飾符模式:不是必須的  
  20.                         ret-type-pattern:   返回類型模式:必須的  
  21.                         declaring-type-pattern?: 路徑模式,不是必須的.  
  22.                                         * 方法所在類的路徑  
  23.                         name-pattern:方法的名稱 必須的  
  24.                                     *表示類中所有的方法  
  25.                                     "save*"表示類中以save開始的方法  
  26.                         (param-pattern):參數模式,必須的  
  27.                                     * ():匹配了一個不接受任何參數的方法  
  28.                                     * (..):匹配了一個接受任意數量參數的方法.  
  29.                                     * 模式(*)匹配了一個接受一個任何類型的參數的方法  
  30.                                     * 模式(*,String)匹配了一個接受兩個參數的方法,  
  31.                                             第一個可以是任意類型,第二個必須是String類型  
  32.                         throws-pattern? : 異常模式,拋出的異常  不是必須的  
  33.     示例:  
  34.         * 任意公共方法的執行:execution(public * * (..))  
  35.         * 任何一個名字以set開始的方法的執行:execution(* set*(..))  
  36.         * AccountService接口定義的任意方法的執行:execution(* com.liu.service.AccountService.*(..))  
  37.         * 在service包中定義的任意方法的執行:execution(* com.liu.service..*(..))  
  38.         * 在service包或其子包中定義的任意方法的執行:execution(* com.liu.service..*.*(..))  
  39.  -->  
<!-- 在spring中配置文件中聲明切面 -->       	
<bean id="security" class="com.liu.aop.before.Security" />
   
<!-- 在spring中配置文件中聲明目標類 -->	
<bean  id="userManager" class="com.liu.aop.before.UserManagerImpl"/>

<!-- 定義切面、切入點、通知-->
<aop:aspect id="securityid" ref="security">
	<aop:pointcut id="perform" expression="execution(* com.liu.aop.before.UserManagerImpl.save*(..))"/>
	<!--定義前置通知-->	
	<aop:before method="checkSecurity" pointcut-ref="perform" />
</aop:aspect>

<!--定義切入點 ,讓通知攔截到com.liu.aop.before.UserManagerImpl中以save開始的方法
	* 使用切入點指示符
		execution : 匹配方法執行的連接點,這是你將會用到的Spring的最主要的切入點指示符。
	* execution切入點指示符表達式如下:
		例如:execution("public * com.liu.UserManagerImpl.*(..) throws Exception")
			execution(	modifiers-pattern? 	方法的修飾符模式:不是必須的
						ret-type-pattern:	返回類型模式:必須的
						declaring-type-pattern?: 路徑模式,不是必須的.
										* 方法所在類的路徑
						name-pattern:方法的名稱 必須的
									*表示類中所有的方法
									"save*"表示類中以save開始的方法
						(param-pattern):參數模式,必須的
									* ():匹配了一個不接受任何參數的方法
									* (..):匹配了一個接受任意數量參數的方法.
									* 模式(*)匹配了一個接受一個任何類型的參數的方法
									* 模式(*,String)匹配了一個接受兩個參數的方法,
											第一個可以是任意類型,第二個必須是String類型
						throws-pattern? : 異常模式,拋出的異常  不是必須的
	示例:
		* 任意公共方法的執行:execution(public * * (..))
		* 任何一個名字以set開始的方法的執行:execution(* set*(..))
		* AccountService接口定義的任意方法的執行:execution(* com.liu.service.AccountService.*(..))
		* 在service包中定義的任意方法的執行:execution(* com.liu.service..*(..))
		* 在service包或其子包中定義的任意方法的執行:execution(* com.liu.service..*.*(..))
 -->

                * 前置通知:
                    <aop:before method="checkSecurity" pointcut-ref="perform" />                
                    * method="checkSecutiry":表示把切面(security)中checkSecurity方法定義爲前置通知
                    * pointcut-ref="perform":把切入點應用到通知.
                    * 前置攔截的類必須實現MethodBeforeAdvice接口,實現其中的before方法
                * 後置通知:
                    <aop:after-returning method="checkSecurity" pointcut-ref="perform" returning="val" />         
                    * return="val" 通知裏可以有返回參數,這個參數只能決定通知裏能不能拿到方法的返回值,和客戶端沒關係.
                    * 在執行目標類的目標方法中遇到異常,則不執行後置通知.
                    * 後置攔截的類必須實現AfterReturningAdvice接口,實現其中的afterReturning方法.
                    * 在攔截器中的方法要和checkSecurity方法一樣,有兩個參數:
                                JoinPoint point : 可以獲得目標方法和參數值
                                Object val :這裏的名字要和return="val"中保持一致,指的是方法的返回值
                * 最終通知:
                    <aop:after method="checkSecurity" pointcut-ref="perform" />
                    * 注意:最終通知不受異常影響,即不論目標方法執行的過程中是否拋出異常,最終通知都將執行.
                * 環繞通知:
                    <aop:around method="checkSecurity" pointcut-ref="perform" />
                    * 前後攔截的類必須實現MethodInterceptor接口,實現其中的invoke方法.
                * 異常通知:
                    <aop:after-throwing method="checkSecurity" pointcut-ref="perform" throwing="ex"/>    
                    * 其中throwing指定了傳遞異常的參數名稱
                    * 在異常通知中(攔截器)中,必須是checkSecurity方法
                        方法中有兩個參數:
                                JoinPoint point:可以獲得方法的名稱、參數
                                Throwable ex : 利用ex.getMessage()可以獲得異常信息
            * 註解形式
                爲了在spring配置中使用@AspectJ切面,首先必須啓用Spring對@AspectJ切面配置的支持,並確保自動代理

  1. <beans ...>  
  2.     <!-- 啓用spring對@AspectJ的支持 -->  
  3.     <aop:aspectj-autoproxy/>  
  4.     <!-- 聲明切面對象 -->  
  5.     <bean id="security" class="com.liu.service.Security"/>  
  6.     <!-- 創建接口實現類對象 -->  
  7.     <bean id="userManager" class="com.liu.service.UserManagerImpl"/>  
  8. </beans>  
  9. // 前置通知  
  10.     /* @Aspectj是按照類型匹配  
  11.      * @Pointcut用於聲明切入點  
  12.      *  在@AspectJ註解風格的aop中,一個切入點簽名通過一個普通的方法來定義  
  13.      *      1.作爲切入點簽名的方法必須返回void類型  
  14.      *      2.方法沒有參數用private修飾  
  15.      *      3.方法體爲空  
  16.      *  切入點表達式的寫法  
  17.      *  execution(..)表示匹配方法執行的連接點  
  18.      *      1."*"表示方法的返回類型任意  
  19.      *      2.com.liu.service..* 表示service包及其子包中所有的類  
  20.      *      3.save* 表示類中所有以save開頭的方法  
  21.      *      4.(..)表示參數是任意數量  
  22.      *  @Before 前置通知,在方法調用前執行  
  23.      *  userManagerPointcut() 表示前面定義的切入點  
  24.      *  args 限定匹配特定的連接點(使用spring AOP 的時候方法的執行),其中參數是指定類型的實例  
  25.      *  username1,psw 參數表示指定類型的實例  
  26.      *      參數名稱必須與通知的參數名稱一致  
  27.      *      通知參數的類型必須與目標對象參數的類型一致,如不一致,則攔截不到      
  28.      */  
  29.     @Aspect  
  30.     public class Security {  
  31.         @Pointcut("execution(* com.liu.service..*.save*(..))")  
  32.         private void userManagerPointcut(){}  
  33.           
  34.         @Before("userManagerPointcut() && args(username1,psw)")  
  35.         public void checkSecurity(String username1, String psw){  
  36.             System.out.println("安全檢查"+username1+" "+psw);  
  37.         }  
  38.     }  
  39. // 後置通知  
  40.     @Aspect  
  41.     public class Security {  
  42.         @Pointcut("execution(* com.liu.service..*.save*(..))")  
  43.         private void userManagerPointcut(){}  
  44.           
  45.         @AfterReturning(pointcut="userManagerPointcut()",returning="value")  
  46.         public void checkSecurity(String value) {  
  47.             System.out.println("安全檢查"+value);  
  48.         }  
  49.     }  
  50. // 異常通知  
  51.     @Aspect  
  52.     public class Security {  
  53.         @Pointcut("execution(* com.liu.service..*.save*(..))")  
  54.         private void userManagerPointcut(){}  
  55.           
  56.         @AfterThrowing(pointcut="userManagerPointcut()",throwing="ex")  
  57.         public void checkSecurity(Exception ex) {  
  58.             System.out.println("安全檢查" + ex);  
  59.         }  
  60.     }  
  61. // 最終通知  
  62.     @Aspect  
  63.     public class Security {  
  64.         @Pointcut("execution(* com.liu.service..*.save*(..))")  
  65.         private void userManagerPointcut(){}  
  66.           
  67.         @After("userManagerPointcut()")  
  68.         public void checkSecurity(Exception ex) {  
  69.             System.out.println("安全檢查");  
  70.         }  
  71.     }  
  72. // 環繞通知  
  73.     @Aspect  
  74.     public class Security {  
  75.         @Pointcut("execution(* com.liu.service..*.save*(..))")  
  76.         private void userManagerPointcut(){}  
  77.           
  78.         @Around("userManagerPointcut()")  
  79.         public Object checkSecurity(ProceedingJoinPoint point)throw Throwable {  
  80.             System.out.println("方法的名稱" + point.getSignature().getName());  
  81.             System.out.println("測試參數對象是否爲空" + point.getArgs().toString());  
  82.             if(point.getArgs().length > 0) {  
  83.                 for(int i=0; i<point.getArgs().length; i++) {  
  84.                 System.out.println("方法的參數值" + point.getArgs()[i]);  
  85.                 }  
  86.             }  
  87.             Object returnvalue = null; //調用方法的返回值,方法無返回值時是null  
  88.             returnvalue=point.proceed(); //調用目標對象方法  
  89.             System.out.println("returnvalue" + returnvalue);  
  90.             System.out.prntln("進行安全檢查");  
  91.             return returnvalue;  
  92.         }  
  93.     }  
	<beans ...>
		<!-- 啓用spring對@AspectJ的支持 -->
		<aop:aspectj-autoproxy/>
		<!-- 聲明切面對象 -->
		<bean id="security" class="com.liu.service.Security"/>
		<!-- 創建接口實現類對象 -->
		<bean id="userManager" class="com.liu.service.UserManagerImpl"/>
	</beans>
	// 前置通知
		/* @Aspectj是按照類型匹配
		 * @Pointcut用於聲明切入點
		 *	在@AspectJ註解風格的aop中,一個切入點簽名通過一個普通的方法來定義
		 * 		1.作爲切入點簽名的方法必須返回void類型
		 *		2.方法沒有參數用private修飾
		 *		3.方法體爲空
		 *	切入點表達式的寫法
		 *	execution(..)表示匹配方法執行的連接點
		 *		1."*"表示方法的返回類型任意
		 * 		2.com.liu.service..* 表示service包及其子包中所有的類
		 * 		3.save* 表示類中所有以save開頭的方法
		 * 		4.(..)表示參數是任意數量
		 *	@Before 前置通知,在方法調用前執行
		 *	userManagerPointcut() 表示前面定義的切入點
		 *	args 限定匹配特定的連接點(使用spring AOP 的時候方法的執行),其中參數是指定類型的實例
		 *  username1,psw 參數表示指定類型的實例
		 *		參數名稱必須與通知的參數名稱一致
		 *		通知參數的類型必須與目標對象參數的類型一致,如不一致,則攔截不到	
		 */
		@Aspect
		public class Security {
			@Pointcut("execution(* com.liu.service..*.save*(..))")
			private void userManagerPointcut(){}
			
			@Before("userManagerPointcut() && args(username1,psw)")
			public void checkSecurity(String username1, String psw){
				System.out.println("安全檢查"+username1+" "+psw);
			}
		}
	// 後置通知
		@Aspect
		public class Security {
			@Pointcut("execution(* com.liu.service..*.save*(..))")
			private void userManagerPointcut(){}
			
			@AfterReturning(pointcut="userManagerPointcut()",returning="value")
			public void checkSecurity(String value) {
				System.out.println("安全檢查"+value);
			}
		}
	// 異常通知
		@Aspect
		public class Security {
			@Pointcut("execution(* com.liu.service..*.save*(..))")
			private void userManagerPointcut(){}
			
			@AfterThrowing(pointcut="userManagerPointcut()",throwing="ex")
			public void checkSecurity(Exception ex) {
				System.out.println("安全檢查" + ex);
			}
		}
	// 最終通知
		@Aspect
		public class Security {
			@Pointcut("execution(* com.liu.service..*.save*(..))")
			private void userManagerPointcut(){}
			
			@After("userManagerPointcut()")
			public void checkSecurity(Exception ex) {
				System.out.println("安全檢查");
			}
		}
	// 環繞通知
		@Aspect
		public class Security {
			@Pointcut("execution(* com.liu.service..*.save*(..))")
			private void userManagerPointcut(){}
			
			@Around("userManagerPointcut()")
			public Object checkSecurity(ProceedingJoinPoint point)throw Throwable {
				System.out.println("方法的名稱" + point.getSignature().getName());
				System.out.println("測試參數對象是否爲空" + point.getArgs().toString());
				if(point.getArgs().length > 0) {
					for(int i=0; i<point.getArgs().length; i++) {
					System.out.println("方法的參數值" + point.getArgs()[i]);
					}
				}
				Object returnvalue = null; //調用方法的返回值,方法無返回值時是null
				returnvalue=point.proceed(); //調用目標對象方法
				System.out.println("returnvalue" + returnvalue);
				System.out.prntln("進行安全檢查");
				return returnvalue;
			}
		}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章