javascript
08 Spring框架 AOP (一)
首先我們先來介紹一下AOP:?
AOP(Aspect Orient Programming),面向切面編程,是面向?qū)ο缶幊蘋OP的一種補充。
面向?qū)ο缶幊淌菑撵o態(tài)角度考慮程序的結(jié)構(gòu),面向切面編程是從動態(tài)的角度考慮程序運行過程。
AOP底層,就是采用動態(tài)代理模式實現(xiàn)的。采用兩種代理:JDK的動態(tài)代理,與CGLIB的動態(tài)代理。
JDK的動態(tài)代理是面向接口的,CGLIB既可以實現(xiàn)有接口的,又可以實現(xiàn)沒有接口的。(對動態(tài)代理不了解的可以看看我的其關(guān)于動態(tài)代理的介紹)
面向切面編程,就是將交叉業(yè)務(wù)邏輯封裝成切面,利用AOP容器的功能將切面植入到主業(yè)務(wù)邏輯中。所謂交叉業(yè)務(wù)邏輯是指:通用的,與主業(yè)務(wù)邏輯無關(guān)的代碼,如安全檢查,事務(wù)日志等。
Spring的AOP的幾種用法:
通知:即我們的切面方法
異常通知
(一)前置通知?
所謂前置通知,就是這個切面方法在我們的主業(yè)務(wù)方法之前執(zhí)行。
首先我們先寫一個目標(biāo)接口:
//目標(biāo)接口 public interface SomeServices {String doFirst();void doSecond(); } //接口實現(xiàn)類,也就是主業(yè)務(wù)方法類 public class SomeServiceImp implements SomeServices{@Overridepublic String doFirst() {System.out.println("print first");return null;}@Overridepublic void doSecond() {System.out.println("print second");} } //切面方法,需要實現(xiàn):**MethodBeforeAdvice** 接口 public class myBeforeMethodAdvice implements MethodBeforeAdvice {//method:業(yè)務(wù)方法//args:方法參數(shù)//target:目標(biāo)類 @Overridepublic void before(Method method, Object[] arg1, Object target) throws Throwable {System.out.println("執(zhí)行主業(yè)務(wù)前方法");}} <!--Spring主配置文件--><bean id="service" class="com.test.beforeMethodAdvice.SomeServiceImp"/><bean id="myAdvice" class="com.test.beforeMethodAdvice.myBeforeMethodAdvice"/><bean id="ProxyService" class="org.springframework.aop.framework.ProxyFactoryBean"><property name="target" ref="service"/><!--<property name="target" value="service"/>--><property name="interceptorNames" value="myAdvice"/></bean>接著是測試方法:
public class test {@Testpublic void Test01() {String source = "com/test/beforeMethodAdvice/applicationContext.xml";ApplicationContext ac = new ClassPathXmlApplicationContext(source);SomeServices service = (SomeServices)ac.getBean("ProxyService");service.doFirst();service.doSecond();} } //控制臺輸出: //執(zhí)行主業(yè)務(wù)前方法 //print first //執(zhí)行主業(yè)務(wù)前方法 //print second(二)后置通知?
后置通知和前置通知雷同,只是切面方法的實現(xiàn)類不同,但是后置通知實現(xiàn)接口方法,多給用了一個returnValue參數(shù),也就意味著我們可以獲得主業(yè)務(wù)方法的返回值,我們來看看范例:
//主業(yè)務(wù)接口 public interface SomeServices {String doFirst();void doSecond(); } //主業(yè)務(wù)方法實現(xiàn)類,doFirst()有返回值 package com.test.afterMethodAdvice;public class SomeServiceImp implements SomeServices{@Overridepublic String doFirst() {System.out.println("print first");return "abc";}@Overridepublic void doSecond() {System.out.println("print second");} } //實現(xiàn)了**AfterReturningAdvice** 接口,實現(xiàn)這個接口的方法有一個返回值參數(shù) public class myAfterMethodAdvice implements AfterReturningAdvice {//returnValue:業(yè)務(wù)方法的返回值//method:業(yè)務(wù)方法屬性類//args:方法參數(shù)//target:目標(biāo)類 @Overridepublic void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {System.out.println("執(zhí)行業(yè)務(wù)后方法");//只能獲取到業(yè)務(wù)方法的返回值,但是不能進(jìn)行修改 System.out.println(returnValue);} <!--配置文件沒什么差別--><bean id="service" class="com.test.afterMethodAdvice.SomeServiceImp"/><bean id="myAdvice" class="com.test.afterMethodAdvice.myAfterMethodAdvice"/><bean id="ProxyService" class="org.springframework.aop.framework.ProxyFactoryBean"><property name="target" ref="service"/><!--<property name="targetName" value="service"/>--><property name="interceptorNames" value="myAdvice"/></bean>測試方法:
public class test {@Testpublic void Test01() {String source = "com/test/afterMethodAdvice/applicationContext.xml";ApplicationContext ac = new ClassPathXmlApplicationContext(source);SomeServices service = (SomeServices)ac.getBean("ProxyService");service.doFirst();service.doSecond();} } //print first //執(zhí)行業(yè)務(wù)后方法 //abc //print second //執(zhí)行業(yè)務(wù)后方法 //null(三)環(huán)繞通知?
環(huán)繞通知就是既能實現(xiàn)前置通知又能實現(xiàn)后置通知,但是不同的是它能夠?qū)χ鳂I(yè)務(wù)方法進(jìn)行修改。
//主業(yè)務(wù)接口 public interface SomeServices {String doFirst();void doSecond(); } //主業(yè)務(wù)方法實現(xiàn)類 public class SomeServiceImp implements SomeServices{@Overridepublic String doFirst() {System.out.println("print first");return "abc";}@Overridepublic void doSecond() {System.out.println("print second");} } //環(huán)繞通知,切面方法類,需要實現(xiàn)**MethodInterceptor** //并且調(diào)用參數(shù)的proceed方法,這個方法有一個返回值,也就是主業(yè)務(wù)方法的返回值,我們可以對它進(jìn)行修改。 public class MyMethodInterceptor implements MethodInterceptor {@Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {System.out.println("環(huán)繞通知,業(yè)務(wù)方法前");Object result = invocation.proceed();System.out.println("環(huán)繞通知,業(yè)務(wù)方法后");if(result != null) {result = ((String)result).toUpperCase();}return result;} } //環(huán)繞通知的配置文件 <bean id="service" class="com.test.MethodInterceptor.SomeServiceImp"/><bean id="myAdvice" class="com.test.MethodInterceptor.MyMethodInterceptor"/><bean id="ProxyService" class="org.springframework.aop.framework.ProxyFactoryBean"><property name="target" ref="service"/><property name="interceptorNames" value="myAdvice"/></bean> //測試方法: public class test {@Testpublic void Test01() {String source = "com/test/MethodInterceptor/applicationContext.xml";ApplicationContext ac = new ClassPathXmlApplicationContext(source);SomeServices service = (SomeServices)ac.getBean("ProxyService");String result = service.doFirst();System.out.println(result);service.doSecond();} } //控制臺輸出: //環(huán)繞通知,業(yè)務(wù)方法前 //print first //環(huán)繞通知,業(yè)務(wù)方法后 //ABC //環(huán)繞通知,業(yè)務(wù)方法前 //print second //環(huán)繞通知,業(yè)務(wù)方法后(四)異常通知:
異常通知就是當(dāng)我們的主業(yè)務(wù)方法出現(xiàn)異常的時候,會對這個主業(yè)務(wù)方法進(jìn)行加強!
例如:我們現(xiàn)在的主業(yè)務(wù)方法是對用戶名和密碼進(jìn)行判斷,如果用戶名或者密碼有誤,我們就就分別拋出對應(yīng)的錯誤,當(dāng)無誤的時候,程序正常執(zhí)行。
//主業(yè)務(wù)接口,判斷用戶名,密碼是否正確 public interface SomeServices {boolean checkedUser(String username,String password) throws UserException; } //實現(xiàn)類,實現(xiàn)了對用戶和密碼的校驗 public class SomeServiceImp implements SomeServices{@Overridepublic boolean checkedUser(String username, String password)throws UserException {if(!"admin".equals(username.trim())) {throw new UsernameException("用戶名錯誤");}if(!"123".equals(password.trim())){throw new PasswordException("密碼錯誤");}return true;} }上面兩個是我們需要的主業(yè)務(wù)方法,里面我們定義了兩個異常:UsernameException,PasswordException,它們都實現(xiàn)了父類UserException:
//UserException public class UserException extends Exception {public UserException() {super();}public UserException(String message) {super(message);} } //UsernameException public class UsernameException extends UserException {public UsernameException() {super();}public UsernameException(String message) {super(message);} } //PasswordException public class PasswordException extends UserException {public PasswordException() {super();}public PasswordException(String message) {super(message);}}定義好上面的異常后我們就要定義我們的通知類了:
//這個異常通知需要實現(xiàn)ThrowsAdvice接口,接口源碼上面有,我們追蹤到源碼會發(fā)現(xiàn)這個接口沒有需要實現(xiàn)的方法,其實是由幾個供我們選擇,防止我們沒有必要的實現(xiàn)全部方法public class MyThrowsAdvice implements ThrowsAdvice {public void afterThrowing(Exception ex) {System.out.println("執(zhí)行異常通知方法:" + ex.getMessage());} }配置文件沒有什么變化:
<bean id="service" class="com.test.afterExceptionAdvice.SomeServiceImp"/><bean id="myAdvice" class="com.test.afterExceptionAdvice.MyThrowsAdvice"/><bean id="ProxyService" class="org.springframework.aop.framework.ProxyFactoryBean"><property name="target" ref="service"/><property name="interceptorNames" value="myAdvice"/></bean>最后就是我們的測試方法:
public class test {@Testpublic void Test01() {String source = "com/test/afterExceptionAdvice/applicationContext.xml";ApplicationContext ac = new ClassPathXmlApplicationContext(source);SomeServices service = (SomeServices)ac.getBean("ProxyService");//service.checkedUser("admin", "123");//service.checkedUser("ad", "123");try {service.checkedUser("admin", "12");} catch (UserException e) {e.printStackTrace();}} } //控制臺: //**報錯** //執(zhí)行異常通知方法:密碼錯誤本篇文章可能主要是代碼的實現(xiàn),原理上沒有說的太多,因為前面關(guān)于動態(tài)代理的文章我也寫了一篇,所以這里就沒有贅述太多動態(tài)代理的知識。?
?
?
?
?
版權(quán)聲明:本文為博主原創(chuàng)文章,如需轉(zhuǎn)載請表明出處。 https://blog.csdn.net/qq_39266910/article/details/78742552?
?
轉(zhuǎn)載于:https://www.cnblogs.com/chengshun/p/9776849.html
總結(jié)
以上是生活随笔為你收集整理的08 Spring框架 AOP (一)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql explain的使用
- 下一篇: 埃及分数The Rotation Gam