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動態代理
- 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;
- }
- }
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方法內容正好就是代理類中的方法體
- //代碼示例:需要添加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;
- }
- }
//代碼示例:需要添加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形式
- <!-- 在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..*.*(..))
- -->
<!-- 在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切面配置的支持,並確保自動代理
- <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;
- }
- }
<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;
}
}